Ver código fonte

初始化项目

赵启卫 2 anos atrás
pai
commit
24b2f0fb5f
100 arquivos alterados com 24201 adições e 0 exclusões
  1. 13 0
      .gitignore
  2. BIN
      application/.DS_Store
  3. 216 0
      application/admin/common.php
  4. 38 0
      application/admin/config.php
  5. 101 0
      application/admin/controller/AuthController.php
  6. 33 0
      application/admin/controller/Common.php
  7. 1232 0
      application/admin/controller/Index.php
  8. 98 0
      application/admin/controller/Login.php
  9. 205 0
      application/admin/controller/article/Article.php
  10. 147 0
      application/admin/controller/article/ArticleCategory.php
  11. 313 0
      application/admin/controller/article/ArticleV1.php
  12. 156 0
      application/admin/controller/article/Consult.php
  13. 52 0
      application/admin/controller/article/Search.php
  14. 201 0
      application/admin/controller/article/WechatNews.php
  15. 472 0
      application/admin/controller/download/DataDownload.php
  16. 162 0
      application/admin/controller/download/DataDownloadCategpry.php
  17. 161 0
      application/admin/controller/educational/Classes.php
  18. 400 0
      application/admin/controller/educational/Student.php
  19. 172 0
      application/admin/controller/educational/Teacher.php
  20. 147 0
      application/admin/controller/educational/TeacherCategpry.php
  21. 243 0
      application/admin/controller/finance/Finance.php
  22. 264 0
      application/admin/controller/finance/UserExtract.php
  23. 173 0
      application/admin/controller/finance/UserRecharge.php
  24. 1306 0
      application/admin/controller/live/AliyunLive.php
  25. 197 0
      application/admin/controller/merchant/Merchant.php
  26. 183 0
      application/admin/controller/merchant/MerchantMenus.php
  27. 247 0
      application/admin/controller/merchant/UserEnter.php
  28. 0 0
      application/admin/controller/order/DataDownloadOrder.php
  29. 0 0
      application/admin/controller/order/StoreOrder.php
  30. 0 0
      application/admin/controller/order/TestPaperOrder.php
  31. 291 0
      application/admin/controller/questions/Certificate.php
  32. 284 0
      application/admin/controller/questions/Questions.php
  33. 141 0
      application/admin/controller/questions/QuestionsCategpry.php
  34. 762 0
      application/admin/controller/questions/TestPaper.php
  35. 146 0
      application/admin/controller/questions/TestPaperCategory.php
  36. 227 0
      application/admin/controller/setting/SystemAdmin.php
  37. 345 0
      application/admin/controller/setting/SystemBroadcast.php
  38. 177 0
      application/admin/controller/setting/SystemBucket.php
  39. 491 0
      application/admin/controller/setting/SystemConfig.php
  40. 68 0
      application/admin/controller/setting/SystemConfigContent.php
  41. 150 0
      application/admin/controller/setting/SystemConfigTab.php
  42. 154 0
      application/admin/controller/setting/SystemGroup.php
  43. 1158 0
      application/admin/controller/setting/SystemGroupData.php
  44. 183 0
      application/admin/controller/setting/SystemMenus.php
  45. 264 0
      application/admin/controller/setting/SystemMessage.php
  46. 146 0
      application/admin/controller/setting/SystemNotice.php
  47. 745 0
      application/admin/controller/setting/SystemPlat.php
  48. 143 0
      application/admin/controller/setting/SystemRole.php
  49. 149 0
      application/admin/controller/special/Course.php
  50. 176 0
      application/admin/controller/special/Grade.php
  51. 461 0
      application/admin/controller/special/Lecturer.php
  52. 176 0
      application/admin/controller/special/SpecialReply.php
  53. 145 0
      application/admin/controller/special/SpecialTaskCategory.php
  54. 1995 0
      application/admin/controller/special/SpecialType.php
  55. 165 0
      application/admin/controller/special/Subject.php
  56. 194 0
      application/admin/controller/special/Task.php
  57. 182 0
      application/admin/controller/store/StoreCategory.php
  58. 563 0
      application/admin/controller/store/StoreProduct.php
  59. 174 0
      application/admin/controller/store/StoreProductReply.php
  60. 91 0
      application/admin/controller/system/Clear.php
  61. 138 0
      application/admin/controller/system/Express.php
  62. 84 0
      application/admin/controller/system/SystemAttachment.php
  63. 139 0
      application/admin/controller/system/SystemClear.php
  64. 186 0
      application/admin/controller/system/SystemCleardata.php
  65. 230 0
      application/admin/controller/system/SystemDatabackup.php
  66. 248 0
      application/admin/controller/system/SystemFile.php
  67. 44 0
      application/admin/controller/system/SystemLog.php
  68. 29 0
      application/admin/controller/system/SystemUpgradeclient.php
  69. 461 0
      application/admin/controller/ump/EventRegistration.php
  70. 175 0
      application/admin/controller/ump/SpecialBatch.php
  71. 153 0
      application/admin/controller/ump/StoreCombination.php
  72. 156 0
      application/admin/controller/user/MemberCard.php
  73. 45 0
      application/admin/controller/user/MemberRecord.php
  74. 137 0
      application/admin/controller/user/MemberShip.php
  75. 132 0
      application/admin/controller/user/SignPoster.php
  76. 1047 0
      application/admin/controller/user/User.php
  77. 320 0
      application/admin/controller/user/UserNotice.php
  78. 41 0
      application/admin/controller/user/UserSign.php
  79. 267 0
      application/admin/controller/user/UserSpread.php
  80. 48 0
      application/admin/controller/wechat/Menus.php
  81. 200 0
      application/admin/controller/wechat/Reply.php
  82. 144 0
      application/admin/controller/wechat/RoutineTemplate.php
  83. 186 0
      application/admin/controller/wechat/StoreService.php
  84. 43 0
      application/admin/controller/wechat/WechatMessage.php
  85. 294 0
      application/admin/controller/wechat/WechatNewsCategory.php
  86. 143 0
      application/admin/controller/wechat/WechatTemplate.php
  87. 394 0
      application/admin/controller/wechat/WechatUser.php
  88. 336 0
      application/admin/controller/widget/Images.php
  89. 62 0
      application/admin/controller/widget/Widgets.php
  90. BIN
      application/admin/model/.DS_Store
  91. 221 0
      application/admin/model/article/Article.php
  92. 94 0
      application/admin/model/article/ArticleCategory.php
  93. 28 0
      application/admin/model/article/ArticleContent.php
  94. 41 0
      application/admin/model/article/Search.php
  95. 208 0
      application/admin/model/download/DataDownload.php
  96. 147 0
      application/admin/model/download/DataDownloadBuy.php
  97. 92 0
      application/admin/model/download/DataDownloadCategpry.php
  98. 91 0
      application/admin/model/download/DataDownloadRecords.php
  99. 70 0
      application/admin/model/educational/Classes.php
  100. 49 0
      application/admin/model/educational/ContactPhone.php

+ 13 - 0
.gitignore

xqd
@@ -0,0 +1,13 @@
+# Windows thumbnail cache files
+/.idea
+/runtime
+/public/uploads
+/public/nginx.htaccess
+*.txt
+think
+.htaccess
+*.log:
+/application/database.php
+/vendor/workerman/workerman.log
+/public/aa.mp4
+/public/audio.mp3

BIN
application/.DS_Store


+ 216 - 0
application/admin/common.php

xqd
@@ -0,0 +1,216 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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;
+    try {
+        $redisModel = new \think\cache\driver\Redis();
+        $exists_recommend_redis = $redisModel->HEXISTS($name, $key);
+        if ($exists_recommend_redis) $redisModel->hdel($name, $key);
+        return true;
+    } catch (\Exception $e) {
+        $basic = new \basic\WapBasic;
+        return $basic->serRedisPwd($e->getMessage());
+    }
+}
+
+/**
+ * 获取产品名称
+ * @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);
+    }
+}
+/**检查是否有看手机号权限
+ * @return bool
+ */
+function is_phone_menu()
+{
+    return \app\admin\model\system\SystemMenus::isMenu('查看手机号', 'is_phone');
+}

+ 38 - 0
application/admin/config.php

xqd
@@ -0,0 +1,38 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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,
+        //有效期
+        'expire' => 86400,
+    ],
+    'app_debug'              => false,
+    // 应用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/'
+    ],
+];

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

xqd
@@ -0,0 +1,101 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 app\admin\model\special\Special;
+use basic\AuthBasic;
+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();
+        Special::updateSpecialSource();//下个版本删除
+        $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->authFail('没有权限访问!'));
+        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->toArray());
+        return $adminInfo;
+    }
+}

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

xqd
@@ -0,0 +1,33 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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);
+    }
+
+
+}

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

xqd
@@ -0,0 +1,1232 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 app\admin\model\special\LearningRecords;
+use app\admin\model\order\DataDownloadOrder;
+use app\admin\model\order\TestPaperOrder;
+use app\admin\model\user\UserRecharge;
+use app\admin\model\ump\EventSignUp;
+use FormBuilder\Json;
+use service\JsonService;
+use service\SystemConfigService;
+use think\Config;
+use think\Cache;
+use think\DB;
+
+/**
+ * 首页控制器
+ * Class Index
+ * @package app\admin\controller
+ *
+ */
+class Index extends AuthController
+{
+    public function index()
+    {
+        //获取当前登录后台的管理员信息
+        $adminInfo = $this->adminInfo;
+        $roles = explode(',', $adminInfo['roles']);
+        $this->assign([
+            'menuList' => SystemMenus::menuList(),
+            'site_logo' => SystemConfigService::get('site_logo'),
+            'Auth_site_name' => SystemConfigService::get('site_name'),
+            '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 = UserModel::where('add_time', 'gt', $now_day)->count();
+        $pre_day_user = UserModel::where('add_time', 'gt', $pre_day)->where('add_time', 'lt', $now_day)->count();
+        $pre_day_user = $pre_day_user ? $pre_day_user : 0;
+        $_user = abs($now_day_user - $pre_day_user);
+        $first_line['day'] = [
+            'data' => $now_day_user ? $now_day_user : 0,
+            'percent' => bcmul($pre_day_user > 0 ? bcdiv($_user, $pre_day_user, 3) : abs($now_day_user), 100, 2),
+            'is_plus' => $now_day_user - $pre_day_user > 0 ? 1 : ($now_day_user - $pre_day_user == 0 ? -1 : 0)
+        ];
+        //学习次数->日
+        $now_day_user = LearningRecords::where('add_time', 'egt', $now_day)->count();
+        $pre_day_user = LearningRecords::where('add_time', 'egt', $pre_day)->where('add_time', 'lt', $now_day)->count();
+        $pre_day_user = $pre_day_user ? $pre_day_user : 0;
+        $_user = abs($now_day_user - $pre_day_user);
+        $first_line['records'] = [
+            'data' => $now_day_user ? $now_day_user : 0,
+            'percent' => bcmul($pre_day_user > 0 ? bcdiv($_user, $pre_day_user, 3) : abs($now_day_user), 100, 2),
+            '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();
+        $_order_p = abs($now_day_order_p - $pre_day_order_p);
+        $first_line['d_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => bcmul($pre_day_order_p > 0 ? bcdiv($_order_p, $pre_day_order_p, 2) : abs($now_day_order_p), 100, 2),
+            '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)');
+        $m_order_p = abs($now_month_order_p - $pre_month_order_p);
+        $first_line['d_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => bcmul($pre_month_order_p > 0 ? bcdiv($m_order_p, $pre_month_order_p, 2) : abs($now_month_order_p), 100, 2),
+            '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();
+        $_order_p = abs($now_day_order_p - $pre_day_order_p);
+        $first_line['d_store_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => bcmul($pre_day_order_p > 0 ? bcdiv($_order_p, $pre_day_order_p, 2) : abs($now_day_order_p), 100, 2),
+            '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)');
+        $m_order_p = abs($now_month_order_p - $pre_month_order_p);
+        $first_line['d_store_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => bcmul($pre_month_order_p > 0 ? bcdiv($m_order_p, $pre_month_order_p, 2) : abs($now_month_order_p), 100, 2),
+            '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 = UserModel::where('level', 1)->where('member_time', 'gt', $now_day)->count();
+        $pre_day_order_p = UserModel::where('level', 1)->where('member_time', 'gt', $pre_day)->where('member_time', 'lt', $now_day)->count();
+        $_order_p = abs($now_day_order_p - $pre_day_order_p);
+        $first_line['d_vip_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => bcmul($pre_day_order_p > 0 ? bcdiv($_order_p, $pre_day_order_p, 2) : abs($now_day_order_p), 100, 2),
+            '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)');
+        $m_order_p = abs($now_month_order_p - $pre_month_order_p);
+        $first_line['d_vip_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => bcmul($pre_month_order_p > 0 ? bcdiv($m_order_p, $pre_month_order_p, 2) : abs($now_month_order_p), 100, 2),
+            '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 = DataDownloadOrder::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $now_day)->count();
+        $pre_day_order_p = DataDownloadOrder::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->count();
+        $_order_p = abs($now_day_order_p - $pre_day_order_p);
+        $first_line['d_data_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => bcmul($pre_day_order_p > 0 ? bcdiv($_order_p, $pre_day_order_p, 2) : abs($now_day_order_p), 100, 2),
+            '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 = DataDownloadOrder::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $now_day)->value('sum(pay_price)');
+        $pre_month_order_p = DataDownloadOrder::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->value('sum(pay_price)');
+        $m_order_p = abs($now_month_order_p - $pre_month_order_p);
+        $first_line['d_data_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => bcmul($pre_month_order_p > 0 ? bcdiv($m_order_p, $pre_month_order_p, 2) : abs($now_month_order_p), 100, 2),
+            '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 = EventSignUp::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $now_day)->count();
+        $pre_day_order_p = EventSignUp::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->count();
+        $_order_p = abs($now_day_order_p - $pre_day_order_p);
+        $first_line['d_event_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => bcmul($pre_day_order_p > 0 ? bcdiv($_order_p, $pre_day_order_p, 2) : abs($now_day_order_p), 100, 2),
+            '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 = EventSignUp::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $now_day)->value('sum(pay_price)');
+        $pre_month_order_p = EventSignUp::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->value('sum(pay_price)');
+        $m_order_p = abs($now_month_order_p - $pre_month_order_p);
+        $first_line['d_event_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => bcmul($pre_month_order_p > 0 ? bcdiv($m_order_p, $pre_month_order_p, 2) : abs($now_month_order_p), 100, 2),
+            '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 = TestPaperOrder::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $now_day)->count();
+        $pre_day_order_p = TestPaperOrder::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->count();
+        $_order_p = abs($now_day_order_p - $pre_day_order_p);
+        $first_line['d_test_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => bcmul($pre_day_order_p > 0 ? bcdiv($_order_p, $pre_day_order_p, 2) : abs($now_day_order_p), 100, 2),
+            '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 = TestPaperOrder::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $now_day)->value('sum(pay_price)');
+        $pre_month_order_p = TestPaperOrder::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->value('sum(pay_price)');
+        $m_order_p = abs($now_month_order_p - $pre_month_order_p);
+        $first_line['d_test_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => bcmul($pre_month_order_p > 0 ? bcdiv($m_order_p, $pre_month_order_p, 2) : abs($now_month_order_p), 100, 2),
+            '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 = UserRecharge::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $now_day)->count();
+        $pre_day_order_p = UserRecharge::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->count();
+        $_order_p = abs($now_day_order_p - $pre_day_order_p);
+        $first_line['d_recharge_num'] = [
+            'data' => $now_day_order_p ? $now_day_order_p : 0,
+            'percent' => bcmul($pre_day_order_p > 0 ? bcdiv($_order_p, $pre_day_order_p, 2) : abs($now_day_order_p), 100, 2),
+            '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 = UserRecharge::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $now_day)->value('sum(price)');
+        $pre_month_order_p = UserRecharge::where(['paid' => 1, 'is_del' => 0])->where('pay_time', 'gt', $pre_day)->where('pay_time', 'lt', $now_day)->value('sum(price)');
+        $m_order_p = abs($now_month_order_p - $pre_month_order_p);
+        $first_line['d_recharge_price'] = [
+            'data' => $now_month_order_p > 0 ? $now_month_order_p : 0,
+            'percent' => bcmul($pre_month_order_p > 0 ? bcdiv($m_order_p, $pre_month_order_p, 2) : abs($now_month_order_p), 100, 2),
+            '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 = 'thirtyday', $type = 0)
+    {
+        $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'));
+                }
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $order_list = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->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();
+                        break;
+                    case '3':
+                        $order_list = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $order_list = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $order_list = EventSignUp::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();
+                        break;
+                    case '6':
+                        $order_list = UserRecharge::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(price) as price")
+                            ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")->order('add_time asc')->select()->toArray();
+                        break;
+                }
+                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值
+                //统计总数上期
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $pre_total = StoreOrderModel::where('add_time', 'between time', [$pre_datebefor, $pre_dateafter])
+                            ->field("count(*) as count,sum(pay_price) as price")->where('type', $type)->where('is_del', 0)->where('paid', 1)
+                            ->find();
+                        break;
+                    case '3':
+                        $pre_total = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $pre_total = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $pre_total = EventSignUp::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();
+                        break;
+                    case '6':
+                        $pre_total = UserRecharge::where('add_time', 'between time', [$pre_datebefor, $pre_dateafter])
+                            ->field("count(*) as count,sum(price) as price")->where('is_del', 0)->where('paid', 1)
+                            ->find();
+                        break;
+                }
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $total = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->field("count(*) as count,sum(pay_price) as price")->where('type', $type)->where('is_del', 0)->where('paid', 1)
+                            ->find();
+                        break;
+                    case '3':
+                        $total = DataDownloadOrder::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->field("count(*) as count,sum(pay_price) as price")->where('is_del', 0)->where('paid', 1)
+                            ->find();
+                        break;
+                    case '4':
+                        $total = TestPaperOrder::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->field("count(*) as count,sum(pay_price) as price")->where('is_del', 0)->where('paid', 1)
+                            ->find();
+                        break;
+                    case '5':
+                        $total = EventSignUp::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->field("count(*) as count,sum(pay_price) as price")->where('is_del', 0)->where('paid', 1)
+                            ->find();
+                        break;
+                    case '6':
+                        $total = UserRecharge::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->field("count(*) as count,sum(price) as price")->where('is_del', 0)->where('paid', 1)
+                            ->find();
+                        break;
+                }
+                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()));
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $order_list = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->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();
+                        break;
+                    case '3':
+                        $order_list = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $order_list = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $order_list = EventSignUp::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();
+                        break;
+                    case '6':
+                        $order_list = UserRecharge::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(price) as price")
+                            ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")->order('add_time asc')->select()->toArray();
+                        break;
+                }
+                //数据查询重新处理
+                $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"));
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $now_order_list = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->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();
+                        break;
+                    case '3':
+                        $now_order_list = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $now_order_list = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $now_order_list = EventSignUp::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();
+                        break;
+                    case '6':
+                        $now_order_list = UserRecharge::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(price) as price")
+                            ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")->order('add_time asc')->select()->toArray();
+                        break;
+                }
+                //数据查询重新处理 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值
+
+                //统计总数上期
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $pre_total = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '3':
+                        $pre_total = DataDownloadOrder::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '4':
+                        $pre_total = TestPaperOrder::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '5':
+                        $pre_total = EventSignUp::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '6':
+                        $pre_total = UserRecharge::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(price) as price")
+                            ->find();
+                        break;
+                }
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $total = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '3':
+                        $total = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $total = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $total = EventSignUp::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();
+                        break;
+                    case '6':
+                        $total = UserRecharge::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(price) as price")
+                            ->find();
+                        break;
+                }
+                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')));
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $order_list = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->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();
+                        break;
+                    case '3':
+                        $order_list = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $order_list = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $order_list = EventSignUp::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();
+                        break;
+                    case '6':
+                        $order_list = UserRecharge::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(price) as price")
+                            ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")->order('add_time asc')->select()->toArray();
+                        break;
+                }
+                //数据查询重新处理
+                $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"));
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $now_order_list = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->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();
+                        break;
+                    case '3':
+                        $now_order_list = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $now_order_list = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $now_order_list = EventSignUp::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();
+                        break;
+                    case '6':
+                        $now_order_list = UserRecharge::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(price) as price")
+                            ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")->order('add_time asc')->select()->toArray();
+                        break;
+                }
+                //数据查询重新处理 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值
+
+                //统计总数上期
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $pre_total = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '3':
+                        $pre_total = DataDownloadOrder::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '4':
+                        $pre_total = TestPaperOrder::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '5':
+                        $pre_total = EventSignUp::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '6':
+                        $pre_total = UserRecharge::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(price) as price")
+                            ->find();
+                        break;
+                }
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $total = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '3':
+                        $total = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $total = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $total = EventSignUp::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();
+                        break;
+                    case '6':
+                        $total = UserRecharge::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(price) as price")
+                            ->find();
+                        break;
+                }
+                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'));
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $order_list = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->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();
+                        break;
+                    case '3':
+                        $order_list = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $order_list = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $order_list = EventSignUp::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();
+                        break;
+                    case '6':
+                        $order_list = UserRecharge::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(price) as price")
+                            ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")->order('add_time asc')->select()->toArray();
+                        break;
+                }
+                //数据查询重新处理
+                $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');
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $now_order_list = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->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();
+                        break;
+                    case '3':
+                        $now_order_list = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $now_order_list = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $now_order_list = EventSignUp::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();
+                        break;
+                    case '6':
+                        $now_order_list = UserRecharge::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(price) as price")
+                            ->group("FROM_UNIXTIME(add_time, '%Y%m%e')")->order('add_time asc')->select()->toArray();
+                        break;
+                }
+                //数据查询重新处理 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值
+
+                //统计总数上期
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $pre_total = StoreOrderModel::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '3':
+                        $pre_total = DataDownloadOrder::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '4':
+                        $pre_total = TestPaperOrder::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '5':
+                        $pre_total = EventSignUp::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '6':
+                        $pre_total = UserRecharge::where('add_time', 'between time', [$datebefor, $dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(price) as price")
+                            ->find();
+                        break;
+                }
+                if ($pre_total) {
+                    $chartdata['pre_cycle']['count'] = [
+                        'data' => $pre_total['count'] ?: 0
+                    ];
+                    $chartdata['pre_cycle']['price'] = [
+                        'data' => $pre_total['price'] ?: 0
+                    ];
+                }
+                //统计总数
+                switch ($type) {
+                    case '0':
+                    case '1':
+                    case '2':
+                        $total = StoreOrderModel::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->where('type', $type)->field("count(*) as count,sum(pay_price) as price")
+                            ->find();
+                        break;
+                    case '3':
+                        $total = DataDownloadOrder::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();
+                        break;
+                    case '4':
+                        $total = TestPaperOrder::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();
+                        break;
+                    case '5':
+                        $total = EventSignUp::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();
+                        break;
+                    case '6':
+                        $total = UserRecharge::where('add_time', 'between time', [$now_datebefor, $now_dateafter])
+                            ->where('is_del', 0)->where('paid', 1)->field("count(*) as count,sum(price) as price")
+                            ->find();
+                        break;
+                }
+                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();
+        $user_list = count($user_list) > 0 ? $user_list->toArray() : [];
+        $chartdata = [];
+        $data = [];
+        $chartdata['legend'] = ['用户数'];//分类
+        $chartdata['yAxis']['maxnum'] = 0;//最大值数量
+        if (empty($user_list)) return JsonService::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 JsonService::successful('ok', $chartdata);
+    }
+
+    /**待办事统计
+     * @param Request|null $request
+     */
+    public function Jnotice()
+    {
+        header('Content-type:text/json');
+        $data = [];
+        $data['reflectnum'] = UserExtractModel::where(['status' => 0, 'mer_id' => 0])->count();;//用户提现
+        $data['mer_reflectnum'] = UserExtractModel::where(['status' => 0])->where('mer_id', '>', 0)->count();;//讲师提现
+        $data['msgcount'] = bcadd($data['reflectnum'], $data['mer_reflectnum'], 0);
+        return JsonService::successful('ok', $data);
+    }
+
+    public function check_auth()
+    {
+        return JsonService::successful('ok', $this->checkAuthDecrypt());
+    }
+
+    /**
+     * @return mixed
+     */
+    public function auth()
+    {
+        $curent_version = getversion();
+        $this->assign(['curent_version' => $curent_version]);
+        return $this->fetch();
+    }
+
+    public function verify_dialog()
+    {
+        return $this->fetch();
+    }
+
+    public function apply_dialog()
+    {
+        return $this->fetch();
+    }
+
+    public function copyright_dialog()
+    {
+        return $this->fetch();
+    }
+
+    /**获取授权码
+     * @return false|string
+     */
+    public function auth_data()
+    {
+        return JsonService::successful($this->getAuth());
+    }
+
+    public function get_auth_data()
+    {
+        return JsonService::successful($this->__u05qFaFgCglbkbV9eHWOEiidrJbsm());
+    }
+
+    /**
+     * 获取授权产品
+     */
+    public function get_zsff_store()
+    {
+        return JsonService::successful('ok', $this->__lskbEPbOLZ0cTaZ0XIGUusdFJsVI4yW('zsff'));
+    }
+
+    /**
+     * 下单
+     */
+    public function pay_order()
+    {
+        $data = parent::postMore([
+            ['phone', ''],
+            ['product_type', 'zsff'],
+            ['domain_name', ''],
+            ['company_name', '']
+        ], $this->request);
+        if (!$data['company_name']) {
+            return JsonService::fail('请填写公司名称');
+        }
+        if (!$data['domain_name']) {
+            return JsonService::fail('请填写授权域名');
+        }
+        return JsonService::successful('ok', $this->__nWr5aRIbtPUWlNWFfD1cctaF9G3aiC($data['phone'], $data['product_type'], $data['company_name'], $data['domain_name']));
+    }
+
+    /**
+     * 获取去授权产品
+     */
+    public function get_zsff_copyright()
+    {
+        return JsonService::successful('ok', $this->__lskbEPbOLZ0cTaZ0XIGUusdFJsVI4yW('copyright'));
+    }
+
+    /**
+     * 查询是否购买版权
+     */
+    public function check_copyright()
+    {
+        $data = parent::postMore([
+            ['phone', ''],
+            ['orderId', '']
+        ], $this->request);
+        if (!$data['phone']) {
+            return JsonService::fail('请填写登录手机号');
+        }
+        if (!$data['orderId']) {
+            return JsonService::fail('请填写购买去版权订单号');
+        }
+        return JsonService::successful('ok', $this->__6j3nfcwmWqrsDx8F0MjZGeQyWvLsqeFXww($data['phone'], $data['orderId']));
+    }
+
+    /**
+     * 查询是购买版权订单
+     */
+    public function check_copyright_order()
+    {
+        $data = parent::postMore([
+            ['phone', ''],
+            ['orderId', '']
+        ], $this->request);
+        if (!$data['phone']) {
+            return JsonService::fail('请填写登录手机号');
+        }
+        if (!$data['orderId']) {
+            return JsonService::fail('请填写购买去版权订单号');
+        }
+        return JsonService::successful('ok', $this->__xz8MHDCmMcIbe1HkWr0RM0FGz3gnYIX($data['phone'], $data['orderId']));
+    }
+
+    /**
+     * 发送短息
+     */
+    public function get_code()
+    {
+        $data = parent::postMore([
+            ['phone', ''],
+        ], $this->request);
+        return JsonService::successful('ok', $this->__6u44FLR2RPvjtC3t7fV8mADyfrn37RZj2($data['phone']));
+    }
+
+    /**
+     * 手机号授权登录
+     */
+    public function user_auth_login()
+    {
+        $data = parent::postMore([
+            ['phone', ''],
+            ['code', '']
+        ], $this->request);
+        return JsonService::successful('ok', $this->__k0dUcnKjRUs9lfEllqO9J($data['phone'], $data['code'], true));
+    }
+
+    /**
+     * 申请授权
+     */
+    public function user_auth_apply()
+    {
+        $data = parent::postMore([
+            ['company_name', ''],
+            ['domain_name', ''],
+            ['order_id', ''],
+            ['phone', ''],
+            ['label', 4],
+            ['captcha', '']
+        ], $this->request);
+        if (!$data['company_name']) {
+            return JsonService::fail('请填写公司名称');
+        }
+        if (!$data['domain_name']) {
+            return JsonService::fail('请填写授权域名');
+        }
+
+        if (!$data['phone']) {
+            return JsonService::fail('请填写手机号码');
+        }
+        if (!$data['order_id']) {
+            return JsonService::fail('请填写订单id');
+        }
+        $res = $this->auth_apply($data);
+        if (isset($res['status']) && $res['status'] === 200) {
+            return JsonService::successful('申请授权成功!');
+        } else {
+            return JsonService::fail(isset($res['msg']) ? $res['msg'] : '申请授权失败');
+        }
+    }
+
+    /**
+     * 保存版权信息
+     */
+    public function save_copyright()
+    {
+        $data = parent::postMore([
+            ['copyrightContent', ''],
+        ], $this->request);
+        if (!$data['copyrightContent']) {
+            return JsonService::fail('请填写版权信息');
+        }
+        return JsonService::successful('ok', $this->__qsG71NREI01vix2OkjH($data['copyrightContent']));
+    }
+
+    /**宝塔命令
+     * @return mixed
+     */
+    public function command()
+    {
+        $queue_name = Config::get('queue_name', '') ? Config::get('queue_name', '') : 'doPinkJobQueue';
+        $this->assign(['name' => $queue_name]);
+        return $this->fetch();
+    }
+}
+
+

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

xqd
@@ -0,0 +1,98 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\SystemConfig;
+use basic\SystemBasic;
+use service\CacheService;
+use service\UtilService;
+use service\JsonService;
+use basic\AuthBasic;
+use think\Request;
+use think\Response;
+use think\Session;
+use think\Url;
+
+/**
+ * 登录验证控制器
+ * Class Login
+ * @package app\admin\controller
+ */
+class Login extends AuthBasic
+{
+    public function index()
+    {
+        $this->assign([
+            'login_logo' => SystemConfig::getValue('login_logo'),
+            'Auth_site_name' => SystemConfig::getValue('site_name'),
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 读取版权信息
+     */
+    public function get_copyright()
+    {
+        // return JsonService::successful('ok', $this->__z6uxyJQ4xYa5ee1mx5());
+    }
+
+    /**
+     * 登录验证 + 验证码验证
+     */
+    public function verify(Request $request)
+    {
+        if (!$request->isPost()) return ['code' => 4];
+        $array = $request->Post();
+        $account = $array['account'];
+        $pwd = $array['pwd'];
+        $verify = $array['verify'];
+        //检验验证码
+        if (!captcha_check($verify)) return ['code' => 2];
+        $error = Session::get('login_error', 'admin') ?: ['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, 'admin');
+            return ['code' => 1];
+        } else {
+            $error['num'] += 1;
+            $error['time'] = time();
+            Session::set('login_error', $error, 'admin');
+            return ['code' => 0, 'msg' => SystemAdmin::getErrorInfo()];
+        }
+    }
+
+    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

xqd
@@ -0,0 +1,205 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 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

xqd
@@ -0,0 +1,147 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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::input('title', '分类名称');
+        $f[] = Form::input('intr', '分类简介')->type('textarea');
+        $f[] = Form::number('sort', '排序', 0)->max(99999);
+        $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', ''],
+            ['intr', ''],
+            ['sort', 0],
+            ['status', 1]
+        ], $request);
+        $data['pid'] = 0;
+        $data['title'] = preg_replace("#(^( |\s)+|( |\s)+$)#", "", $data['title']);
+        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::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('编辑的记录不存在!');
+        if (ArticleCategoryModel::where(['title' => $data['title'], 'is_del' => 0])->where('id', '<>', $id)->count() >= 1) 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('删除成功!');
+    }
+
+
+}
+

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

xqd
@@ -0,0 +1,313 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\WebRecommend;
+use app\admin\model\system\RecommendRelation;
+use app\admin\model\system\WebRecommendRelation;
+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($c_id)
+    {
+        $where = parent::getMore([
+            ['limit', 20],
+            ['page', 1],
+            ['cid', 0],
+            ['store_name', ''],
+            ['order', ''],
+            ['is_show', ''],
+        ]);
+        if (!$where['cid'] && $c_id) $where['cid'] = $c_id;
+        return Json::successlayui(Article::getArticleLayList($where));
+    }
+
+    /**
+     * 设置单个产品上架|下架
+     *
+     * @return json
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = parent::getDataModification('article', $id, '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('缺少参数');
+        $res = parent::getDataModification('article', $id, $field, $value);
+        if ($res)
+            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::edit($data, $id, 'id');
+                ArticleContent::edit(['content' => $content], $id, 'nid');
+                Article::commitTrans();
+                return Json::successful('修改成功');
+            } else {
+                $data['add_time'] = time();
+                $data['is_show'] = 1;
+                $data['visit'] = 0;
+                $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 = [];
+                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('请选择推荐');
+        $recommend = Recommend::get($data['recommend_id']);
+        if (!$recommend) 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('推荐失败');
+    }
+
+    /**取消推荐
+     * @param int $id
+     */
+    public function cancel_recommendation($id = 0, $article_id = 0)
+    {
+        if (!$id || !$article_id) $this->failed('缺少参数');
+        if (RecommendRelation::be(['id' => $id, 'link_id' => $article_id])) {
+            $res = RecommendRelation::where(['id' => $id, 'link_id' => $article_id])->delete();
+            if ($res)
+                return Json::successful('取消推荐成功');
+            else
+                return Json::fail('取消推荐失败');
+        } else {
+            return Json::fail('推荐不存在');
+        }
+    }
+
+    /**
+     * 添加推荐
+     * @param int $special_id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function web_recommend($article_id = 0)
+    {
+        if (!$article_id) $this->failed('缺少参数');
+        $article = Article::get($article_id);
+        if (!$article) $this->failed('没有查到此新闻');
+        $form = Form::create(Url::build('save_web_recommend', ['article_id' => $article_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () {
+                $model = WebRecommend::where(['is_show' => 1, 'type' => 4]);
+                $list = $model->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_web_recommend($article_id = 0)
+    {
+        if (!$article_id) $this->failed('缺少参数');
+        $data = parent::postMore([
+            ['recommend_id', 0],
+            ['sort', 0],
+        ]);
+        if (!$data['recommend_id']) return Json::fail('请选择推荐');
+        $recommend = WebRecommend::get($data['recommend_id']);
+        if (!$recommend) return Json::fail('导航菜单不存在');
+        $data['add_time'] = time();
+        $data['type'] = $recommend->type;
+        $data['link_id'] = $article_id;
+        if (WebRecommendRelation::be(['type' => $recommend->type, 'link_id' => $article_id, 'recommend_id' => $data['recommend_id']])) return Json::fail('已推荐,请勿重复推荐');
+        if (WebRecommendRelation::set($data))
+            return Json::successful('推荐成功');
+        else
+            return Json::fail('推荐失败');
+    }
+
+    /**取消推荐
+     * @param int $id
+     */
+    public function cancel_web_recommendation($id = 0, $article_id = 0)
+    {
+        if (!$id || !$article_id) return Json::fail('缺少参数');
+        if (WebRecommendRelation::be(['id' => $id, 'link_id' => $article_id])) {
+            $res = WebRecommendRelation::where(['id' => $id, 'link_id' => $article_id])->delete();
+            if ($res)
+                return Json::successful('取消推荐成功');
+            else
+                return Json::fail('取消推荐失败');
+        } else {
+            return Json::fail('推荐不存在');
+        }
+    }
+}

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

xqd
@@ -0,0 +1,156 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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('删除成功!');
+    }
+}
+

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

xqd
@@ -0,0 +1,52 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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('删除失败');
+    }
+}

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

xqd
@@ -0,0 +1,201 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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)
+    {
+        $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();
+    }
+}

+ 472 - 0
application/admin/controller/download/DataDownload.php

xqd
@@ -0,0 +1,472 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\download;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use app\admin\model\download\DataDownloadCategpry;
+use app\admin\model\download\DataDownload as DownloadModel;
+use app\admin\model\download\DataDownloadRecords;
+use service\SystemConfigService;
+use app\admin\model\system\Recommend;
+use app\admin\model\system\RecommendRelation;
+use app\admin\model\system\WebRecommend;
+use app\admin\model\system\WebRecommendRelation;
+use app\admin\model\merchant\Merchant;
+use service\FormBuilder as Form;
+use think\Url;
+
+/**资料控制器
+ * Class DataDownload
+ * @package app\admin\controller\download
+ */
+class DataDownload extends AuthController
+{
+    /**
+     * 资料下载列表
+     */
+    public function index()
+    {
+        $cate_list = DataDownloadCategpry::specialCategoryAll(2);
+        $mer_list = Merchant::getMerchantList();
+        $this->assign([
+            'cate_list' => $cate_list,
+            'mer_list' => $mer_list
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取资料下载列表
+     */
+    public function data_download_list()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['status', 1],
+            ['page', 1],
+            ['limit', 20],
+            ['cate_id', 0],
+            ['mer_id', 0],
+            ['is_show', ''],
+            ['title', '']
+        ]);
+        return Json::successlayui(DownloadModel::get_download_list($where));
+    }
+
+    /**资料审核
+     * @return mixed
+     */
+    public function examine()
+    {
+        $cate_list = DataDownloadCategpry::specialCategoryAll(2);
+        $mer_list = Merchant::getMerchantList();
+        $this->assign([
+            'cate_list' => $cate_list,
+            'mer_list' => $mer_list
+        ]);
+        return $this->fetch();
+    }
+
+    /**获得审核资料
+     * @throws \think\Exception
+     */
+    public function data_download_examine_list()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['status', ''],
+            ['page', 1],
+            ['limit', 20],
+            ['cate_id', 0],
+            ['mer_id', 0],
+            ['title', '']
+        ]);
+        return Json::successlayui(DownloadModel::get_download_examine_list($where));
+    }
+
+    public function examineDetails($id)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $details = DownloadModel::get($id);
+        if (!$details) return Json::fail('资料不存在');
+        $this->assign(['details' => json_encode($details)]);
+        return $this->fetch('material');
+    }
+
+    /**不通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function fail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!DownloadModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $special = DownloadModel::get($id);
+        if (!$special) return Json::fail('操作记录不存!');
+        if ($special->status != 0) return Json::fail('您已审核,请勿重复操作');
+        DownloadModel::beginTrans();
+        $res = DownloadModel::changeFail($id, $special['mer_id'], $fail_msg['message']);
+        if ($res) {
+            DownloadModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            DownloadModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    /**通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function succ($id)
+    {
+        if (!DownloadModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $special = DownloadModel::get($id);
+        if (!$special) return Json::fail('操作记录不存!');
+        if ($special->status != 0) return Json::fail('您已审核,请勿重复操作');
+        DownloadModel::beginTrans();
+        $res = DownloadModel::changeSuccess($id, $special['mer_id']);
+        if ($res) {
+            DownloadModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            DownloadModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+
+    public function get_cate_list()
+    {
+        $cate_list = DataDownloadCategpry::specialCategoryAll(2);
+        return Json::successful($cate_list);
+    }
+
+    /**资料编辑、添加
+     * @param int $id
+     */
+    public function add($id = 0)
+    {
+        if ($id) {
+            $download = DownloadModel::get($id);
+            if (!$download) return Json::fail('资料不存在');
+            $this->assign(['download' => json_encode($download)]);
+        }
+        $this->assign(['id' => $id]);
+        return $this->fetch();
+    }
+
+    /**保存、编辑轻专题
+     * @param int $id
+     */
+    public function save_data($id = 0)
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['abstract', ''],
+            ['cate_id', 0],
+            ['sales', 0],
+            ['image', ''],
+            ['poster_image', ''],
+            ['money', 0],
+            ['sort', 0],
+            ['member_money', 0],
+            ['member_pay_type', 0],
+            ['pay_type', 0],//支付方式:免费、付费
+            ['type', 0],
+            ['link', ''],
+            ['network_disk_link', ''],
+            ['network_disk_pwd', '']
+        ]);
+
+        if (!$data['cate_id']) return Json::fail('请选择分类');
+        if (!$data['title']) return Json::fail('请输入资料标题');
+        if (!$data['abstract']) return Json::fail('请输入资料简介');
+        if (!$data['image']) return Json::fail('请上传资料封面图');
+        if (!$data['poster_image']) return Json::fail('请上传推广海报');
+        if ($data['type'] == 1) {
+            if (!$data['link']) return Json::fail('请上传文件');
+            $data['network_disk_link'] = '';
+            $data['network_disk_pwd'] = '';
+        } else if ($data['type'] == 2) {
+            if (!$data['network_disk_link']) return Json::fail('请输入百度网盘文件链接');
+            if (!$data['network_disk_pwd']) return Json::fail('请输入百度网盘文件获取密码');
+            $data['link'] = '';
+        } else {
+            if (!$data['link']) return Json::fail('请上传文件');
+            if (!$data['network_disk_link']) return Json::fail('请输入百度网盘文件链接');
+            if (!$data['network_disk_pwd']) 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;
+        }
+        DownloadModel::beginTrans();
+        try {
+            if ($id) {
+                $res = DownloadModel::edit($data, $id, 'id');
+                if ($res) {
+                    DownloadModel::commitTrans();
+                    return Json::successful('修改成功');
+                } else {
+                    DownloadModel::rollbackTrans();
+                    return Json::fail('添加失败');
+                }
+            } else {
+                $data['is_show'] = 1;
+                $data['add_time'] = time();
+                if (DownloadModel::be(['title' => $data['title'], 'is_del' => 0])) return Json::fail('资料已存在');
+                $res = DownloadModel::set($data);
+                if ($res) {
+                    DownloadModel::commitTrans();
+                    return Json::successful('添加成功');
+                } else {
+                    DownloadModel::rollbackTrans();
+                    return Json::fail('添加失败');
+                }
+            }
+        } catch (\Exception $e) {
+            DownloadModel::rollbackTrans();
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    public function sliceFileUpload()
+    {
+        $aliyunOss = \Api\AliyunOss::instance([
+            'AccessKey' => SystemConfigService::get('accessKeyId'),
+            'AccessKeySecret' => SystemConfigService::get('accessKeySecret'),
+            'OssEndpoint' => SystemConfigService::get('end_point'),
+            'OssBucket' => SystemConfigService::get('OssBucket'),
+            'uploadUrl' => SystemConfigService::get('uploadUrl'),
+        ]);
+        $res = $aliyunOss->sliceFileUpload('file');
+        if ($res) {
+            return Json::successful('上传成功', ['url' => $res['url']]);
+        } else {
+            return Json::fail('上传失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        if (!$field || !$id || $value == '') Json::fail('缺少参数3');
+
+        if ($field == 'sort' && bcsub($value, 0, 0) < 0) return Json::fail('排序不能为负数');
+        if ($field == 'ficti' && bcsub($value, 0, 0) < 0) return Json::fail('虚拟下载量不能为负数');
+        $res = DownloadModel::where('id', $id)->update([$field => $value]);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**
+     * 添加推荐
+     * @param int $special_id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function recommend($data_id = 0)
+    {
+        if (!$data_id) $this->failed('缺少参数');
+        $download = DownloadModel::get($data_id);
+        if (!$download) $this->failed('没有查到此资料');
+        if ($download->is_del) $this->failed('此资料已删除');
+        $form = Form::create(Url::build('save_recommend', ['data_id' => $data_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () {
+                $model = Recommend::where(['is_show' => 1, 'is_fixed' => 0, 'type' => 14]);
+                $list = $model->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($data_id = 0)
+    {
+        if (!$data_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'] = $data_id;
+        if (RecommendRelation::be(['type' => $recommend->type, 'link_id' => $data_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, $data_id = 0)
+    {
+        if (!$id || !$data_id) $this->failed('缺少参数');
+        if (RecommendRelation::be(['id' => $id, 'link_id' => $data_id])) {
+            $res = RecommendRelation::where(['id' => $id, 'link_id' => $data_id])->delete();
+            if ($res)
+                return Json::successful('取消推荐成功');
+            else
+                return Json::fail('取消推荐失败');
+        } else {
+            return Json::fail('推荐不存在');
+        }
+    }
+
+    /**
+     * 添加推荐
+     * @param int $data_id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function web_recommend($data_id = 0)
+    {
+        if (!$data_id) $this->failed('缺少参数');
+        $download = DownloadModel::get($data_id);
+        if (!$download) $this->failed('没有查到此资料');
+        if ($download->is_del) $this->failed('此资料已删除');
+        $form = Form::create(Url::build('save_web_recommend', ['data_id' => $data_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () {
+                $model = WebRecommend::where(['is_show' => 1, 'type' => 3]);
+                $list = $model->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_web_recommend($data_id = 0)
+    {
+        if (!$data_id) $this->failed('缺少参数');
+        $data = parent::postMore([
+            ['recommend_id', 0],
+            ['sort', 0],
+        ]);
+        if (!$data['recommend_id']) return Json::fail('请选择推荐');
+        $recommend = WebRecommend::get($data['recommend_id']);
+        if (!$recommend) return Json::fail('导航菜单不存在');
+        $data['add_time'] = time();
+        $data['type'] = $recommend->type;
+        $data['link_id'] = $data_id;
+        if (WebRecommendRelation::be(['type' => $recommend->type, 'link_id' => $data_id, 'recommend_id' => $data['recommend_id']])) return Json::fail('已推荐,请勿重复推荐');
+        if (WebRecommendRelation::set($data))
+            return Json::successful('推荐成功');
+        else
+            return Json::fail('推荐失败');
+    }
+
+    /**取消推荐
+     * @param int $id
+     */
+    public function cancel_web_recommendation($id = 0, $data_id = 0)
+    {
+        if (!$id || !$data_id) return Json::fail('缺少参数');
+        if (WebRecommendRelation::be(['id' => $id, 'link_id' => $data_id])) {
+            $res = WebRecommendRelation::where(['id' => $id, 'link_id' => $data_id])->delete();
+            if ($res)
+                return Json::successful('取消推荐成功');
+            else
+                return Json::fail('取消推荐失败');
+        } else {
+            return Json::fail('推荐不存在');
+        }
+    }
+
+    /**资料删除
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) $this->failed('缺少参数');
+        $download = DownloadModel::get($id);
+        if (!$download) $this->failed('没有查到此资料');
+        if ($download->is_del) $this->failed('此资料已删除');
+        $data['is_del'] = 1;
+        $res = DownloadModel::edit($data, $id);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+    /**下载记录
+     * @param int $id
+     * @throws \think\exception\DbException
+     */
+    public function records($id = 0)
+    {
+        $this->assign(['id' => $id, 'year' => getMonth('y')]);
+        return $this->fetch();
+    }
+
+    public function get_download_records_list($id)
+    {
+        $where = parent::getMore([
+            ['id', 0],
+            ['page', 1],
+            ['limit', 20],
+            ['excel', 0],
+            ['data', '']
+        ]);
+        $where['id'] = $where['id'] >= 0 ? $where['id'] : $id;
+        return Json::successlayui(DataDownloadRecords::specialLearningRecordsLists($where, $where['id']));
+    }
+
+}

+ 162 - 0
application/admin/controller/download/DataDownloadCategpry.php

xqd
@@ -0,0 +1,162 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\download;
+
+use app\admin\controller\AuthController;
+use app\admin\model\download\DataDownloadCategpry as DataCategpryModel;
+use service\JsonService as Json;
+use app\admin\model\download\DataDownload;
+
+/**
+ * 资料分类控制器
+ * Class DataDownloadCategpry
+ * @package app\admin\controller\download
+ */
+class DataDownloadCategpry extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    public function get_download_cate_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', $this->request->param('pid', '')],
+            ['title', '']
+        ]);
+        return Json::successful(DataCategpryModel::get_download_cate_list($where));
+    }
+
+    /**
+     * 创建分类
+     * @param int $id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0)
+    {
+        $cate = $id > 0 ? DataCategpryModel::get($id) : [];
+        $this->assign(['cate' => json_encode($cate), 'id' => $id]);
+        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()
+    {
+        $cate = DataCategpryModel::specialCategoryAll(1);
+        $array = [];
+        $oneCate['id'] = 0;
+        $oneCate['title'] = '顶级分类';
+        array_push($array, $oneCate);
+        foreach ($cate as $key => $value) {
+            array_push($array, $value);
+        }
+        return Json::successful($array);
+    }
+
+    /**
+     * 新增或者修改
+     *
+     * @return json
+     */
+    public function save($id = 0)
+    {
+        $post = parent::postMore([
+            ['title', ''],
+            ['pid', 0],
+            ['sort', 0],
+            ['is_show', 0],
+        ]);
+        if (!$post['title']) return Json::fail('请输入分类名称');
+        if ($id) {
+            $cate = DataCategpryModel::get($id);
+            if (!$cate['pid'] && $post['pid'] && DataCategpryModel::be(['pid' => $id, 'is_del' => 0])) return Json::fail('无法移动有下级的分类');
+            if (DataCategpryModel::where(['title' => $post['title'], 'is_del' => 0])->where('id', '<>', $id)->count() >= 1) return Json::fail('分类名称已存在');
+            $res = DataCategpryModel::edit($post, $id);
+            if ($res)
+                return Json::successful('修改成功');
+            else
+                return Json::fail('修改失败');
+        } else {
+            $post['add_time'] = time();
+            if (DataCategpryModel::be(['title' => $post['title'], 'is_del' => 0])) {
+                return Json::fail('分类名称已存在!');
+            }
+            $res = DataCategpryModel::set($post);
+            if ($res)
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        ($field == '' || $id == '' || $value == '') && Json::fail('缺少参数');
+        $res = DataCategpryModel::where(['id' => $id])->update([$field => $value]);
+        if ($res)
+            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 = DataCategpryModel::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('缺少参数');
+        $cate = DataCategpryModel::get($id);
+        if ($cate['pid']) {
+            if (DataDownload::PreWhere()->where('cate_id', $id)->count()) return Json::fail('暂无法删除,请先去除资料关联');
+        } else {
+            if (DataCategpryModel::where('pid', $id)->where('is_del', 0)->count()) return Json::fail('暂无法删除,请删除下级分类');
+        }
+        $data['is_del'] = 1;
+        $res = DataCategpryModel::edit($data, $id);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除成功');
+    }
+}

+ 161 - 0
application/admin/controller/educational/Classes.php

xqd
@@ -0,0 +1,161 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\educational;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use app\admin\model\educational\Classes as ClassesModel;
+use app\admin\model\educational\Teacher as TeacherModel;
+use app\admin\model\educational\Student as StudentModel;
+use app\admin\model\merchant\Merchant;
+use service\FormBuilder as Form;
+use think\Db;
+use think\Url;
+
+/**
+ * 班级管理
+ * Class Classes
+ */
+class Classes extends AuthController
+{
+    /**
+     * 班级列表
+     */
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 获取班级列表
+     */
+    public function getClassesList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['status', ''],
+            ['title', ''],
+        ]);
+        return Json::successlayui(ClassesModel::getClassesLists($where));
+    }
+
+    /**
+     * 老师列表
+     */
+    public function getTeacherList()
+    {
+        $list = TeacherModel::where(['is_del' => 0])->field('name,id')->order('sort desc,add_time desc')->select();
+        $list = count($list) > 0 ? $list->toArray() : [];
+        return Json::successful($list);
+    }
+
+    /**关联专题
+     * @param int $id
+     */
+    public function relation($id = 0)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $questions = ClassesModel::get($id);
+        if (!$questions) Json::fail('班级不存在');
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['id' => $id, 'relation_ids' => $questions['relation'],'mer_list' => $mer_list]);
+        return $this->fetch('relation');
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        if (!$field || !$id || $value == '') Json::fail('缺少参数3');
+        if ($field == 'sort' && bcsub($value, 0, 0) < 0) return Json::fail('排序不能为负数');
+        $res = parent::getDataModification('classes', $id, $field, $value);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**添加/编辑
+     * @param int $id
+     * @return mixed
+     */
+    public function create($id = 0)
+    {
+        $classes = $id > 0 ? ClassesModel::get($id) : [];
+        $this->assign(['id' => $id, 'classes' => json_encode($classes)]);
+        return $this->fetch();
+    }
+
+    /**添加/编辑班级
+     * @param int $id
+     */
+    public function save_add($id = 0)
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['status', 1],
+            ['upper_limit', 0],
+            ['teacher_id', ''],
+            ['start_time', ''],
+            ['end_time', ''],
+            ['sort', 0]
+        ]);
+        if (!$data['title']) return Json::fail('请输入班级名称');
+        if ($data['upper_limit'] <= 0) return Json::fail('请输入班级学员数量上限');
+        if ($data['teacher_id'] == '') return Json::fail('请选择班级老师');
+        if ($data['start_time'] == '') return Json::fail('请选择班级开班时间');
+        if ($data['end_time'] == '') return Json::fail('请选择班级结班时间');
+        $data['start_time'] = strtotime($data['start_time']);
+        $data['end_time'] = strtotime($data['end_time']);
+        if ($data['end_time'] <= $data['start_time']) return Json::fail('结班时间不能小于等于开班时间');
+        if ($id) {
+            if (ClassesModel::where(['title' => $data['title'], 'is_del' => 0])->where('id', '<>', $id)->count() >= 1) return Json::fail('班级名称已存在');
+            $res = ClassesModel::edit($data, $id);
+        } else {
+            $data['add_time'] = time();
+            if (!ClassesModel::be(['title' => $data['title'], 'is_del' => 0])) {
+                $res = ClassesModel::set($data);
+            } else {
+                return Json::fail('班级已存在');
+            }
+        }
+        if ($res) {
+            return Json::successful('添加/编辑成功');
+        } else {
+            return Json::fail('添加/编辑失败');
+        }
+    }
+
+    /**删除班级
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $classes = ClassesModel::get($id);
+        if (!$classes) return Json::fail('要删除的班级不存在');
+        $res = parent::getDataModification('classes', $id, 'is_del', 1);
+        if ($res) {
+            $count = StudentModel::where('classes_id', $classes['id'])->count();
+            if ($count) StudentModel::where('classes_id', $classes['id'])->update(['is_del' => 1]);
+            return Json::successful('删除成功');
+        } else {
+            return Json::fail('删除失败');
+        }
+    }
+}

+ 400 - 0
application/admin/controller/educational/Student.php

xqd
@@ -0,0 +1,400 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\educational;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use app\admin\model\educational\Teacher as TeacherModel;
+use app\admin\model\educational\Classes as ClassesModel;
+use app\admin\model\educational\Student as StudentModel;
+use app\admin\model\educational\ContactPhone as ContactPhoneModel;
+use app\admin\model\questions\TestPaper as TestPaperModel;
+use app\admin\model\download\DataDownloadBuy;
+use app\admin\model\questions\TestPaperObtain;
+use app\admin\model\user\User;
+use app\admin\model\special\Special;
+use app\admin\model\special\SpecialSource;
+use app\admin\model\special\SpecialBuy;
+use app\admin\model\merchant\Merchant;
+
+/**
+ * 学员
+ * Class Student
+ */
+class Student extends AuthController
+{
+    /**
+     * 学员列表
+     */
+    public function index($cid = 0)
+    {
+        $this->assign(['cid' => $cid, 'classes' => ClassesModel::classesList()]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取学员列表
+     */
+    public function getStudentList($c_id = 0)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['cid', 0],
+            ['title', ''],
+        ]);
+        if ($c_id > 0 && $where['cid'] == 0) $where['cid'] = $c_id;
+        return Json::successlayui(StudentModel::getStudentLists($where));
+    }
+
+    /**
+     * 班级列表
+     */
+    public function classesList()
+    {
+        $classes = ClassesModel::classesList();
+        return Json::successful($classes);
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        if (!$field || !$id || $value == '') Json::fail('缺少参数3');
+        if ($field == 'sort' && bcsub($value, 0, 0) < 0) return Json::fail('排序不能为负数');
+        $res = parent::getDataModification('student', $id, $field, $value);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**添加/编辑
+     * @param int $id
+     * @return mixed
+     */
+    public function create($id = 0, $uid = 0)
+    {
+        $student = $id > 0 ? StudentModel::get($id) : [];
+        if ($student && $id) $phone = ContactPhoneModel::contactPhoneList($id);
+        else $phone = [];
+        $this->assign(['id' => $id, 'uid' => $uid, 'student' => json_encode($student), 'phone' => json_encode($phone)]);
+        return $this->fetch();
+    }
+
+    /**添加/编辑学员
+     * @param int $id
+     */
+    public function save_add($id = 0)
+    {
+        $data = parent::postMore([
+            ['name', ''],
+            ['uid', 0],
+            ['classes_id', 0],
+            ['sex', 0],
+            ['image', ''],
+            ['province', ''],
+            ['city', ''],
+            ['district', ''],
+            ['detail', ''],
+            ['contact', ''],
+            ['sort', 0]
+        ]);
+        if ($data['classes_id'] <= 0) return Json::fail('请选择所在班级');
+        if (!$data['name']) return Json::fail('请输入学员名称');
+        if (!$data['image']) return Json::fail('请选择学员头像');
+        if (!$data['province'] || !$data['city'] || !$data['district'] || !$data['detail']) return Json::fail('请选择地址');
+        $contact = json_decode($data['contact'], true);
+        StudentModel::beginTrans();
+        if ($id) {
+            $res = StudentModel::edit($data, $id);
+            $res1 = ContactPhoneModel::contactPhoneAdd($id, $contact);
+        } else {
+            $user = User::where('uid', $data['uid'])->field('identitys,nickname')->find();
+            if ($user['identitys'] == 2) return Json::fail('该用户已是老师');
+            $data['nickname'] = $user['nickname'];
+            $data['add_time'] = time();
+            $res = true;
+            if (!StudentModel::be(['uid' => $data['uid'], 'classes_id' => $data['classes_id'], 'is_del' => 0])) {
+                $upper_limit = ClassesModel::where('id', $data['classes_id'])->value('upper_limit');
+                $count = StudentModel::where('classes_id', $data['classes_id'])->where('is_del', 0)->count();
+                if (bcsub($count, $upper_limit, 0) >= 0) return Json::fail('班级学员数量已达上限,不能添加!');
+                $id = StudentModel::insertGetId($data);
+                $res1 = ContactPhoneModel::contactPhoneAdd($id, $contact);
+                if ($id && $res1) User::edit(['identitys' => 1], $data['uid'], 'uid');
+            } else {
+                StudentModel::rollbackTrans();
+                return Json::fail('该用户已在班级中');
+            }
+        }
+        if ($res && $id && $res1) {
+            StudentModel::commitTrans();
+            return Json::successful('添加/编辑成功');
+        } else {
+            StudentModel::rollbackTrans();
+            return Json::fail('添加/编辑失败');
+        }
+    }
+
+    /**删除学员
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $student = StudentModel::get($id);
+        if (!$student) return Json::fail('要删除的学员不存在');
+        $res = parent::getDataModification('student', $id, 'is_del', 1);
+        if ($res) {
+            User::edit(['identitys' => 0], $student['uid'], 'uid');
+            ContactPhoneModel::where('sid', $id)->delete();
+            return Json::successful('删除成功');
+        } else {
+            return Json::fail('删除失败');
+        }
+    }
+
+    /**给学员发送试卷
+     * @param string $uid
+     * @return mixed
+     */
+    public function send()
+    {
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['mer_list' => $mer_list]);
+        return $this->fetch();
+    }
+
+    /**
+     *试卷列表
+     */
+    public function getTestPaperList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', ''],
+            ['type', ''],
+            ['is_show', 1],
+            ['status', 1],
+            ['mer_id', 0],
+            ['title', '']
+        ]);
+        return Json::successlayui(TestPaperModel::sendTestPaperExercisesList($where));
+    }
+
+    /**发送试卷
+     * @param $sid
+     * @param $tid
+     */
+    public function sendTestPaper($sid, $tid)
+    {
+        if (!$sid || !$tid) return Json::fail('缺少参数无法赠送');
+        $sid = explode(',', $sid);
+        $tid = explode(',', $tid);
+        foreach ($sid as $k => $item) {
+            $res = TestPaperObtain::addsend($item, $tid);
+        }
+        if ($res) {
+            return Json::successful('发送成功');
+        } else {
+            return Json::fail('发送失败');
+        }
+    }
+
+    /**
+     *移除已发送的试卷
+     */
+    public function removeTestPaper($uid, $test_id)
+    {
+        if (!$uid || !$test_id) return Json::fail('参数错误');
+        $res = TestPaperObtain::where(['uid' => $uid, 'test_id' => $test_id])->update(['is_del' => 1]);
+        if ($res) {
+            return Json::successful('移除成功');
+        } else {
+            return Json::fail('移除失败');
+        }
+    }
+
+    /**给学员发送课程
+     * @param string $uid
+     * @return mixed
+     */
+    public function special()
+    {
+        $mer_list = Merchant::getMerchantList();
+        $this->assign([
+            'mer_list' => $mer_list
+        ]);
+        return $this->fetch();
+    }
+
+    /**发送专题
+     * @param $sid
+     * @param $tid
+     */
+    public function sendSpecial($uid, $tid)
+    {
+        if (!$uid || !$tid) return Json::fail('缺少参数无法赠送');
+        $uid = explode(',', $uid);
+        $tid = explode(',', $tid);
+        $res = false;
+        foreach ($uid as $k => $item) {
+            foreach ($tid as $h => $value) {
+                $res = $this->save_give($item, $value);
+            }
+        }
+        if ($res) {
+            return Json::successful('赠送成功');
+        } else {
+            return Json::fail('赠送失败');
+        }
+    }
+
+    /**赠送专题
+     * @param $uid
+     * @param $special_id
+     * @return bool|object
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function save_give($uid, $special_id)
+    {
+        if (!$uid || !$special_id) return false;
+        $special = Special::PreWhere()->where(['id'=>$special_id])->find();
+        if (SpecialBuy::be(['uid' => $uid, 'special_id' => $special_id, 'is_del' => 0, 'type' => 3])) return true;
+        if ($special['type'] == SPECIAL_COLUMN) {
+            $special_source = SpecialSource::getSpecialSource($special['id']);
+            if ($special_source) {
+                foreach ($special_source as $k => $v) {
+                    $task_special = Special::PreWhere()->where(['id'=>$v['source_id']])->find();
+                    if ($task_special['is_show'] == 1) {
+                        SpecialBuy::setBuySpecial('', $uid, $v['source_id'], 3, $task_special['validity'], $special_id);
+                    }
+                }
+            }
+        }
+        $res = SpecialBuy::setBuySpecial('', $uid, $special_id, 3, $special['validity']);
+        if ($res) {
+            TestPaperObtain::setTestPaper('', $uid, $special_id, 3);
+            DataDownloadBuy::setDataDownload('', $uid, $special_id, 2);
+        }
+        return $res;
+    }
+
+
+    /**已获得的课程
+     * @param int $uid
+     * @return mixed
+     */
+    public function special_list($uid = 0)
+    {
+        $this->assign('uid', $uid);
+        return $this->fetch();
+    }
+
+    /**获取已获得课程
+     * @param $uid
+     */
+    public function getUserSpecialList($uid)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20]
+        ]);
+        $where['uid'] = $uid;
+        $special_task = Special::getUserSpecialList($where);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                if (isset($where['is_light']) && $v['is_light'] && $v['type'] == 6) {
+                    $special_task['data'][$k]['types'] = lightTypeNmae($v['light_type']);
+                } else {
+                    $special_task['data'][$k]['types'] = parent::specialTaskType($v['type']);
+                }
+            }
+        }
+        return Json::successlayui($special_task);
+    }
+
+    /**移除专题
+     * @param int $id
+     * @throws \think\exception\DbException
+     */
+    public function del_special_buy($uid = 0, $special_id = 0)
+    {
+        if (!$uid || !$special_id) return Json::fail('缺少参数');
+        $type = Special::where(['id' => $special_id])->value('type');
+        $res = SpecialBuy::where(['uid' => $uid, 'type' => 3, 'special_id' => $special_id])->update(['is_del' => 1]);
+        if ($type == SPECIAL_COLUMN) {
+            $res2 = SpecialBuy::where(['uid' => $uid, 'type' => 3, 'column_id' => $special_id])->update(['is_del' => 1]);
+            $res = $res && $res2;
+        }
+        if ($res) {
+            TestPaperObtain::delTestPaper('', $uid, $special_id, 3);
+            DataDownloadBuy::delDataDownload('', $uid, $special_id, 2);
+            return Json::successful('移除成功');
+        } else
+            return Json::fail('移除失败');
+    }
+
+    /**已获得试卷
+     * @param int $uid
+     * @return mixed
+     */
+    public function test_paper($uid = 0)
+    {
+        $this->assign('uid', $uid);
+        return $this->fetch();
+    }
+
+    /**获取已获得试卷
+     * @param $uid
+     */
+    public function getUserTestPaperList($uid)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20]
+        ]);
+        $where['uid'] = $uid;
+        return Json::successlayui(TestPaperModel::getUserTestPaperList($where));
+    }
+
+    /**获取用户
+     * @return mixed
+     */
+    public function user()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 获取用户列表
+     */
+    public function user_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['nickname', ''],
+            ['identitys', 1],
+            ['order', '']
+        ]);
+        return Json::successlayui(User::add_teacher_user_list($where));
+    }
+}

+ 172 - 0
application/admin/controller/educational/Teacher.php

xqd
@@ -0,0 +1,172 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\educational;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use app\admin\model\educational\Teacher as TeacherModel;
+use app\admin\model\educational\TeacherCategpry;
+use app\admin\model\user\User;
+
+/**
+ * 老师控制器
+ * Class Teacher
+ */
+class Teacher extends AuthController
+{
+    /**
+     * 老师列表
+     */
+    public function index()
+    {
+        $this->assign(['category' => TeacherCategpry::taskCategoryAll(2)]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取老师列表
+     */
+    public function getTeacherList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', 0],
+            ['title', ''],
+        ]);
+        return Json::successlayui(TeacherModel::getTeacherLists($where));
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        if (!$field || !$id || $value == '') Json::fail('缺少参数3');
+        if ($field == 'sort' && bcsub($value, 0, 0) < 0) return Json::fail('排序不能为负数');
+        $res = parent::getDataModification('teacher', $id, $field, $value);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**添加/编辑
+     * @param int $id
+     * @return mixed
+     */
+    public function create($id = 0, $uid = 0)
+    {
+        $teacher = $id > 0 ? TeacherModel::get($id) : [];
+        $this->assign(['id' => $id, 'uid' => $uid, 'teacher' => json_encode($teacher)]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取老师分类
+     */
+    public function get_teacher_cate()
+    {
+        $category = TeacherCategpry::taskCategoryAll(2);
+        return Json::successful($category);
+    }
+
+    /**添加/编辑老师
+     * @param int $id
+     */
+    public function save_add($id = 0)
+    {
+        $data = parent::postMore([
+            ['name', ''],
+            ['uid', 0],
+            ['pid', 0],
+            ['image', ''],
+            ['position', ''],
+            ['phone', ''],
+            ['sort', 0]
+        ]);
+        if ($data['pid'] <= 0) return Json::fail('请选择老师分类');
+        if (!$data['name']) return Json::fail('请输入老师名称');
+        if (!$data['image']) return Json::fail('请选择老师头像');
+        if (!$data['position']) return Json::fail('请输入老师职位');
+        if (!$data['phone']) return Json::fail('请输入老师手机号');
+        if (!check_phone($data['phone'])) return Json::fail('手机号不正确');
+        TeacherModel::beginTrans();
+        if ($id) {
+            $res = TeacherModel::edit($data, $id);
+        } else {
+            $user = User::where('uid', $data['uid'])->field('identitys,nickname')->find();
+            if ($user['identitys'] == 2) return Json::fail('该用户已是老师');
+            if ($user['identitys'] == 1) return Json::fail('该用户已是学员');
+            $data['nickname'] = $user['nickname'];
+            $data['add_time'] = time();
+            if (!TeacherModel::be(['uid' => $data['uid'], 'is_del' => 0])) {
+                $res = TeacherModel::set($data);
+                if ($res) User::where('uid', $data['uid'])->update(['identitys' => 2]);
+            } else {
+                TeacherModel::rollbackTrans();
+                return Json::fail('该用户已是老师');
+            }
+        }
+        if ($res) {
+            TeacherModel::commitTrans();
+            return Json::successful('添加/编辑成功');
+        } else {
+            TeacherModel::rollbackTrans();
+            return Json::fail('添加/编辑失败');
+        }
+    }
+
+    /**删除老师
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $teacher = TeacherModel::get($id);
+        if (!$teacher) return Json::fail('要删除的老师不存在');
+        $res = parent::getDataModification('teacher', $id, 'is_del', 1);
+        if ($res) {
+            User::where('uid', $teacher['uid'])->update(['identitys' => 0]);
+            return Json::successful('删除成功');
+        } else {
+            return Json::fail('删除失败');
+        }
+    }
+
+    /**获取用户
+     * @return mixed
+     */
+    public function user()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 获取用户列表
+     */
+    public function user_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['nickname', ''],
+            ['identitys', 0],
+            ['order', '']
+        ]);
+        return Json::successlayui(User::add_teacher_user_list($where));
+    }
+}

+ 147 - 0
application/admin/controller/educational/TeacherCategpry.php

xqd
@@ -0,0 +1,147 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\educational;
+
+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\educational\TeacherCategpry as TeacherCategpryModel;
+use app\admin\model\educational\Teacher as TeacherModel;
+
+/**
+ * 老师分类
+ * Class TeacherCategpry
+ */
+class TeacherCategpry extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 分类列表
+     */
+    public function get_category_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', 0],
+            ['title', ''],
+        ]);
+        return Json::successful(TeacherCategpryModel::getAllList($where));
+    }
+
+    /**
+     * 创建分类
+     * @param int $id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0)
+    {
+        $cate = $id > 0 ? TeacherCategpryModel::get($id) : [];
+        $this->assign(['cate' => json_encode($cate), 'id' => $id]);
+        return $this->fetch();
+    }
+
+    public function get_cate_list()
+    {
+        $category = TeacherCategpryModel::taskCategoryAll(2);
+        return Json::successful($category);
+    }
+
+    public function add_cate_list()
+    {
+        $category = TeacherCategpryModel::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('缺少参数');
+        $res = parent::getDataModification('teacher_categpry', $id, $field, $value);
+        if ($res)
+            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) {
+            $cate = TeacherCategpryModel::get($id);
+            if (!$cate['pid'] && $post['pid'] && TeacherCategpryModel::be(['pid' => $id, 'is_del' => 0])) return Json::fail('无法移动有下级的分类');
+            $res = TeacherCategpryModel::edit($post, $id);
+            if ($res)
+                return Json::successful('修改成功');
+            else
+                return Json::fail('修改失败');
+        } else {
+            $post['add_time'] = time();
+            $res = TeacherCategpryModel::set($post);
+            if ($res)
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 删除
+     *
+     * @return json
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $cate = TeacherCategpryModel::get($id);
+        if (!$cate['pid']) {
+            $count = TeacherCategpryModel::where('pid', $id)->where('is_del', 0)->count();
+            if ($count) return Json::fail('暂无法删除,请删除下级分类');
+        }
+        if (TeacherModel::where('pid', $id)->where('is_del', 0)->count()) return Json::fail('暂无法删除,请先删除老师');
+        $res = parent::getDataModification('teacher_categpry', $id, 'is_del', 1);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+}

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

xqd
@@ -0,0 +1,243 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 app\admin\model\merchant\MerchantFlowingWater;
+use app\admin\model\merchant\MerchantBill;
+use app\admin\model\merchant\Merchant;
+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 Finance
+ */
+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,
+            'category' => $category,
+            'gold_name' => $category == "gold_num" ? 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));
+    }
+
+    /**讲师流水
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function merbill()
+    {
+        $list = Merchant::getMerWhere()->select();
+        $this->assign(['selectList' => $list]);
+        return $this->fetch();
+    }
+
+    /**
+     * 显示资金记录ajax列表
+     */
+    public function merbilllist()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['category', 'now_money'],
+            ['limit', 20],
+            ['page', 1],
+            ['mer_id', 0],
+            ['excel', 0],
+        ]);
+        return Json::successlayui(MerchantBill::getBillList($where));
+    }
+
+    /**
+     *保存资金监控的excel表格
+     */
+    public function save_mer_bell_export()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['mer_id', 0],
+            ['category', 'now_money'],
+        ]);
+        MerchantBill::SaveExport($where);
+    }
+
+    /**金币流水
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function mer_gold_bill()
+    {
+        $list = Merchant::getMerWhere()->select();
+        $this->assign(['selectList' => $list]);
+        return $this->fetch('mer_gold_bill');
+    }
+
+    /**订单分成
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function merOrderBill()
+    {
+        $list = Merchant::getMerWhere()->select();
+        $this->assign(['selectList' => $list]);
+        return $this->fetch('mer_order_bill');
+    }
+
+    /**
+     * 订单分成列表
+     */
+    public function merOrderBillList()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['nickname', ''],
+            ['limit', 20],
+            ['page', 1],
+            ['mer_id', 0],
+        ]);
+        return Json::successlayui(MerchantFlowingWater::getBillList($where));
+    }
+
+    /**
+     *保存资金监控的excel表格
+     */
+    public function save_mer_order_bell_export()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['nickname', ''],
+            ['mer_id', 0],
+        ]);
+        MerchantFlowingWater::SaveExport($where);
+    }
+}
+

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

xqd
@@ -0,0 +1,264 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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
+ */
+class UserExtract extends AuthController
+{
+    /**用户提现
+     * @return mixed
+     */
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 用户提现记录
+     */
+    public function get_user_extract()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['status', ''],
+            ['extract_type', ''],
+            ['nireid', ''],
+            ['page', 1],
+            ['limit', 20],
+        ], $this->request);
+        return JsonService::successlayui(UserExtractModel::get_user_extract_list($where));
+    }
+
+    /**讲师提现
+     * @return mixed
+     */
+    public function merIndex()
+    {
+        return $this->fetch();
+    }
+
+    public function get_mer_user_extract()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['mer_id', 1],
+            ['status', ''],
+            ['extract_type', ''],
+            ['nireid', ''],
+            ['page', 1],
+            ['limit', 20],
+        ], $this->request);
+        return JsonService::successlayui(UserExtractModel::get_mer_user_extract_list($where));
+    }
+
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $UserExtract = UserExtractModel::get($id);
+        if (!$UserExtract) return JsonService::fail('数据不存在!');
+        $f = array();
+        if ($UserExtract['extract_type'] == 'alipay') {
+            $f[] = Form::input('real_name', '姓名', $UserExtract['real_name']);
+            $f[] = Form::input('alipay_code', '支付宝账号', $UserExtract['alipay_code']);
+        } else if ($UserExtract['extract_type'] == 'bank') {
+            $f[] = Form::input('real_name', '姓名', $UserExtract['real_name']);
+            $f[] = Form::input('bank_code', '银行卡号', $UserExtract['bank_code']);
+            $f[] = Form::input('bank_address', '开户行', $UserExtract['bank_address']);
+        } else if ($UserExtract['extract_type'] == 'weixin') {
+            $f[] = Form::input('real_name', '姓名', $UserExtract['real_name']);
+            $f[] = Form::input('wechat', '微信号', $UserExtract['wechat']);
+        }
+        $f[] = Form::number('extract_price', '提现金额', $UserExtract['extract_price'])->precision(2);
+        $f[] = Form::input('mark', '备注', $UserExtract['mark'])->type('textarea');
+        $form = Form::make_post_form('编辑', $f, Url::build('update', array('id' => $id)), 2);
+        $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 if ($UserExtract['extract_type'] == 'weixin') {
+            $data = parent::postMore([
+                'real_name',
+                'mark',
+                'extract_price',
+                'wechat',
+            ], $request);
+            if (!$data['real_name']) return JsonService::fail('请输入姓名');
+            if ($data['extract_price'] <= -1) return JsonService::fail('请输入提现金额');
+            if (!$data['wechat']) return JsonService::fail('请输入wechat');
+        } else if ($UserExtract['extract_type'] == 'bank') {
+            $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('请输入开户行');
+        } else if ($UserExtract['extract_type'] == 'yue') {
+            $data = parent::postMore([
+                'extract_price',
+                'mark',
+            ], $request);
+            if ($data['extract_price'] <= -1) return JsonService::fail('请输入提现金额');
+        }
+        if (!UserExtractModel::edit($data, $id))
+            return JsonService::fail(UserExtractModel::getErrorInfo('修改失败'));
+        else
+            return JsonService::successful('修改成功!');
+    }
+
+    /**提现回退
+     * @param Request $request
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function fail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!UserExtractModel::be(['id' => $id, 'status' => 0])) return JsonService::fail('操作记录不存在或状态错误!');
+        $extract = UserExtractModel::get($id);
+        if (!$extract) return JsonService::fail('操作记录不存!');
+        if ($extract->status == 1) return JsonService::fail('已经提现,错误操作');
+        if ($extract->status == -1) return JsonService::fail('您的提现申请已被拒绝,请勿重复操作!');
+        UserExtractModel::beginTrans();
+        $res = UserExtractModel::changeFail($id, $fail_msg['message'], $extract);
+        if ($res) {
+            UserExtractModel::commitTrans();
+            return JsonService::successful('操作成功!');
+        } else {
+            UserExtractModel::rollbackTrans();
+            return JsonService::fail('操作失败!');
+        }
+    }
+
+    /**提现通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function succ($id)
+    {
+        if (!UserExtractModel::be(['id' => $id, 'status' => 0])) return JsonService::fail('操作记录不存在或状态错误!');
+        $extract = UserExtractModel::get($id);
+        if (!$extract) return JsonService::fail('操作记录不存!');
+        if ($extract->status == 1) return JsonService::fail('您已提现,请勿重复提现!');
+        if ($extract->status == -1) return JsonService::fail('您的提现申请已被拒绝!');
+        UserExtractModel::beginTrans();
+        $res = UserExtractModel::changeSuccess($id, $extract);
+        if ($res) {
+            UserExtractModel::commitTrans();
+            return JsonService::successful('操作成功!');
+        } else {
+            UserExtractModel::rollbackTrans();
+            return JsonService::fail('操作失败!');
+        }
+    }
+
+    /**提现回退
+     * @param Request $request
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function merFail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!UserExtractModel::be(['id' => $id, 'status' => 0])) return JsonService::fail('操作记录不存在或状态错误!');
+        $extract = UserExtractModel::get($id);
+        if (!$extract) return JsonService::fail('操作记录不存!');
+        if ($extract->status == 1) return JsonService::fail('已经提现,错误操作');
+        if ($extract->status == -1) return JsonService::fail('您的提现申请已被拒绝,请勿重复操作!');
+        UserExtractModel::beginTrans();
+        $res = UserExtractModel::changeMerFail($id, $fail_msg['message'], $extract);
+        if ($res) {
+            UserExtractModel::commitTrans();
+            return JsonService::successful('操作成功!');
+        } else {
+            UserExtractModel::rollbackTrans();
+            return JsonService::fail('操作失败!');
+        }
+    }
+
+    /**提现通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function merSucc($id)
+    {
+        if (!UserExtractModel::be(['id' => $id, 'status' => 0])) return JsonService::fail('操作记录不存在或状态错误!');
+        $extract = UserExtractModel::get($id);
+        if (!$extract) return JsonService::fail('操作记录不存!');
+        if ($extract->status == 1) return JsonService::fail('您已提现,请勿重复提现!');
+        if ($extract->status == -1) return JsonService::fail('您的提现申请已被拒绝!');
+        UserExtractModel::beginTrans();
+        $res = UserExtractModel::changeMerSuccess($id, $extract);
+        if ($res) {
+            UserExtractModel::commitTrans();
+            return JsonService::successful('操作成功!');
+        } else {
+            UserExtractModel::rollbackTrans();
+            return JsonService::fail('操作失败!');
+        }
+    }
+
+    /**提现备注
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function remarks($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        $extract = UserExtractModel::get($id);
+        if (!$extract) return JsonService::fail('操作记录不存!');
+        $res = UserExtractModel::where('id', $id)->update(['mark' => $fail_msg['message']]);
+        if ($res) {
+            return JsonService::successful('操作成功!');
+        } else {
+            return JsonService::fail('操作失败!');
+        }
+    }
+}

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

xqd
@@ -0,0 +1,173 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\admin\model\user\UserBill;
+use behavior\wap\StoreProductBehavior;
+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 service\SystemConfigService;
+use service\AlipayTradeWapService;
+use app\admin\model\user\User;
+
+/**
+ * 微信充值记录
+ * Class UserRecharge
+ */
+class UserRecharge extends AuthController
+{
+    /**
+     * 显示操作记录
+     */
+    public function index()
+    {
+        $this->assign([
+            'year' => getMonth('y'),
+            'real_name' => $this->request->get('real_name', ''),
+            'orderCount' => UserRechargeModel::orderCount()
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取头部订单金额等信息
+     * return json
+     *
+     */
+    public function getBadge()
+    {
+        $where = parent::postMore([
+            ['status', ''],
+            ['real_name', ''],
+            ['data', ''],
+        ]);
+        return Json::successful(UserRechargeModel::getBadge($where));
+    }
+
+    public function get_user_recharge_list()
+    {
+        $where = parent::getMore([
+            ['status', ''],
+            ['real_name', $this->request->param('real_name', '')],
+            ['data', ''],
+            ['order', ''],
+            ['page', 1],
+            ['limit', 20],
+            ['excel', 0]
+        ]);
+        return Json::successlayui(UserRechargeModel::systemPage($where));
+    }
+
+    /**订单删除
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误!');
+        $data['is_del'] = 1;
+        UserRechargeModel::edit($data, $id);
+        return Json::successful('删除成功!');
+    }
+
+    /**订单详情
+     * @param string $oid
+     * @return mixed|void
+     * @throws \think\exception\DbException
+     */
+    public function order_info($oid = '')
+    {
+        if (!$oid || !($orderInfo = UserRechargeModel::get($oid)))
+            return $this->failed('订单不存在!');
+        $userInfo = User::getAllUserinfo($orderInfo['uid']);
+        $this->assign(compact('orderInfo', 'userInfo'));
+        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)), 4);
+            $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;
+        $data['refund_status'] = 2;
+        if ($UserRecharge['recharge_type'] == 'weixin') {
+            try {
+                HookService::listen('user_recharge_refund', $UserRecharge['order_id'], $refund_data, true, PaymentBehavior::class);
+            } catch (\Exception $e) {
+                return Json::fail($e->getMessage());
+            }
+        } else if ($UserRecharge['recharge_type'] == 'yue') {
+            UserRechargeModel::beginTrans();
+            $res = User::bcInc($UserRecharge['uid'], 'now_money', $refund_price, 'uid');
+            UserRechargeModel::checkTrans($res);
+            if (!$res) return Json::fail('余额退款失败!');
+        } else if ($UserRecharge['recharge_type'] == 'zhifubao') {
+            $res = AlipayTradeWapService::init()->AliPayRefund($UserRecharge['order_id'], $UserRecharge['trade_no'], $refund_price, '虚拟币充值退款', 'refund');
+            if (empty($res) || $res != 10000) {
+                return Json::fail('支付宝退款失败!');
+            }
+        }
+        $data['refund_reason_time'] = time();
+        $resEdit = UserRechargeModel::edit($data, $id);
+        if ($resEdit) {
+            $goldNum = money_rate_num($refund_price, 'gold');
+            $gold_name = SystemConfigService::get('gold_name');//虚拟币名称
+            User::bcDec($UserRecharge['uid'], 'gold_num', $goldNum, 'uid');
+            UserBill::expend($gold_name . '充值退款', $UserRecharge['uid'], 'gold_num', 'return', $goldNum, $UserRecharge['id'], 0, '退' . floatval($goldNum) . $gold_name);
+            $recharge_type = $UserRecharge['recharge_type'] == 'yue' ? 'now_money' : $UserRecharge['recharge_type'];
+            UserBill::income('虚拟币充值退款', $UserRecharge['uid'], $recharge_type, 'user_recharge_refund', $refund_price, $UserRecharge['id'], 0, '订单退款' . floatval($refund_price) . '元');
+            return Json::successful('修改成功!');
+        } else {
+            return Json::successful('修改失败!');
+        }
+    }
+}

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

xqd
@@ -0,0 +1,1306 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\LiveAudit;
+use app\admin\model\live\LivePlayback;
+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\merchant\Merchant;
+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;
+use app\wap\model\routine\RoutineTemplate;
+use app\wap\model\wap\SmsTemplate;
+use app\index\controller\PushJob;
+
+/**直播
+ * Class AliyunLive
+ * @package app\admin\controller\live
+ */
+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(),
+            'mer_list' => Merchant::getMerchantList(),
+            '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);
+        $res = parent::getDataModification('studio', $id, $field, $value);
+        if ($res)
+            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::textarea('live_introduction', '直播间简介:', $liveInfo->getData('live_introduction'));
+        $f[] = Form::number('online_num', '虚拟在线人数:', $liveInfo->getData('online_num'))->min(0);
+        $f[] = Form::number('sort', '排序:', $liveInfo->getData('sort'))->min(0);
+        $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' => '否']
+        ]);
+        $f[] = Form::radio('is_chat', '直播间聊天:', $liveInfo->getData('is_chat'))->options([
+            ['value' => 1, 'label' => '开启'],
+            ['value' => 0, 'label' => '关闭']
+        ]);
+        $f[] = Form::radio('is_class_chat', '直播间课堂:', $liveInfo->getData('is_class_chat'))->options([
+            ['value' => 1, 'label' => '开启'],
+            ['value' => 0, 'label' => '关闭']
+        ]);
+        $f[] = Form::radio('is_live_recommend', '直播间推荐:', $liveInfo->getData('is_live_recommend'))->options([
+            ['value' => 1, 'label' => '开启'],
+            ['value' => 0, 'label' => '关闭']
+        ]);
+        $f[] = Form::radio('is_ranking', '直播间排行:', $liveInfo->getData('is_ranking'))->options([
+            ['value' => 1, 'label' => '开启'],
+            ['value' => 0, 'label' => '关闭']
+        ]);
+        $form = Form::make_post_form('修改直播间', $f, Url::build('save_live', array('id' => $id)), 2);
+        $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', ''],
+            ['live_introduction', ''],
+            ['online_num', 0],
+            ['sort', 0],
+            ['is_remind', 0],
+            ['remind_time', 0],
+            ['is_recording', 0],
+            ['is_playback', 0],
+            ['is_chat', 0],
+            ['is_class_chat', 0],
+            ['is_live_recommend', 0],
+            ['is_ranking', 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('缺少参数');
+        $res = parent::getDataModification('live_user', $id, $field, $value);
+        if ($res)
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败');
+    }
+
+    /**礼物
+     * @param string $field
+     * @param string $id
+     * @param string $value
+     */
+    public function set_live_gift_value($field = '', $id = '', $value = '')
+    {
+        if (!$field || !$id) return Json::fail('缺少参数');
+        $res = parent::getDataModification('live_gift', $id, $field, $value);
+        if ($res)
+            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],
+        ]);
+        return Json::successlayui(LiveStudio::getLiveList($where));
+    }
+
+
+    /**
+     * 直播专题列表
+     * @param int $subject_id
+     * @return mixed
+     */
+    public function special_live()
+    {
+        $special_type = $this->request->param("special_type");
+        if (!$special_type || !is_numeric($special_type)) return $this->failed('专题类型参数缺失');
+        $subjectlist = SpecialSubject::specialCategoryAll();
+        $this->assign([
+            'type' => 1,
+            'special_type' => $special_type,
+            'special_title' => SPECIAL_TYPE[$special_type],
+            'subject_list' => $subjectlist,
+            'mer_list' => Merchant::getMerchantList(),
+            'is_live' => 1,
+        ]);
+        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('直播间已删除无法提醒');
+        $liveInfo = $liveInfo->toArray();
+        if ($liveInfo['is_reminded'] == 0) {
+            LiveStudio::where('id', $liveInfo['id'])->update(['is_reminded' => 1]);
+        }
+        if ($specialInfo['pay_type'] == 1 && $specialInfo['member_pay_type'] == 1) {
+            $orderList = StoreOrderModel::where(['cart_id' => $id, 'type' => 0])->column("uid");
+        } elseif ($specialInfo['pay_type'] == 1 && $specialInfo['member_pay_type'] == 0) {
+            $order = StoreOrderModel::where(['cart_id' => $id, 'type' => 0])->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('暂无合适用户,无需提醒');
+        }
+        $site_url = SystemConfigService::get('site_url');
+        $orderList = array_unique($orderList);
+        $data['id'] = $id;
+        $data['site_url'] = $site_url;
+        $data['live_title'] = $specialInfo['title'];
+        $data['start_play_time'] = $liveInfo['start_play_time'];
+        foreach ($orderList as $k => $v) {
+            $data['uid'] = $v;
+            PushJob::actionWithDoPinkJob($data, 'doLiveStudioJob');
+        }
+        return Json::successful("发送成功");
+    }
+
+    /**直播审核
+     * @return mixed
+     */
+    public function live_audit()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 审核列表
+     */
+    public function get_live_audit_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['store_name', ''],
+        ]);
+        return Json::successlayui(LiveAudit::liveExamineList($where));
+    }
+
+    /**不通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function fail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!LiveAudit::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $audit = LiveAudit::get($id);
+        if (!$audit) return Json::fail('操作记录不存!');
+        if ($audit->status != 0) return Json::fail('您已审核,请勿重复操作');
+        LiveAudit::beginTrans();
+        $res = LiveAudit::changeFail($id, $audit['mer_id'], $fail_msg['message']);
+        if ($res) {
+            LiveAudit::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            LiveAudit::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    /**通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function succ($id)
+    {
+        if (!LiveAudit::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $audit = LiveAudit::get($id);
+        if (!$audit) return Json::fail('操作记录不存!');
+        if ($audit->status != 0) return Json::fail('您已审核,请勿重复操作');
+        LiveAudit::beginTrans();
+        $res = LiveAudit::changeSuccess($id, $audit['mer_id']);
+        if ($res) {
+            LiveAudit::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            LiveAudit::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    /**
+     * 获取专题直播列表
+     */
+    public function special_list()
+    {
+        $where = parent::getMore([
+            ['subject_id', 0],
+            ['mer_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'];
+        }
+        $special_list = SpecialModel::getSpecialList($where);
+        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 user($live_id = 0)
+    {
+        $this->assign('live_id', $live_id);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取用户列表
+     */
+    public function 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(User::add_get_user_list($where));
+    }
+
+    /**
+     * 添加嘉宾
+     * @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 = parent::getDataModification('play_back', $id, '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 = parent::getDataModification('play_back', $id, '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 = parent::getDataModification('play_back', $id, $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', SpecialSubject::specialCategoryAll(1));
+            $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 = 0, $special_id = 0)
+    {
+        $this->assign(['live_id' => $live_id, 'special_id' => $special_id]);
+        return $this->fetch();
+    }
+
+    /**添加直播的专题课程推荐
+     * @param int $id
+     * @param string $ids
+     */
+    public function add_live_special($special_id = 0, $ids = '', $type = 0)
+    {
+        if (!$special_id || !$ids) return Json::fail('参数错误');
+        $res = LiveGoods::saveLiveGoods($ids, $special_id, $type);
+        if ($res)
+            return Json::successful('添加成功');
+        else
+            return Json::fail('添加失败');
+    }
+
+    /**直播推荐列表数据
+     * @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 = 0, $special_id = 0)
+    {
+        $this->assign(['live_id' => $live_id, 'special_id' => $special_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($live_id = 0)
+    {
+        $gold_info = SystemConfigService::more(['gold_name', 'gold_image']);
+        $where['l.is_del'] = 0;
+        $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);
+        $this->assign("live_id", $live_id);
+        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 : '')->min(0),
+            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)->min(0)->max(99999),
+            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 DESC,id DESC')->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));
+    }
+
+}

+ 197 - 0
application/admin/controller/merchant/Merchant.php

xqd
@@ -0,0 +1,197 @@
+<?php
+
+namespace app\admin\controller\merchant;
+
+use app\admin\controller\AuthController;
+use app\admin\model\user\User;
+use app\admin\model\merchant\UserEnter;
+use app\merchant\model\merchant\MerchantMenus;
+use service\HookService;
+use service\JsonService;
+use service\SystemConfigService;
+use service\UploadService;
+use think\Request;
+use think\Url;
+use app\admin\model\merchant\Merchant as MerchantModel;
+use app\merchant\model\merchant\MerchantAdmin as MerchantAdminModel;
+use app\admin\model\special\Lecturer;
+use app\admin\model\special\Special;
+use app\admin\model\download\DataDownload as DownloadModel;
+use app\admin\model\store\StoreProduct as ProductModel;
+use app\admin\model\ump\EventRegistration as EventRegistrationModel;
+
+/**
+ * Class Merchant
+ * @package app\admin\controller\merchant
+ */
+class Merchant extends AuthController
+{
+    /**讲师后台列表
+     * @return mixed
+     */
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 讲师列表获取
+     * @return
+     * */
+    public function lecturer_merchant_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['title', ''],
+        ]);
+        return JsonService::successlayui(MerchantModel::getLecturerMerchantList($where));
+    }
+
+    /**
+     * 删除讲师后台
+     * @param int $id 修改的主键
+     * @return json
+     * */
+    public function delete($id = 0)
+    {
+        if (!$id) return JsonService::fail('缺少参数');
+        $merchant = MerchantModel::get($id);
+        if (!$merchant) return JsonService::fail('讲师后台不存在');
+        if (MerchantModel::delMerchant($id)) {
+            Lecturer::where('mer_id', $id)->update(['is_del' => 1]);
+            User::where('uid', $merchant['uid'])->update(['business' => 0]);
+            return JsonService::successful('删除成功');
+        } else
+            return JsonService::fail(UserEnterModel::getErrorInfo('删除失败'));
+    }
+
+    /**编辑讲师信息
+     * @param $id
+     * @return mixed
+     */
+    public function edit($id)
+    {
+        $role = MerchantModel::get($id);
+        $this->assign(['title' => '编辑讲师后台', 'roles' => $role->toJson(), 'menus' => json(MerchantMenus::ruleList())->getContent(), 'action' => Url::build('update', array('id' => $id))]);
+        return $this->fetch('edit');
+    }
+
+    /**
+     * @param Request $request
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            'mer_name',
+            'real_name',
+            'pwd',
+            'mer_phone',
+            'mer_address',
+            'mer_special_divide',
+            'mer_store_divide',
+            'mer_event_divide',
+            'mer_data_divide',
+            'mer_test_divide',
+            'gold_divide',
+            'mark',
+            'is_source',
+            'is_audit',
+            'status',
+            ['checked_menus', [], '', 'rules'],
+            'uid'
+        ], $request);
+        if (!$id) return JsonService::fail('数据错误');
+        if (!is_array($data['rules']) || !count($data['rules'])) return JsonService::fail('请选择最少一个权限');
+        foreach ($data['rules'] as &$v) {
+            $pid = MerchantMenus::where('id', $v)->value('pid');
+            if (!in_array($pid, $data['rules'])) $data['rules'][] = $pid;
+        }
+        $status = $data['status'];
+        $data['rules'] = implode(',', $data['rules']);
+        $merchant = MerchantModel::get($id);
+        if (!$merchant) return JsonService::fail('讲师后台不存在');
+        if (!$data['mer_name']) return JsonService::fail('请输入讲师后台名称');
+        MerchantModel::beginTrans();
+        $res1 = MerchantModel::edit($data, $id);
+        $update = array();
+        $update['rules'] = $data['rules'];
+        $rules = MerchantAdminModel::where('level', 0)->where('mer_id', $id)->value('rules');
+        if ($update['rules'] == $rules) $res2 = true;
+        else $res2 = false !== MerchantAdminModel::where('level', 0)->where('mer_id', $id)->update($update);
+        $res = false;
+        if ($res1 && $res2) $res = true;
+        MerchantModel::checkTrans($res);
+        if ($res) {
+            if (!$status) {
+                Special::where(['is_del' => 0, 'mer_id' => $id])->update(['is_show' => 0]);
+                DownloadModel::where(['is_del' => 0, 'mer_id' => $id])->update(['is_show' => 0]);
+                ProductModel::where(['is_del' => 0, 'mer_id' => $id])->update(['is_show' => 0]);
+                EventRegistrationModel::where(['is_del' => 0, 'mer_id' => $id])->update(['is_show' => 0]);
+                Lecturer::where(['id' => $merchant['lecturer_id']])->update(['is_show' => 0]);
+                $dat['is_show'] = 0;
+                Lecturer::edit($dat, $merchant['lecturer_id'], 'id');
+            } else {
+                $dat['is_show'] = 1;
+                Lecturer::edit($dat, $merchant['lecturer_id'], 'id');
+            }
+            return JsonService::successful('修改成功!');
+        } else
+            return JsonService::fail('修改失败!');
+    }
+
+    /**
+     * 修改状态
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function modify($id, $status)
+    {
+        if (!$id) return JsonService::fail('数据错误');
+        $merchantInfo = MerchantModel::where('id', $id)->where('is_del', 0)->find();
+        if (!$merchantInfo) return JsonService::fail('数据错误');
+        $data['status'] = $status;
+        if (!MerchantModel::edit($data, $id)) {
+            return JsonService::fail(MerchantModel::getErrorInfo('修改失败,请稍候再试!'));
+        } else {
+            $dat['is_show'] = $status;
+            Lecturer::edit($dat, $merchantInfo['lecturer_id'], 'id');
+            return JsonService::successful('修改成功!');
+        }
+    }
+
+    /**登录
+     * @param $id
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function login($id)
+    {
+        $merchantInfo = MerchantModel::where('id', $id)->where('is_del', 0)->find();
+        if (!$merchantInfo) return $this->failed('登陆的讲师后台不存在!');
+        $adminInfo = MerchantAdminModel::where('level', 0)->where('mer_id', $merchantInfo->id)->find();
+        if (!$adminInfo) return $this->failed('登陆的讲师后台不存在!');
+        MerchantAdminModel::setLoginInfo($adminInfo->toArray());
+        MerchantAdminModel::setMerchantInfo($merchantInfo->toArray());
+        return $this->redirect(Url::build('/merchant/index/index'));
+    }
+
+    /**重置密码
+     * @param $id
+     */
+    public function reset_pwd($id)
+    {
+        if (!$id) return JsonService::fail('参数错误失败!');
+        $pwd = md5(1234567);
+        $adminPwd = MerchantAdminModel::where('mer_id', $id)->where('level', 0)->value('pwd');
+        if ($pwd == $adminPwd) return JsonService::fail('您的密码无需重置!');
+        if (MerchantAdminModel::where('mer_id', $id)->where('level', 0)->update(['pwd' => md5(1234567)]))
+            return JsonService::successful('重置成功!');
+        else
+            return JsonService::fail('重置失败!');
+    }
+}

+ 183 - 0
application/admin/controller/merchant/MerchantMenus.php

xqd
@@ -0,0 +1,183 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\merchant;
+
+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\merchant\model\merchant\MerchantMenus as MenusModel;
+use app\admin\controller\AuthController;
+
+/**
+ * 菜单管理控制器
+ * Class MerchantMenus
+ * @package app\admin\controller\merchant
+ */
+class MerchantMenus 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', ''],
+            ['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' => 'merchant']]),
+            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)->min(0),
+            Form::radio('is_show', '是否菜单', 1)->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '显示(菜单只显示三级)']]),
+        ]);
+        $form->setMethod('post')->setTitle('添加权限')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},2000);');
+        $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' => 'merchant']]),
+            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'])->min(0),
+            Form::radio('is_show', '是否菜单', $menu['is_show'])->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '显示(菜单只显示三级)']])
+        ]);
+        $form->setMethod('post')->setTitle('编辑权限')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},2000);');
+        $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('删除成功!');
+    }
+
+}

+ 247 - 0
application/admin/controller/merchant/UserEnter.php

xqd
@@ -0,0 +1,247 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\merchant;
+
+use app\admin\controller\AuthController;
+use app\admin\model\special\Lecturer;
+use app\admin\model\special\Lecturer as LecturerModel;
+use app\admin\model\merchant\UserEnter as UserEnterModel;
+use app\admin\model\merchant\Merchant as MerchantModel;
+use app\admin\model\merchant\MerchantAdmin as MerchantAdminModel;
+use app\merchant\model\merchant\MerchantMenus;
+use app\admin\model\user\User;
+use service\JsonService;
+use service\FormBuilder as Form;
+use think\Url;
+
+/**
+ * 讲师申请控制器
+ */
+class UserEnter extends AuthController
+{
+    /**
+     * 讲师申请列表展示
+     * @return
+     * */
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 讲师申请列表获取
+     * @return
+     * */
+    public function lecturer_enter_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['title', ''],
+        ]);
+        return JsonService::successlayui(UserEnterModel::getLecturerList($where));
+    }
+
+    /**
+     * 删除讲师申请
+     * @param int $id 修改的主键
+     * @return json
+     * */
+    public function delete($id = 0)
+    {
+        if (!$id) return JsonService::fail('缺少参数');
+        if (UserEnterModel::delLecturer($id))
+            return JsonService::successful('删除成功');
+        else
+            return JsonService::fail(UserEnterModel::getErrorInfo('删除失败'));
+    }
+
+    /**查看申请
+     * @param int $id
+     * @return mixed
+     */
+    public function see($id = 0)
+    {
+        $this->assign(['id' => $id]);
+        return $this->fetch();
+    }
+
+    /**申请数据
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function getUserEnter($id)
+    {
+        $data = UserEnterModel::get($id);
+        $data['address'] = $data['province'] . $data['city'] . $data['district'] . $data['address'];
+        $data['label'] = json_decode($data['label']);
+        if ($data['charter']) {
+            $data['charter'] = json_decode($data['charter']);
+        } else {
+            $data['charter'] = [];
+        }
+        return JsonService::successful($data);
+    }
+
+    /**不通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function fail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!UserEnterModel::be(['id' => $id, 'status' => 0])) return JsonService::fail('操作记录不存在或状态错误!');
+        $enter = UserEnterModel::get($id);
+        if (!$enter) return JsonService::fail('操作记录不存!');
+        if ($enter->status != 0) return Json::fail('您已审核,请勿重复操作');
+        UserEnterModel::beginTrans();
+        $res = UserEnterModel::changeFail($id, $enter['uid'], $fail_msg['message'], $enter);
+        if ($res) {
+            UserEnterModel::commitTrans();
+            return JsonService::successful('操作成功!');
+        } else {
+            UserEnterModel::rollbackTrans();
+            return JsonService::fail('操作失败!');
+        }
+    }
+
+    /**通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function succ($id)
+    {
+        if (!UserEnterModel::be(['id' => $id, 'status' => 0])) return JsonService::fail('操作记录不存在或状态错误!');
+        $enter = UserEnterModel::get($id);
+        if (!$enter) return JsonService::fail('操作记录不存!');
+        if ($enter->status != 0) return Json::fail('您已审核,请勿重复操作');
+        UserEnterModel::beginTrans();
+        $res = UserEnterModel::changeSuccess($id, $enter['uid'], $enter);
+        if ($res) {
+            UserEnterModel::commitTrans();
+            return JsonService::successful('操作成功!');
+        } else {
+            UserEnterModel::rollbackTrans();
+            return JsonService::fail('操作失败!');
+        }
+    }
+
+    /**生成讲师后台
+     * @return mixed
+     */
+    public function create($id)
+    {
+        $enter = UserEnterModel::get($id);
+        $this->assign([
+            'title' => '添加讲师后台',
+            'enter' => json_encode($enter),
+            'action' => Url::build('save'),
+            'menus' => json(MerchantMenus::ruleList())->getContent()
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加讲师商户
+     */
+    public function save()
+    {
+        $data = parent::postMore([
+            'account',
+            ['id', 0],
+            ['uid', 0],
+            'conf_pwd',
+            'pwd',
+            'mer_name',
+            'real_name',
+            'mer_phone',
+            'mer_special_divide',
+            'mer_store_divide',
+            'mer_event_divide',
+            'mer_data_divide',
+            'mer_test_divide',
+            'gold_divide',
+            'mark',
+            'mer_address',
+            ['checked_menus', [], '', 'rules'],
+            ['is_source', 0],
+            ['is_audit', 0],
+            ['status', 0]
+        ]);
+        if (!is_array($data['rules']) || !count($data['rules'])) return JsonService::fail('请选择最少一个权限');
+        foreach ($data['rules'] as &$v) {
+            $pid = MerchantMenus::where('id', $v)->value('pid');
+            if (!in_array($pid, $data['rules'])) $data['rules'][] = $pid;
+        }
+        $data['rules'] = implode(',', $data['rules']);
+        if (!$data['account']) return JsonService::fail('请输入讲师后台账号');
+        if (MerchantAdminModel::where('account', trim($data['account']))->where('is_del', 0)->count()) return JsonService::fail('商户账号已存在,请使用别的商户账号注册');
+        if (!$data['pwd']) return JsonService::fail('请输入讲师后台登陆密码');
+        if ($data['pwd'] != $data['conf_pwd']) return JsonService::fail('两次输入密码不想同');
+        if (!$data['mer_name']) return JsonService::fail('请输入讲师后台名称');
+        if (!$data['uid']) return JsonService::fail('请输入绑定的用户ID');
+        $user = User::where('uid', $data['uid'])->find();
+        if (!$user) {
+            return JsonService::fail('绑定的用户不存在');
+        } else {
+            if ($user['business'] == 1) {
+                return JsonService::fail('该用户已是讲师');
+            }
+        }
+        $data['pwd'] = trim(md5($data['pwd']));
+        $data['reg_time'] = time();
+        $data['add_time'] = time();
+        $data['reg_admin_id'] = $this->adminId;
+        $admin = array();
+        $admin['account'] = trim($data['account']);
+        $admin['pwd'] = $data['pwd'];
+        $enter = UserEnterModel::get($data['id']);
+        $data['mer_avatar'] = $enter['merchant_head'];
+        $data['estate'] = 1;
+        UserEnterModel::where('id', $data['id'])->update(['status' => 2]);
+        unset($data['id']);
+        unset($data['conf_pwd']);
+        unset($data['account']);
+        unset($data['pwd']);
+        MerchantModel::beginTrans();
+        $res = MerchantModel::set($data);
+        $res1 = false;
+        if ($res) {
+            $admin['uid'] = $data['uid'];
+            $admin['mer_id'] = $res->id;
+            $admin['real_name'] = $data['mer_name'];
+            $admin['rules'] = $data['rules'];
+            $admin['phone'] = $data['mer_phone'];
+            $admin['add_time'] = time();
+            $admin['status'] = 1;
+            $admin['level'] = 0;
+            $res1 = MerchantAdminModel::set($admin);
+        }
+        $res2 = false;
+        if ($res1 && $res) {
+            $res2 = Lecturer::addLecturer($enter, $res->id);
+        }
+        $bool = false;
+        if ($res1 && $res && $res2) $bool = true;
+        MerchantModel::checkTrans($bool);
+        if ($bool) {
+            MerchantModel::where('id', $res->id)->update(['lecturer_id' => $res2->id]);
+            User::where('uid', $data['uid'])->update(['business' => 1]);
+            return JsonService::successful('添加讲师后台成功!');
+        } else {
+            return JsonService::successful('添加讲师后台失败!');
+        }
+
+    }
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
application/admin/controller/order/DataDownloadOrder.php


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
application/admin/controller/order/StoreOrder.php


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
application/admin/controller/order/TestPaperOrder.php


+ 291 - 0
application/admin/controller/questions/Certificate.php

xqd
@@ -0,0 +1,291 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\questions;
+
+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\questions\Certificate as CertificateModel;
+use app\admin\model\questions\TestPaper as TestPaperModel;
+use app\admin\model\questions\CertificateRecord;
+use app\admin\model\merchant\Merchant;
+
+/**
+ * 证书
+ * Class Certificate
+ */
+class Certificate extends AuthController
+{
+    /**
+     * 证书列表
+     */
+    public function index()
+    {
+        $mer_list = Merchant::getMerchantList();
+        $this->assign([
+            'mer_list' => $mer_list
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取证书列表
+     */
+    public function getCertificateList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['obtain', 0],
+            ['title', ''],
+            ['status', 1],
+            ['mer_id', 0],
+        ]);
+        return Json::successlayui(CertificateModel::getCertificateList($where));
+    }
+
+    /**证书审核
+     * @return mixed
+     */
+    public function examine()
+    {
+        $mer_list = Merchant::getMerchantList();
+        $this->assign([
+            'mer_list' => $mer_list
+        ]);
+        return $this->fetch();
+    }
+
+    /**获得审核证书
+     * @throws \think\Exception
+     */
+    public function get_certificate_examine_list()
+    {
+        $where = parent::getMore([
+            ['status', ''],
+            ['page', 1],
+            ['limit', 20],
+            ['obtain', 0],
+            ['mer_id', 0],
+            ['title', '']
+        ]);
+        return Json::successlayui(CertificateModel::get_certificate_examine_list($where));
+    }
+
+    public function examineDetails($id)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $certificate = CertificateModel::get($id);
+        if (!$certificate) return Json::fail('证书不存在');
+        $this->assign(['certificate' => json_encode($certificate)]);
+        return $this->fetch('material');
+    }
+
+    /**不通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function fail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!CertificateModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $certificate = CertificateModel::get($id);
+        if (!$certificate) return Json::fail('操作记录不存!');
+        if ($certificate->status != 0) return Json::fail('您已审核,请勿重复操作');
+        CertificateModel::beginTrans();
+        $res = CertificateModel::changeFail($id, $certificate['mer_id'], $fail_msg['message']);
+        if ($res) {
+            CertificateModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            CertificateModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    /**通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function succ($id)
+    {
+        if (!CertificateModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $certificate = CertificateModel::get($id);
+        if (!$certificate) return Json::fail('操作记录不存!');
+        if ($certificate->status != 0) return Json::fail('您已审核,请勿重复操作');
+        CertificateModel::beginTrans();
+        $res = CertificateModel::changeSuccess($id, $certificate['mer_id']);
+        if ($res) {
+            CertificateModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            CertificateModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '', $test = 0)
+    {
+        if (!$field || !$id || $value == '') Json::fail('缺少参数3');
+        if ($field == 'sort' && bcsub($value, 0, 0) < 0) return Json::fail('排序不能为负数');
+        $res = parent::getDataModification('certificate', $id, $field, $value);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**添加/编辑
+     * @param int $id
+     * @return mixed
+     */
+    public function add($id = 0)
+    {
+        $certificate = $id > 0 ? CertificateModel::get($id) : [];
+        $this->assign(['id' => $id, 'certificate' => json_encode($certificate)]);
+        return $this->fetch('create');
+    }
+
+    /**添加/编辑证书
+     * @param int $id
+     */
+    public function save_add($id = 0)
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['background', ''],
+            ['qr_code', ''],
+            ['obtain', 0],
+            ['explain', ''],
+            ['sort', 0]
+        ]);
+        if ($data['title'] == '') return Json::fail('请输入证书标题');
+        if ($data['background'] == '') return Json::fail('请上传证书背景');
+        if (mb_strlen($data['explain'], "utf-8") > 30 || mb_strlen($data['explain'], "utf-8") <= 0) return Json::fail('证书说明不能大于30个字或者为空');
+        if ($id) {
+            $res = CertificateModel::edit($data, $id);
+        } else {
+            $data['add_time'] = time();
+            if (CertificateModel::be(['title' => $data['title'], 'is_del' => 0])) {
+                return Json::fail('证书标题已存在!');
+            }
+            $res = CertificateModel::set($data);
+        }
+        if ($res) {
+            return Json::successful('添加/编辑成功');
+        } else {
+            return Json::fail('添加/编辑失败');
+        }
+    }
+
+    /**删除证书
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $test = CertificateModel::get($id);
+        if (!$test) return Json::fail('要删除的证书不存在');
+        $res = parent::getDataModification('certificate', $id, 'is_del', 1);
+        if ($res) {
+            return Json::successful('删除成功');
+        } else {
+            return Json::fail('删除失败');
+        }
+    }
+
+    /**
+     *试卷列表
+     */
+    public function getTestPaperList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', ''],
+            ['type', 2],
+            ['title', '']
+        ]);
+        return Json::successlayui(TestPaperModel::testPaperExercisesList($where));
+    }
+
+    /**证书获取记录
+     * @return mixed
+     */
+    public function record()
+    {
+        $this->assign(['certificate' => CertificateModel::certificateList()]);
+        return $this->fetch();
+    }
+
+    /**
+     * 证书获取记录列表
+     */
+    public function getCertificateRecord()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['cid', 0],
+            ['title', ''],
+            ['excel', 0]
+        ]);
+        return Json::successlayui(CertificateRecord::getCertificateRecordList($where));
+    }
+
+    /**证书获取记录删除
+     * @param int $id
+     * @throws \think\exception\DbException
+     */
+    public function deleteRecord($id = 0)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $test = CertificateRecord::get($id);
+        if (!$test) return Json::fail('要删除的记录不存在');
+        $res = parent::getDataModification('record', $id, 'is_del', 1);
+        if ($res) {
+            return Json::successful('删除成功');
+        } else {
+            return Json::fail('删除失败');
+        }
+    }
+
+    /**证书获取记录撤销
+     * @param int $id
+     * @throws \think\exception\DbException
+     */
+    public function revokeRecord($id = 0)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $test = CertificateRecord::get($id);
+        if (!$test) return Json::fail('要撤销的记录不存在');
+        $res = parent::getDataModification('record', $id, 'status', 0);
+        if ($res) {
+            return Json::successful('撤销成功');
+        } else {
+            return Json::fail('撤销失败');
+        }
+    }
+}

+ 284 - 0
application/admin/controller/questions/Questions.php

xqd
@@ -0,0 +1,284 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\questions;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use think\Url;
+use app\admin\model\questions\Questions as QuestionsModel;
+use app\admin\model\questions\Relation;
+use app\admin\model\questions\QuestionsCategpry;
+use app\admin\model\questions\TestPaperQuestions;
+use app\admin\model\questions\ExaminationTestRecord;
+use app\admin\model\merchant\Merchant;
+
+/**
+ * 试题
+ * Class Questions
+ */
+class Questions extends AuthController
+{
+    /**
+     * 题库列表
+     */
+    public function index()
+    {
+        $this->assign(['category' => QuestionsCategpry::taskCategoryAll(2)]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取题库列表
+     */
+    public function getQuestionsList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['type', ''],
+            ['pid', 0],
+            ['title', ''],
+            ['excel', 0]
+        ]);
+        return Json::successlayui(QuestionsModel::questionsList($where));
+    }
+
+    /**
+     * 试题导入
+     */
+    public function importTestQuestions()
+    {
+        $where = parent::postMore([
+            ['link', '']
+        ]);
+        $data = QuestionsModel::GetExcelData($where['link'], 4);
+        if (count($data) <= 0) return Json::fail('导入文件内容为空');
+        $res = QuestionsModel::importQuestions($data);
+        if ($res)
+            return Json::successful('导入成功');
+        else
+            return Json::fail('导入失败');
+    }
+
+    /**
+     * 下载试题导入文件
+     */
+    public function downloadExcel()
+    {
+        QuestionsModel::getExcel();
+    }
+
+    /**
+     * @return mixed
+     */
+    public function imports()
+    {
+        return $this->fetch('import');
+    }
+
+    /**
+     * 上传文件
+     * @return string
+     */
+    public function file_import_upload()
+    {
+        $res = Upload::file('file', 'config/file');
+        if (!$res->status) return Json::fail($res->error);
+        return Json::successful('上传成功!', ['filePath' => $res->filePath]);
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        if (!$field || !$id || $value == '') Json::fail('缺少参数3');
+        if ($field == 'sort' && bcsub($value, 0, 0) < 0) return Json::fail('排序不能为负数');
+        $res = parent::getDataModification('questions', $id, $field, $value);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**关联试题知识点
+     * @param int $id
+     * @return mixed
+     */
+    public function knowledge($id = 0)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $this->assign(['id' => $id]);
+        return $this->fetch();
+    }
+
+    /**获取试题关联的专题
+     * @param int $id
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function knowledge_points($id = 0)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $data = Relation::getQuestionsRelationSpecial($id, 3);
+        foreach ($data['data'] as $k => &$v) {
+            if ($v['type'] == 6) $v['type'] = $v['light_type'];
+            $v['types'] = parent::specialTaskType($v['type']);
+        }
+        return Json::successlayui($data);
+    }
+
+    /**试题关联专题
+     * @param int $id
+     */
+    public function add_knowledge_points($id, $special_ids)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $res = Relation::setRelations($id, $special_ids, 3);
+        if ($res)
+            return Json::successful('关联成功');
+        else
+            return Json::fail('关联失败');
+    }
+
+    /**试题知识点排序
+     * @param int $id
+     * @param int $special_id
+     * @param $value
+     */
+    public function up_knowledge_points_sort($id, $special_id, $value)
+    {
+        if (!$id || !$special_id) Json::fail('缺少参数');
+        $res = Relation::updateRelationSort($id, $special_id, 3, $value);
+        if ($res)
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败');
+    }
+
+    /**删除关联专题
+     * @param int $id
+     * @param int $special_id
+     * @throws \think\exception\DbException
+     */
+    public function delete_knowledge_points($id = 0, $special_id = 0)
+    {
+        if (!$id || !$special_id) Json::fail('缺少参数');
+        $res = Relation::delRelation($id, $special_id, 3);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+    /**关联专题
+     * @param int $id
+     */
+    public function relation($id = 0)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['id' => $id,'mer_list' => $mer_list]);
+        return $this->fetch('relation');
+    }
+
+    /**添加/编辑
+     * @param int $id
+     * @return mixed
+     */
+    public function add($id = 0)
+    {
+        $questions = $id > 0 ? QuestionsModel::get($id) : [];
+        $this->assign(['id' => $id, 'questions' => json_encode($questions)]);
+        return $this->fetch('subject');
+    }
+
+    /**
+     * 获取试题分类
+     */
+    public function get_subject_list()
+    {
+        $category = QuestionsCategpry::taskCategoryAll(2);
+        return Json::successful($category);
+    }
+
+    /**添加/编辑试题
+     * @param int $id
+     */
+    public function save_add($id = 0)
+    {
+        $data = parent::postMore([
+            ['question_type', 1],
+            ['is_img', 0],
+            ['pid', 0],
+            ['stem', ''],
+            ['image', ''],
+            ['option', ''],
+            ['answer', ''],
+            ['difficulty', ''],
+            ['analysis', ''],
+            ['sort', 0]
+        ]);
+        if ($data['pid'] <= 0) return Json::fail('请选择试题分类');
+        if (!$data['stem']) return Json::fail('请输入试题题干');
+        if (!$data['option']) return Json::fail('请输入试题选项');
+        if (!$data['answer']) return Json::fail('请设置正确答案');
+        if ($id) {
+            $res = QuestionsModel::edit($data, $id);
+        } else {
+            $data['add_time'] = time();
+            if (QuestionsModel::be(['stem' => $data['stem'], 'is_del' => 0, 'mer_id' => 0])) {
+                return Json::fail('试题题干已存在!');
+            }
+            $res = QuestionsModel::set($data);
+        }
+        if ($res) {
+            return Json::successful('添加/编辑成功');
+        } else {
+            return Json::fail('添加/编辑失败');
+        }
+    }
+
+    /**删除试题
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $questions = QuestionsModel::get($id);
+        if (!$questions) return Json::fail('要删除的试题不存在');
+        if (TestPaperQuestions::be(['questions_id' => $id])) return Json::fail('试题在试卷中使用,不能删除;请先在试卷中删除');
+        $res = parent::getDataModification('questions', $id, 'is_del', 1);
+        if ($res) {
+            return Json::successful('删除成功');
+        } else {
+            return Json::fail('删除失败');
+        }
+    }
+
+    /**获取答题情况
+     * @param int $id
+     */
+    public function getQuestionsAnswer($id = 0)
+    {
+        $data = ExaminationTestRecord::testRecord($id);
+        return Json::successful($data);
+    }
+}

+ 141 - 0
application/admin/controller/questions/QuestionsCategpry.php

xqd
@@ -0,0 +1,141 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\questions;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use app\admin\model\questions\QuestionsCategpry as QuestionsCategpryModel;
+use app\admin\model\questions\Questions as QuestionsModel;
+
+/**
+ * 试题分类
+ * Class QuestionsCategpry
+ */
+class QuestionsCategpry extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    public function get_category_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', 0],
+            ['title', '']
+        ]);
+        return Json::successful(QuestionsCategpryModel::getAllList($where));
+    }
+
+    /**
+     * 创建分类
+     * @param int $id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0)
+    {
+        $cate = $id > 0 ? QuestionsCategpryModel::get($id) : [];
+        $this->assign(['cate' => json_encode($cate), 'id' => $id]);
+        return $this->fetch();
+    }
+
+    public function get_cate_list()
+    {
+        $category = QuestionsCategpryModel::taskCategoryAll(2);
+        return Json::successful($category);
+    }
+
+    public function add_cate_list()
+    {
+        $category = QuestionsCategpryModel::where(['pid' => 0, 'is_del' => 0, 'mer_id' => 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('缺少参数');
+        $res = parent::getDataModification('categpry', $id, $field, $value);
+        if ($res)
+            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) {
+            $cate = QuestionsCategpryModel::get($id);
+            if (!$cate['pid'] && $post['pid'] && QuestionsCategpryModel::be(['pid' => $id, 'is_del' => 0, 'mer_id' => 0])) return Json::fail('无法移动有下级的分类');
+            if (QuestionsCategpryModel::where(['title' => $post['title'], 'is_del' => 0, 'mer_id' => 0])->where('id', '<>', $id)->count() >= 1) return Json::fail('分类名称已存在');
+            $res = QuestionsCategpryModel::edit($post, $id);
+            if ($res)
+                return Json::successful('修改成功');
+            else
+                return Json::fail('修改失败');
+        } else {
+            $post['add_time'] = time();
+            $res = QuestionsCategpryModel::set($post);
+            if ($res)
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 删除
+     *
+     * @return json
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $cate = QuestionsCategpryModel::get($id);
+        if (!$cate['pid']) {
+            $count = QuestionsCategpryModel::where('pid', $id)->where(['is_del' => 0, 'mer_id' => 0])->count();
+            if ($count) return Json::fail('暂无法删除,请删除下级分类');
+        }
+        if (QuestionsModel::where('pid', $id)->where(['is_del' => 0, 'mer_id' => 0])->count()) return Json::fail('暂无法删除,请先删除题目');
+        $res = parent::getDataModification('categpry', $id, 'is_del', 1);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+}

+ 762 - 0
application/admin/controller/questions/TestPaper.php

xqd
@@ -0,0 +1,762 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\questions;
+
+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\questions\TestPaper as TestPaperModel;
+use app\admin\model\questions\TestPaperCategory;
+use app\admin\model\questions\QuestionsCategpry;
+use app\admin\model\questions\Questions;
+use app\admin\model\questions\TestPaperQuestions;
+use app\admin\model\questions\TestPaperScoreGrade;
+use app\admin\model\questions\TestPaperObtain;
+use app\admin\model\questions\Certificate;
+use app\admin\model\questions\CertificateRelated;
+use app\admin\model\questions\ExaminationRecord;
+use app\admin\model\special\Special;
+use app\admin\model\system\Recommend;
+use app\admin\model\system\RecommendRelation;
+use app\admin\model\merchant\Merchant;
+use app\admin\model\system\WebRecommend;
+use app\admin\model\system\WebRecommendRelation;
+use app\admin\model\user\User;
+
+/**
+ * 试卷
+ * Class TestPaper
+ */
+class TestPaper extends AuthController
+{
+    /**
+     * 试卷列表
+     */
+    public function index($type = 1)
+    {
+        $this->assign([
+            'type' => $type,
+            'mer_list' => Merchant::getMerchantList(),
+            'category' => TestPaperCategory::taskCategoryAll(2, $type)
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取试卷列表
+     */
+    public function getTestPaperExercisesList($type = 1)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', 0],
+            ['is_show', ''],
+            ['status', 1],
+            ['mer_id', 0],
+            ['title', '']
+        ]);
+        $where['type'] = $type;
+        return Json::successlayui(TestPaperModel::testPaperExercisesList($where));
+    }
+
+    /**资料审核
+     * @return mixed
+     */
+    public function examine($type = 1)
+    {
+        $category = TestPaperCategory::taskCategoryAll(2, $type);
+        $mer_list = Merchant::getMerchantList();
+        $this->assign([
+            'type' => $type,
+            'category' => $category,
+            'mer_list' => $mer_list
+        ]);
+        return $this->fetch();
+    }
+
+    /**获得审核资料
+     * @throws \think\Exception
+     */
+    public function get_test_paper_examine_list($type = 1)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', 0],
+            ['is_show', ''],
+            ['status', ''],
+            ['mer_id', 0],
+            ['title', '']
+        ]);
+        $where['type'] = $type;
+        return Json::successlayui(TestPaperModel::testPaperExercisesExamineList($where));
+    }
+
+    /**审核
+     * @param $id
+     * @param $type
+     * @return mixed|void
+     * @throws \think\exception\DbException
+     */
+    public function examineDetails($id,$type)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $details = TestPaperModel::get($id);
+        if (!$details) return Json::fail('试卷不存在');
+        $grade = [];
+        if ($details && $id) {
+            $single_tmp_list = TestPaperQuestions::gettestPaperQuestions($id, 1);
+            $many_tmp_list = TestPaperQuestions::gettestPaperQuestions($id, 2);
+            $judge_tmp_list = TestPaperQuestions::gettestPaperQuestions($id, 3);
+            if ($type == 2) $grade = TestPaperScoreGrade::testPaperScoreGradeList($id);
+        } else {
+            $single_tmp_list = [];
+            $many_tmp_list = [];
+            $judge_tmp_list = [];
+        }
+        $this->assign([
+            'type' => $type,
+            'details' => json_encode($details),
+            'grade' => json_encode($grade),
+            'single_tmp_list' => json_encode($single_tmp_list),
+            'many_tmp_list' => json_encode($many_tmp_list),
+            'judge_tmp_list' => json_encode($judge_tmp_list)
+        ]);
+        return $this->fetch('material');
+    }
+
+    /**不通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function fail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!TestPaperModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $test = TestPaperModel::get($id);
+        if (!$test) return Json::fail('操作记录不存!');
+        if ($test->status != 0) return Json::fail('您已审核,请勿重复操作');
+        TestPaperModel::beginTrans();
+        $res = TestPaperModel::changeFail($id, $test['mer_id'], $fail_msg['message']);
+        if ($res) {
+            TestPaperModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            TestPaperModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    /**通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function succ($id)
+    {
+        if (!TestPaperModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $test = TestPaperModel::get($id);
+        if (!$test) return Json::fail('操作记录不存!');
+        if ($test->status != 0) return Json::fail('您已审核,请勿重复操作');
+        TestPaperModel::beginTrans();
+        $res = TestPaperModel::changeSuccess($id, $test['mer_id']);
+        if ($res) {
+            TestPaperModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            TestPaperModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+
+    /**
+     * 用户答题记录
+     */
+    public function answerNotes($type = 1, $test_id = 0, $uid = 0)
+    {
+        $this->assign(['type' => $type, 'test_id' => $test_id, 'uid' => $uid, 'testPaper' => TestPaperModel::testPaperList($type)]);
+        return $this->fetch('record');
+    }
+
+    /**
+     * 获取试卷列表
+     */
+    public function getExaminationRecords($type = 1, $testId = 0, $uid = 0)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['test_id', 0],
+            ['title', ''],
+            ['excel', 0]
+        ]);
+        $where['type'] = $type;
+        if ($testId) $where['test_id'] = $testId;
+        if ($uid) $where['uid'] = $uid;
+        return Json::successlayui(ExaminationRecord::getExaminationRecord($where));
+    }
+
+    /**
+     * 用户答题
+     */
+    public function answers($record_id = 0, $test_id = 0, $type = 1, $uid =0)
+    {
+        $dat=TestPaperModel::where('id',$test_id)->field('single_sort,many_sort,judge_sort')->find();
+        $this->assign(['record_id' => $record_id, 'test_id' => $test_id, 'type' => $type, 'uid' => $uid, 'single_sort' => $dat['single_sort'], 'many_sort' => $dat['many_sort'], 'judge_sort' => $dat['judge_sort']]);
+        return $this->fetch();
+    }
+
+    /**答题信息
+     * @param $uid
+     * @return void
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function getUserInformation($uid)
+    {
+        if(!$uid) return Json::fail('参数错误');
+        $data=User::where(['uid'=>$uid])->field('nickname,name,uid,avatar')->find();
+        return Json::successful($data);
+    }
+    /**成绩
+     * @param int $record_id
+     * @param int $test_id
+     * @param int $uid
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function getUserAchievement($record_id=0,$test_id=0,$uid=0)
+    {
+        if(!$record_id || !$test_id || !$uid) return Json::fail('参数错误');
+        $dat=TestPaperModel::where('id',$test_id)->field('title,item_number,total_score')->find();
+        $record=ExaminationRecord::where(['id'=>$record_id,'test_id'=>$test_id,'uid'=>$uid,'type'=>2])->find();
+        $data['title']=$dat['title'];
+        $data['item_number']=$dat['item_number'];
+        $data['total_score']=$dat['total_score'];
+        $data['yes_questions']=$record['yes_questions'];
+        $data['score']=$record['score'];
+        $data['start_time']=date('Y-m-d H:i',$record['start_time']);
+        return Json::successful($data);
+    }
+    /**试卷中的试题答题情况
+     * @param int $id
+     * @param int $type
+     */
+    public function getTestPaperAnswers($test_id=0,$record_id=0,$question_type=1)
+    {
+        if(!$test_id || !$record_id) return Json::fail('参数错误');
+        return Json::successful(TestPaperQuestions::getExaminationRecordAnswers($test_id,$record_id,$question_type));
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '', $test = 0)
+    {
+        if (!$field || !$id || $value == '') Json::fail('缺少参数3');
+        if ($field == 'sort' && bcsub($value, 0, 0) < 0) return Json::fail('排序不能为负数');
+        if ($test) {
+            $model_type = 'paper';
+        } else {
+            $model_type = 'test';
+        }
+        $res = parent::getDataModification($model_type, $id, $field, $value);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**关联试题 手动组题
+     * @param int $id
+     */
+    public function questions($question_type = 0, $id = 1)
+    {
+        $this->assign(['id' => $id, 'question_type' => $question_type, 'cateList' => QuestionsCategpry::taskCategoryAll(2)]);
+        return $this->fetch('questions');
+    }
+
+    /**
+     * 获取题库列表
+     */
+    public function getTestQuestionsList($question_type = '', $id = 0)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', 0],
+            ['title', '']
+        ]);
+        $where['type'] = $question_type;
+        $arrays = [];
+        if ($id) {
+            $arrays = TestPaperQuestions::where(['test_id' => $id])->column('questions_id');
+        }
+        $list = Questions::questionsList($where, $arrays);
+        return Json::successlayui($list);
+    }
+
+    /**试题分类
+     * @param int $id
+     * @param int $type
+     */
+    public function cate_questions()
+    {
+        $list = QuestionsCategpry::taskCategoryAll(2);
+        return Json::successful($list);
+    }
+
+    /**
+     * 查看试卷
+     */
+    public function test_paper($id = 0, $type = 1)
+    {
+        $this->assign(['id' => $id, 'type' => $type]);
+        return $this->fetch();
+    }
+
+    /**试卷中的试题
+     * @param int $id
+     * @param int $type
+     */
+    public function getTestPaperList($id = 0, $type = 1)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+        ]);
+        return Json::successlayui(TestPaperQuestions::getTestPaperList($where, $id, $type));
+    }
+
+    /**添加/编辑
+     * @param int $id
+     * @return mixed
+     */
+    public function add($id = 0, $type = 1)
+    {
+        $test = $id > 0 ? TestPaperModel::get($id) : [];
+        $grade = [];
+        if ($test && $id) {
+            $single_tmp_list = TestPaperQuestions::gettestPaperQuestions($id, 1);
+            $many_tmp_list = TestPaperQuestions::gettestPaperQuestions($id, 2);
+            $judge_tmp_list = TestPaperQuestions::gettestPaperQuestions($id, 3);
+            if ($type == 2) $grade = TestPaperScoreGrade::testPaperScoreGradeList($id);
+        } else {
+            $single_tmp_list = [];
+            $many_tmp_list = [];
+            $judge_tmp_list = [];
+        }
+        $this->assign([
+            'id' => $id,
+            'type' => $type,
+            'test' => json_encode($test),
+            'grade' => json_encode($grade),
+            'single_tmp_list' => json_encode($single_tmp_list),
+            'many_tmp_list' => json_encode($many_tmp_list),
+            'judge_tmp_list' => json_encode($judge_tmp_list)
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 获取试题分类
+     */
+    public function add_cate_list($type = 1)
+    {
+        $category = TestPaperCategory::taskCategoryAll(2, $type);
+        return Json::successful($category);
+    }
+
+    /**添加/编辑试题
+     * @param int $id
+     */
+    public function save_add($id = 0, $type = 1)
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['image', ''],
+            ['tid', 0],
+            ['is_show', 1],
+            ['item_number', 0],
+            ['total_score', 0],
+            ['single_number', 0],
+            ['single_score', 0],
+            ['many_number', 0],
+            ['many_score', 0],
+            ['judge_number', 0],
+            ['judge_score', 0],
+            ['single_sort', 0],
+            ['many_sort', 0],
+            ['judge_sort', 0],
+            ['txamination_time', 0],
+            ['fake_sales', 0],
+            ['difficulty', 1],
+            ['pay_type', 0],
+            ['money', 0],
+            ['member_pay_type', 0],
+            ['member_money', 0],
+            ['is_score', 0],
+            ['is_group', 1],
+            ['cate_id', 0],
+            ['frequency', 1],
+            ['singleIds', ''],
+            ['manyIds', ''],
+            ['judgeIds', ''],
+            ['grade', ''],
+            ['sort', 0]
+        ]);
+        if ($data['tid'] <= 0) return Json::fail('请选择试题分类');
+        if (!$data['title']) return Json::fail('请输入试卷标题');
+        if ($type == 2 && !$data['image']) return Json::fail('请添加试卷封面图');
+        if ($data['single_number'] < 0 || $data['many_number'] < 0 || $data['judge_number'] < 0) return Json::fail('各类型题目数量不能小于0');
+        $data['item_number'] = bcadd($data['single_number'], bcadd($data['many_number'], $data['judge_number'], 0), 0);
+        $total_single_score = bcmul($data['single_number'], $data['single_score'], 0);
+        $total_many_score = bcmul($data['many_number'], $data['many_score'], 0);
+        $total_judge_score = bcmul($data['judge_number'], $data['judge_score'], 0);
+        $data['total_score'] = bcadd($total_single_score, bcadd($total_many_score, $total_judge_score, 0), 0);
+        if ($data['item_number'] > 100) return Json::fail('试卷最多100道');
+        if ($type == 1) {
+            unset(
+                $data['txamination_time'],
+                $data['image'],
+                $data['pay_type'],
+                $data['money'],
+                $data['member_pay_type'],
+                $data['member_money']
+            );
+        }
+        $singleIds = json_decode($data['singleIds']);
+        $manyIds = json_decode($data['manyIds']);
+        $judgeIds = json_decode($data['judgeIds']);
+        $grade = json_decode($data['grade'], true);
+        TestPaperModel::beginTrans();
+        if ($id) {
+            $res = TestPaperModel::edit($data, $id);
+            $res1 = true;
+            if ($type == 2) {
+                $res1 = TestPaperScoreGrade::testPaperScoreGradeAdd($id, $grade);
+            }
+            TestPaperQuestions::where('test_id', $id)->delete();
+            if ($data['is_group'] == 1) {
+                $res2 = TestPaperQuestions::addTestPaperQuestions($id, $type, (int)$data['single_number'], $singleIds, $data['single_score']);
+                $res3 = TestPaperQuestions::addTestPaperQuestions($id, $type, (int)$data['many_number'], $manyIds, $data['many_score']);
+                $res4 = TestPaperQuestions::addTestPaperQuestions($id, $type, (int)$data['judge_number'], $judgeIds, $data['judge_score']);
+            } else {
+                $res2 = TestPaperQuestions::addRandomGroupQuestions($id, $type, 1, $data['cate_id'], (int)$data['single_number'], $data['single_score']);
+                $res3 = TestPaperQuestions::addRandomGroupQuestions($id, $type, 2, $data['cate_id'], (int)$data['many_number'], $data['many_score']);
+                $res4 = TestPaperQuestions::addRandomGroupQuestions($id, $type, 3, $data['cate_id'], (int)$data['judge_number'], $data['judge_score']);
+            }
+            $res5 = $this->inspectTestQuestions($id);
+        } else {
+            $data['type'] = $type;
+            $data['add_time'] = time();
+            if (TestPaperModel::be(['title' => $data['title'], 'is_del' => 0])) {
+                return Json::fail('标题已存在!');
+            }
+            $res = TestPaperModel::insertGetId($data);
+            $res1 = true;
+            if ($type == 2) {
+                $res1 = TestPaperScoreGrade::testPaperScoreGradeAdd($res, $grade);
+            }
+            if ($data['is_group'] == 1) {
+                $res2 = TestPaperQuestions::addTestPaperQuestions($res, $type, (int)$data['single_number'], $singleIds, $data['single_score']);
+                $res3 = TestPaperQuestions::addTestPaperQuestions($res, $type, (int)$data['many_number'], $manyIds, $data['many_score']);
+                $res4 = TestPaperQuestions::addTestPaperQuestions($res, $type, (int)$data['judge_number'], $judgeIds, $data['judge_score']);
+            } else {
+                $res2 = TestPaperQuestions::addRandomGroupQuestions($res, $type, 1, $data['cate_id'], (int)$data['single_number'], $data['single_score']);
+                $res3 = TestPaperQuestions::addRandomGroupQuestions($res, $type, 2, $data['cate_id'], (int)$data['many_number'], $data['many_score']);
+                $res4 = TestPaperQuestions::addRandomGroupQuestions($res, $type, 3, $data['cate_id'], (int)$data['judge_number'], $data['judge_score']);
+            }
+            $res5 = $this->inspectTestQuestions($res);
+        }
+        if ($res && $res1 && $res2 && $res3 && $res4 && $res5) {
+            TestPaperModel::commitTrans();
+            return Json::successful('添加/编辑成功');
+        } else {
+            TestPaperModel::rollbackTrans();
+            return Json::fail('添加/编辑失败');
+        }
+    }
+
+    /**
+     * 检查试卷试题数量
+     */
+    public function inspectTestQuestions($id)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $test = TestPaperModel::get($id);
+        if (!$test) return Json::fail('试卷不存在');
+        $single_number = TestPaperQuestions::testPaperQuestionsNumber($id, 1);
+        $many_number = TestPaperQuestions::testPaperQuestionsNumber($id, 2);
+        $judge_number = TestPaperQuestions::testPaperQuestionsNumber($id, 3);
+        if ($single_number < $test['single_number'] || $many_number < $test['many_number'] || $judge_number < $test['judge_number']) {
+            $total = bcadd($single_number, bcadd($many_number, $judge_number, 0), 0);
+            $total_single_score = bcmul($single_number, $test['single_score'], 0);
+            $total_many_score = bcmul($many_number, $test['many_score'], 0);
+            $total_judge_score = bcmul($judge_number, $test['judge_score'], 0);
+            $total_score = bcadd($total_single_score, bcadd($total_many_score, $total_judge_score, 0), 0);
+            $data['single_number'] = $single_number;
+            $data['many_number'] = $many_number;
+            $data['judge_number'] = $judge_number;
+            $data['item_number'] = $total;
+            $data['total_score'] = $total_score;
+            return TestPaperModel::edit($data, $id);
+        } else {
+            return true;
+        }
+    }
+
+    /**删除试卷
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $test = TestPaperModel::get($id);
+        if (!$test) return Json::fail('要删除的试卷不存在');
+        $res = parent::getDataModification('test', $id, 'is_del', 1);
+        if ($res) {
+            TestPaperQuestions::where('test_id', $id)->delete();
+            return Json::successful('删除成功');
+        } else {
+            return Json::fail('删除失败');
+        }
+    }
+
+    /**删除试题
+     * @param int $id
+     */
+    public function TestPaperDelete($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $paperQuestion = TestPaperQuestions::where('id', $id)->find();
+        if (!$paperQuestion) return Json::fail('要删除的试题不存在');
+        TestPaperQuestions::beginTrans();
+        $res = TestPaperQuestions::where('id', $id)->delete();
+        if ($res) {
+            $res1 = $this->inspectTestQuestions($paperQuestion['test_id']);
+            TestPaperQuestions::checkTrans($res1);
+            if ($res1) {
+                return Json::successful('删除成功');
+            } else {
+                return Json::fail('删除失败');
+            }
+        } else {
+            return Json::fail('删除失败');
+        }
+    }
+
+    /**关联证书
+     * @param int $id
+     */
+    public function certificate($related_id = 0)
+    {
+        if (!$related_id) return Json::fail('参数错误');
+        $certificate = CertificateRelated::where(['related' => $related_id, 'obtain' => 2])->find();
+        if ($certificate) {
+            $id = $certificate['id'];
+        } else {
+            $id = 0;
+            $certificate = [];
+        }
+        $this->assign(['related_id' => $related_id, 'id' => $id, 'certificate' => json_encode($certificate)]);
+        return $this->fetch();
+    }
+
+    /**获取对应证书
+     * @param int $obtain
+     */
+    public function certificateLists($obtain = 1)
+    {
+        $list = Certificate::where(['is_del' => 0, 'obtain' => $obtain])->order('sort desc,add_time desc')->select();
+        $list = count($list) > 0 ? $list->toArray() : [];
+        return Json::successful($list);
+    }
+
+    /**试卷关联证书
+     * @param int $id
+     * @param int $obtain
+     */
+    public function certificateRecord($id = 0, $obtain = 1)
+    {
+        $data = parent::postMore([
+            ['cid', 0],
+            ['condition', ''],
+            ['related', 0],
+            ['is_show', 0]
+        ]);
+        $data['obtain'] = $obtain;
+        $res = CertificateRelated::addCertificateRelated($data, $id);
+        if ($res) {
+            return Json::successful('关联成功');
+        } else {
+            return Json::fail('关联失败');
+        }
+    }
+
+    /**
+     * 添加推荐
+     * @param int $product_id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function recommend($test_id = 0)
+    {
+        if (!$test_id) $this->failed('缺少参数');
+        $testPaper = TestPaperModel::get($test_id);
+        if (!$testPaper) $this->failed('没有查到此试卷');
+        if ($testPaper->is_del) $this->failed('此试卷已删除');
+        $type = $testPaper->type;
+        $form = Form::create(Url::build('save_recommend', ['test_id' => $test_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () use ($type) {
+                $types = $type == 1 ? 11 : 12;
+                $list = Recommend::where(['is_show' => 1, 'type' => $types])->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', '排序')->min(0)
+        ]);
+        $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($test_id = 0)
+    {
+        if (!$test_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'] = $test_id;
+        if (RecommendRelation::be(['type' => $recommend->type, 'link_id' => $test_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, $test_id = 0)
+    {
+        if (!$id || !$test_id) $this->failed('缺少参数');
+        if (RecommendRelation::be(['id' => $id, 'link_id' => $test_id])) {
+            $res = RecommendRelation::where(['id' => $id, 'link_id' => $test_id])->delete();
+            if ($res)
+                return Json::successful('取消推荐成功');
+            else
+                return Json::fail('取消推荐失败');
+        } else {
+            return Json::fail('推荐不存在');
+        }
+    }
+
+    /**
+     * 添加推荐
+     * @param int $data_id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function web_recommend($test_id = 0)
+    {
+        if (!$test_id) $this->failed('缺少参数');
+        $testPaper = TestPaperModel::get($test_id);
+        if (!$testPaper) $this->failed('没有查到此试卷');
+        if ($testPaper->is_del) $this->failed('此试卷已删除');
+        $type = $testPaper->type;
+        $form = Form::create(Url::build('save_web_recommend', ['test_id' => $test_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () use ($type) {
+                $types = $type == 1 ? 7 : 8;
+                $model = WebRecommend::where(['is_show' => 1, 'type' => $types]);
+                $list = $model->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_web_recommend($test_id = 0)
+    {
+        if (!$test_id) $this->failed('缺少参数');
+        $data = parent::postMore([
+            ['recommend_id', 0],
+            ['sort', 0],
+        ]);
+        if (!$data['recommend_id']) return Json::fail('请选择推荐');
+        $recommend = WebRecommend::get($data['recommend_id']);
+        if (!$recommend) return Json::fail('导航菜单不存在');
+        $data['add_time'] = time();
+        $data['type'] = $recommend->type;
+        $data['link_id'] = $test_id;
+        if (WebRecommendRelation::be(['type' => $recommend->type, 'link_id' => $test_id, 'recommend_id' => $data['recommend_id']])) return Json::fail('已推荐,请勿重复推荐');
+        if (WebRecommendRelation::set($data))
+            return Json::successful('推荐成功');
+        else
+            return Json::fail('推荐失败');
+    }
+
+    /**取消推荐
+     * @param int $id
+     */
+    public function cancel_web_recommendation($id = 0, $test_id = 0)
+    {
+        if (!$id || !$test_id) return Json::fail('缺少参数');
+        if (WebRecommendRelation::be(['id' => $id, 'link_id' => $test_id])) {
+            $res = WebRecommendRelation::where(['id' => $id, 'link_id' => $test_id])->delete();
+            if ($res)
+                return Json::successful('取消推荐成功');
+            else
+                return Json::fail('取消推荐失败');
+        } else {
+            return Json::fail('推荐不存在');
+        }
+    }
+}

+ 146 - 0
application/admin/controller/questions/TestPaperCategory.php

xqd
@@ -0,0 +1,146 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\questions;
+
+use app\admin\controller\AuthController;
+use service\JsonService as Json;
+use app\admin\model\questions\TestPaperCategory as TestPaperCategoryModel;
+use app\admin\model\questions\TestPaper;
+
+/**
+ * 试卷分类
+ * Class TestPaperCategory
+ */
+class TestPaperCategory extends AuthController
+{
+    public function index($type = 1)
+    {
+        $this->assign(['type' => $type]);
+        return $this->fetch();
+    }
+
+    public function get_category_list($type = 1)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['tid', 0],
+            ['title', ''],
+        ]);
+        return Json::successful(TestPaperCategoryModel::getAllList($where, $type));
+    }
+
+    /**
+     * 创建分类
+     * @param int $id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0, $type = 1)
+    {
+        $cate = $id > 0 ? TestPaperCategoryModel::get($id) : [];
+        $this->assign(['cate' => json_encode($cate), 'id' => $id, 'type' => $type]);
+        return $this->fetch();
+    }
+
+    public function get_cate_list($type = 1)
+    {
+        $category = TestPaperCategoryModel::taskCategoryAll(2, $type);
+        return Json::successful($category);
+    }
+
+    /**一级分类
+     * @param int $type
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function add_cate_list($type = 1)
+    {
+        $category = TestPaperCategoryModel::where(['pid' => 0, 'is_del' => 0, 'type' => $type])->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('缺少参数');
+        $res = parent::getDataModification('test_paper', $id, $field, $value);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**
+     * 新增或者修改
+     * @return json
+     */
+    public function save($id = 0, $type = 1)
+    {
+        $post = parent::postMore([
+            ['title', ''],
+            ['pid', ''],
+            ['sort', 0],
+        ]);
+        if (!$post['title']) return Json::fail('请输入分类名称');
+        if ($id) {
+            $cate = TestPaperCategoryModel::get($id);
+            if (!$cate['pid'] && $post['pid'] && TestPaperCategoryModel::be(['pid' => $id, 'type' => $type, 'is_del' => 0])) return Json::fail('无法移动有下级的分类');
+            if (TestPaperCategoryModel::where(['title' => $post['title'], 'is_del' => 0])->where('id', '<>', $id)->count() >= 1) return Json::fail('分类名称已存在');
+            $res = TestPaperCategoryModel::edit($post, $id);
+            if ($res)
+                return Json::successful('修改成功');
+            else
+                return Json::fail('修改失败');
+        } else {
+            $post['add_time'] = time();
+            $post['type'] = $type;
+            $res = TestPaperCategoryModel::set($post);
+            if ($res)
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 删除
+     * @return json
+     */
+    public function delete($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        $cate = TestPaperCategoryModel::get($id);
+        if (!$cate['pid']) {
+            $count = TestPaperCategoryModel::where('pid', $id)->where('is_del', 0)->count();
+            if ($count) return Json::fail('暂无法删除,请删除下级分类');
+        }
+        if (TestPaper::where('tid', $id)->where('is_del', 0)->count()) return Json::fail('暂无法删除,请先删除试卷');
+        $res = parent::getDataModification('test_paper', $id, 'is_del', 1);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+}

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

xqd
@@ -0,0 +1,227 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\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\setting
+ */
+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::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('添加管理员', $f, 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([
+            'account',
+            'conf_pwd',
+            'pwd',
+            'real_name',
+            ['roles', []],
+            ['status', 0]
+        ], $request);
+        if (!$data['account']) return Json::fail('请输入管理员账号');
+        if (!$data['roles']) return Json::fail('请选择至少一个管理员身份');
+        if (!$data['pwd']) return Json::fail('请输入管理员登陆密码');
+        if ($data['pwd'] != $data['conf_pwd']) return Json::fail('两次输入密码不想同');
+        if (AdminModel::be($data['account'], 'account')) return Json::fail('管理员账号已存在');
+        $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::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $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)
+    {
+        $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']);
+        }
+        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']);
+            $res = AdminModel::edit($data, $adminInfo['id']);
+            if ($res) {
+                AdminModel::clearLoginInfo();
+                return Json::successful('修改成功!,请重新登录');
+            } else {
+                return Json::successful('修改失败!');
+            }
+        }
+    }
+}

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

xqd
@@ -0,0 +1,345 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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, 'endpoint' => $region])->select();
+        $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('参数有误');
+        $OssBucketId = $data['OssBucketId'];
+        $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) {
+            $dat['is_use'] = 1;
+            SystemBucketModel::edit($dat, $OssBucketId, 'id');
+            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('域名已存在!');
+        SystemBroadcastModel::beginTrans();
+        $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)) {
+                SystemBroadcastModel::commitTrans();
+                return Json::successful('添加直播域名成功!');
+            } else {
+                SystemBroadcastModel::rollbackTrans();
+                return Json::fail('添加到数据库失败/请确认域名是否和视频直播在同一个阿里云账户下!');
+            }
+        } else {
+            SystemBroadcastModel::rollbackTrans();
+            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('设置直播域名失败');
+        }
+    }
+}

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

xqd
@@ -0,0 +1,177 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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;
+        $this->assign(['endpoint' => $endpoint]);
+        return $this->fetch();
+    }
+
+    /**
+     * Bucket列表
+     */
+    public function bucket_list()
+    {
+        $where = parent::getMore([
+            ['title', ''],
+            ['endpoint', ''],
+            ['types', 1],
+        ], $this->request);
+        return Json::successlayui(SystemBucketModel::bucKetList($where));
+    }
+
+    /**
+     * 拉取储存空间
+     */
+    public function pullBucket()
+    {
+        $where = parent::getMore([
+            ['endpoint', ''],
+        ], $this->request);
+        $list = AlipayDisposeService::ossBucketList($where['endpoint']);
+        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('存储空间已存在');
+        }
+        SystemBucketModel::beginTrans();
+        $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)) {
+                SystemBucketModel::commitTrans();
+                return Json::successful('添加存储空间成功!');
+            } else {
+                SystemBucketModel::rollbackTrans();
+                return Json::fail('添加到数据库失败或设置跨域规则失败!');
+            }
+        } else {
+            SystemBucketModel::rollbackTrans();
+            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('设置存储空间失败');
+        }
+    }
+
+}

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

xqd
@@ -0,0 +1,491 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\setting
+ */
+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'])->min(0);
+                            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'), 2);
+        $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'), 2);
+        $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)), 2);
+        $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' || $k == 'service_url') {
+                    $http = "/^(http(s)?:\/\/)([0-9a-z-]{1,}.)?[0-9a-z-]{2,}.([0-9a-z-]{2,}.)?[a-z]{2,}$/i";
+                    if ($k == 'service_url' && $v != '' || $k == 'site_url') {
+                        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 == 'member_brokerage_ratio' || $k == 'deduction_proportion_ratio' || $k == 'member_brokerage_two' || $k == 'goods_brokerage_ratio' || $k == 'goods_brokerage_two' || $k == 'gold_coin_ratio' || $k == 'barrage_show_time' || $k == 'store_stock' || $k == 'order_clear_time' || $k == 'automatic_receiving_time' || $k == 'extract_price') {
+                    if ($k == 'store_stock') {
+                        $v = bcadd($v, 0, 0);
+                    } else {
+                        $v = bcadd($v, 0, 2);
+                    }
+                    if (bcsub($v, 0, 2) <= 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 'barrage_show_time':
+                                return Json::fail('专题弹幕停留时间不能小于等于0');
+                                break;
+                            case 'store_stock':
+                                return Json::fail('警戒库存不能小于等于0');
+                                break;
+                        }
+                    }
+                    if (bcsub($v, 100, 2) > 0 || bcsub($v, 0, 2) < 0) {
+                        switch ($k) {
+                            case 'store_brokerage_ratio':
+                                return Json::fail('课程一级推广人返佣比例不能大于100或小于0');
+                                break;
+                            case 'store_brokerage_two':
+                                return Json::fail('课程二级推广人返佣比例不能大于100或小于0');
+                                break;
+                            case 'member_brokerage_ratio':
+                                return Json::fail('会员一级推广人返佣比例不能大于100或小于0');
+                                break;
+                            case 'member_brokerage_two':
+                                return Json::fail('会员二级推广人返佣比例不能大于100或小于0');
+                                break;
+                            case 'goods_brokerage_ratio':
+                                return Json::fail('商品一级推广人返佣比例不能大于100或小于0');
+                                break;
+                            case 'goods_brokerage_two':
+                                return Json::fail('商品二级推广人返佣比例不能大于100或小于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

xqd
@@ -0,0 +1,68 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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('内容不能为空');
+        }
+        $data['content'] = htmlspecialchars($content);
+        if (SystemConfigContentModel::edit($data, $id)) {
+            return JsonService::successful('保存成功');
+        } else {
+            return JsonService::fail('保存失败');
+        }
+    }
+}

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

xqd
@@ -0,0 +1,150 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\setting
+ */
+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' => 2, 'label' => '分销'], ['value' => 3, 'label' => '其它'], ['value' => 4, 'label' => '支付'], ['value' => 5, 'label' => '阿里云'], ['value' => 6, 'label' => '虚拟币']]),
+            Form::radio('status', '状态', 1)->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']])
+        ]);
+        $form->setMethod('post')->setTitle('添加分类配置')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},2000);');
+        $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' => 2, 'label' => '分销'], ['value' => 3, 'label' => '其它'], ['value' => 4, 'label' => '支付'], ['value' => 5, 'label' => '阿里云'], ['value' => 6, 'label' => '虚拟币']]),
+            Form::radio('status', '状态', $menu['status'])->options([['value' => 1, 'label' => '显示'], ['value' => 2, 'label' => '隐藏']])
+        ]);
+        $form->setMethod('post')->setTitle('添加分类配置')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},2000);');
+        $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

xqd
@@ -0,0 +1,154 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\setting
+ */
+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('删除成功!');
+        }
+    }
+}

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

xqd
@@ -0,0 +1,1158 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\SpecialSubject;
+use app\admin\model\special\RecommendBanner;
+use app\admin\model\special\Special;
+use app\admin\model\special\Lecturer;
+use app\admin\model\system\Recommend;
+use app\admin\model\system\RecommendRelation;
+use app\admin\model\system\WebRecommend;
+use app\admin\model\system\WebRecommendRelation;
+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;
+use service\SystemConfigService;
+use app\admin\model\system\SystemConfig;
+use app\admin\model\download\DataDownload;
+
+/**
+ * 数据列表控制器  在组合数据中
+ * Class SystemGroupData
+ * @package app\admin\controller\setting
+ */
+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"])->maxlength(90);
+                    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)->min(0);
+        $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 == "" || preg_replace("#(^( |\s)+|( |\s)+$)#", "", $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 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'])->maxlength(90);
+                    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::number('sort', '排序', $GroupData["sort"])->min(0);
+        $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 == "" || preg_replace("#(^( |\s)+|( |\s)+$)#", "", $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', SpecialSubject::specialCategoryAll(1));
+        $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', SpecialSubject::specialCategoryAll(1));
+        $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', ''],
+        ]);
+        $post['is_show'] = $post['is_fixed'] ? 1 : $post['is_show'];
+        if ($post['type'] == 14) {
+            if ($post['typesetting'] == 1 || $post['typesetting'] == 4) return Json::fail('资料不能选择该排版');
+        }
+        if ($post['typesetting'] == 5) {
+            unset($post['type'], $post['image'], $post['show_count']);
+        }
+        if ($id) {
+            $rescomm = Recommend::get($id);
+            if (!$rescomm) return Json::fail('修改的信息不存在');
+            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();
+        }
+    }
+
+    /**新闻\素材推荐内容
+     * @param int $id
+     * @return mixed
+     */
+    public function recemmend_article_content($id = 0)
+    {
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    /**练习/考试推荐内容
+     * @param int $id
+     * @return mixed
+     */
+    public function recemmend_test_content($id = 0)
+    {
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    /**商品推荐内容
+     * @param int $id
+     * @return mixed
+     */
+    public function recemmend_store_content($id = 0)
+    {
+        $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 = '', $recommend = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        if ($recommend == 'web') {
+            $res = WebRecommend::where(['id' => $id])->update(['is_show' => (int)$is_show]);
+        } else {
+            $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 = '', $recommend = '')
+    {
+        $field == '' || $id == '' || $value == '' && Json::fail('缺少参数');
+        if ($recommend == 'web') {
+            $res = WebRecommend::where(['id' => $id])->update([$field => $value]);
+        } else {
+            $res = Recommend::where(['id' => $id])->update([$field => $value]);
+        }
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_recemmend_value($field = '', $id = '', $value = '')
+    {
+        $field == '' || $id == '' || $value == '' && 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();
+    }
+
+    /**
+     * 个人中心题库菜单
+     */
+    public function center_menu_topic($gid = 0)
+    {
+        $this->assign('gid', $gid);
+        return $this->fetch('center_menu1');
+    }
+
+    /**
+     * 个人中心服务菜单
+     */
+    public function center_menu()
+    {
+        return $this->fetch('center_menu');
+    }
+
+    /**
+     * pc端首页导航
+     */
+    public function center_web_menu()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * pc端自定义跳转导航添加和修改页面
+     * @param int $id
+     * @return mixed|void
+     * @throws \FormBuilder\exception\FormBuilderException
+     * @throws \think\exception\DbException
+     */
+    public function create_web_recemmend_custom($id = 0, $is_fixed = 1)
+    {
+        if ($id) {
+            $recommend = WebRecommend::get($id);
+            if (!$recommend) {
+                return $this->failed('您修改的导航不存在');
+            }
+        }
+        $f[] = Form::input('title', '名称', isset($recommend) ? $recommend->title : '');
+        $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_web_recemmend_custom', compact('id', 'is_fixed')), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存pc端自定义导航链接
+     * @param int $id
+     */
+    public function save_web_recemmend_custom($id = 0, $is_fixed = 1)
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['link', ''],
+            ['sort', 0],
+            ['is_show', 0],
+            ['type', 6],
+            ['is_fixed', $is_fixed],
+        ]);
+        $data['title'] = preg_replace("#(^( |\s)+|( |\s)+$)#", "", $data['title']);
+        $data['link'] = preg_replace("#(^( |\s)+|( |\s)+$)#", "", $data['link']);
+        if (!$data['title']) {
+            return Json::fail('请填写导航名称');
+        }
+        if (mb_strlen($data['title']) > 6) return Json::fail('标题不能超过6个字');
+        if (!$data['link']) {
+            return Json::fail('请填写导航跳转地址');
+        }
+
+        if ($id) {
+            WebRecommend::edit($data, $id);
+            return Json::successful('修改成功');
+        } else {
+            $data['add_time'] = time();
+            if (WebRecommend::be(['title' => $data['title'], 'link' => $data['link']])) return Json::fail('名称已存在');
+            $res = WebRecommend::set($data);
+            if ($res) {
+                return Json::successful('添加成功');
+            } else {
+                return Json::fail('修改失败');
+            }
+        }
+    }
+
+    /**
+     * 自定义跳转导航添加和修改页面
+     * @param int $id
+     * @return mixed|void
+     * @throws \FormBuilder\exception\FormBuilderException
+     * @throws \think\exception\DbException
+     */
+    public function create_recemmend_custom($id = 0, $is_fixed = 1)
+    {
+        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::number('sort', '排序', isset($recommend) ? $recommend->sort : 0)->min(0);
+        if ($is_fixed == 2) {
+            $f[] = Form::radio('is_promoter', '推广权限', isset($recommend) ? $recommend->is_promoter : 0)->options([['value' => 1, 'label' => '需要权限'], ['value' => 0, 'label' => '无需权限']]);
+            $f[] = Form::radio('is_write_off', '核销权限', isset($recommend) ? $recommend->is_write_off : 0)->options([['value' => 1, 'label' => '需要权限'], ['value' => 0, 'label' => '无需权限']]);
+            $f[] = Form::radio('is_lecturer', '讲师菜单', isset($recommend) ? $recommend->is_lecturer : 0)->options([['value' => 0, 'label' => '非讲师菜单'], ['value' => 1, 'label' => '讲师申请菜单'], ['value' => 2, 'label' => '讲师中心菜单']]);
+        }
+        $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', 'is_fixed')), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**
+     * 保存自定义导航链接
+     * @param int $id
+     */
+    public function save_recemmend_custom($id = 0, $is_fixed = 1)
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['icon', ''],
+            ['link', ''],
+            ['sort', 0],
+            ['is_show', 0],
+            ['is_promoter', 0],
+            ['is_write_off', 0],
+            ['is_lecturer', 0],
+            ['type', 3],
+            ['is_fixed', $is_fixed],
+        ]);
+        $data['title'] = preg_replace("#(^( |\s)+|( |\s)+$)#", "", $data['title']);
+        $data['link'] = preg_replace("#(^( |\s)+|( |\s)+$)#", "", $data['link']);
+        if (!$data['title']) {
+            return Json::fail('请填写导航名称');
+        }
+        if (!$data['icon']) {
+            return Json::fail('请选择导航图标');
+        }
+        if (!$data['link']) {
+            return Json::fail('请填写导航跳转地址');
+        }
+
+        if ($id) {
+            Recommend::edit($data, $id);
+            return Json::successful('修改成功');
+        } else {
+            $data['add_time'] = time();
+            if (Recommend::be(['title' => $data['title'], 'link' => $data['link']])) return Json::fail('名称已存在');
+            $res = Recommend::set($data);
+            if ($res) {
+                return Json::successful('添加成功');
+            } else {
+                return Json::fail('修改失败');
+            }
+        }
+    }
+
+
+    /**
+     * 显示资源列表
+     * @return \think\Response
+     */
+    public function index_v1($gid)
+    {
+        $is_show_or_hide = SystemConfigService::get('is_show_or_hide');
+        $this->assign(compact("gid", 'is_show_or_hide'));
+        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 = count($data);
+        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(SpecialSubject::specialCategoryAll(1)),
+        ]);
+        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 {
+            $is_light = Special::where('id', $data['select_id'])->value('is_light');
+            if ($is_light) {
+                $info['wap_link']['value'] = '/wap/special/single_details?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('编辑失败');
+        }
+    }
+
+    /**首页活动是否显示
+     * @param $value
+     */
+    public function is_show_or_hide($value)
+    {
+        $res = SystemConfig::edit(['value' => json_encode($value)], 'is_show_or_hide', 'menu_name');
+        if ($res) {
+            return Json::successful('编辑成功');
+        } else {
+            return Json::fail('编辑失败');
+        }
+    }
+
+    public function web_recommend()
+    {
+        return $this->fetch();
+    }
+
+    public function web_recommend_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['is_fixed', $this->request->param('is_fixed', 0)],
+            ['order', '']
+        ]);
+        return Json::successlayui(WebRecommend::getRecommendList($where));
+    }
+
+    public function create_web_recemmend($id = 0)
+    {
+        if ($id) {
+            $this->assign('recemmend', WebRecommend::get($id));
+        }
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    public function save_web_recemmend($id = 0)
+    {
+        $post = parent::postMore([
+            ['title', ''],
+            ['explain', ''],
+            ['type', ''],
+            ['sort', 0],
+            ['is_show', 0],
+            ['show_count', 0],
+        ]);
+        if (mb_strlen($post['title']) > 6) return Json::fail('标题不能超过6个字');
+        if ($id) {
+            $rescomm = WebRecommend::get($id);
+            if (!$rescomm) return Json::fail('修改的信息不存在');
+            WebRecommend::update($post, ['id' => $id]);
+            return Json::successful('修改成功');
+        } else {
+            $post['add_time'] = time();
+            if (WebRecommend::set($post))
+                return Json::successful('保存成功');
+            else
+                return Json::fail('保存失败');
+        }
+    }
+
+    public function data_download($id = 0)
+    {
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+
+    public function article_list($id = 0)
+    {
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    public function test_list($id = 0)
+    {
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    public function recemmend_web_content($id = 0)
+    {
+        if (!$id) return Json::fail('缺少参数');
+        if ($this->request->isAjax()) {
+            $where = parent::getMore([
+                ['page', 1],
+                ['limit', 20],
+            ]);
+            return Json::successlayui(WebRecommendRelation::getAll($where, $id));
+        } else {
+            $this->assign('id', $id);
+            return $this->fetch();
+        }
+    }
+
+    /**关联资料
+     * @param int $id
+     * @param int $ids
+     */
+    public function addDataDownload($id = 0, $ids = '')
+    {
+        if (!$id || $ids == '') Json::fail('缺少参数');
+        $res = WebRecommendRelation::addDataDownload($id, $ids);
+        if ($res) {
+            return Json::successful('关联成功');
+        } else {
+            return Json::fail('关联失败');
+        }
+    }
+
+    /**专题关联试卷删除
+     * @param int $id
+     * @param int $data_id
+     */
+    public function delRecemmend($id, $data_id)
+    {
+        if (!$id || !$data_id) Json::fail('缺少参数');
+        $res = WebRecommendRelation::userDelRecemmend($id, $data_id);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+    /**排序
+     * @param int $id
+     * @param int $link_id
+     * @param $value
+     */
+    public function upRecemmendSort($id, $value)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $res = WebRecommendRelation::updateRecommendSort($id, $value);
+        if ($res)
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败');
+    }
+
+    /**
+     * 获取资料列表
+     */
+    public function getDataDownloadList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['recommend_id', 0],
+            ['status', 1],
+            ['title', '']
+        ]);
+        $data = [];
+        if (isset($where['recommend_id']) && $where['recommend_id']) {
+            $data = WebRecommendRelation::setWhere($where['recommend_id'])->column('link_id');
+        }
+        $download = DataDownload::dataDownloadLists($where, $data);
+        if (isset($download['data']) && $download['data']) {
+            foreach ($download['data'] as $k => $v) {
+                $download['data'][$k]['is_check'] = 0;
+            }
+        }
+        return Json::successlayui($download);
+    }
+
+    public function special_list($id = 0)
+    {
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    /**
+     * 图文、音频、视频、专栏专题素材列表获取
+     * @return json
+     * */
+    public function source_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['title', ''],
+            ['type', ''],
+            ['is_light', ''],
+            ['recommend_id', 0]
+        ]);
+        $rescomm = WebRecommend::get($where['recommend_id']);
+        $special_source = [];
+        if (isset($where['recommend_id']) && $where['recommend_id']) {
+            $special_source = WebRecommendRelation::setWhere($where['recommend_id'])->column('link_id');
+        }
+        $special_task = Special::getUserSpecialLists($where, $special_source, $rescomm['type']);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                $special_task['data'][$k]['is_check'] = 0;
+                $special_task['data'][$k]['pay_status'] = PAY_MONEY;
+                if ($v['type'] == 6) $v['type'] = $v['light_type'];
+                $special_task['data'][$k]['types'] = parent::specialTaskType($v['type']);
+            }
+        }
+        return Json::successlayui($special_task);
+    }
+
+    public function lecturer_list($id = 0)
+    {
+        $this->assign('id', $id);
+        return $this->fetch();
+    }
+
+    public function get_lecturer_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['title', ''],
+            ['is_show', 1],
+            ['recommend_id', 0]
+        ]);
+        $lecturer = [];
+        if (isset($where['recommend_id']) && $where['recommend_id']) {
+            $lecturer = WebRecommendRelation::setWhere($where['recommend_id'])->column('link_id');
+        }
+        $special_task = Lecturer::getRecommendLecturerList($where, $lecturer);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                $special_task['data'][$k]['is_check'] = 0;
+            }
+        }
+        return Json::successlayui($special_task);
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @param  int $id
+     * @return \think\Response
+     */
+    public function delete_web_recomm($id)
+    {
+        if (WebRecommendRelation::be(['recommend_id' => $id])) return Json::fail('删除失败,请先删除内容管理里面的列表');
+        if (!WebRecommend::del($id))
+            return Json::fail('删除失败');
+        else
+            return Json::successful('删除成功!');
+    }
+}

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

xqd
@@ -0,0 +1,183 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\setting
+ */
+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', ''],
+            ['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)->min(0),
+            Form::radio('is_show', '是否菜单', 1)->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '显示(菜单只显示三级)']]),
+        ]);
+        $form->setMethod('post')->setTitle('添加权限')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},2000);');
+        $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'])->min(0),
+            Form::radio('is_show', '是否菜单', $menu['is_show'])->options([['value' => 0, 'label' => '隐藏'], ['value' => 1, 'label' => '显示(菜单只显示三级)']])
+        ]);
+        $form->setMethod('post')->setTitle('编辑权限')->setSuccessScript('parent.$(".J_iframe:visible")[0].contentWindow.location.reload(); setTimeout(function(){parent.layer.close(parent.layer.getFrameIndex(window.name));},2000);');
+        $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('删除成功!');
+    }
+
+}

+ 264 - 0
application/admin/controller/setting/SystemMessage.php

xqd
@@ -0,0 +1,264 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\SystemMessage as MessageModel;
+use app\admin\model\wechat\WechatTemplate as WechatTemplateModel;
+use service\JsonService;
+use service\WechatTemplateService;
+use service\SystemConfigService;
+use think\Request;
+use think\Url;
+
+/**
+ * 消息通知 控制器
+ * Class SystemMessage
+ * @package app\admin\controller\setting
+ */
+class SystemMessage extends AuthController
+{
+    /**
+     * 消息通知展示
+     * @return
+     * */
+    public function index()
+    {
+        $data = [];
+        if (SystemConfigService::get('wechat_appid') && SystemConfigService::get('wechat_appsecret')) {
+            try {
+                $data = WechatTemplateService::getIndustry();
+                $data = count($data) > 0 ? $data->toArray() : [];
+            } catch (\Exception $e) {
+            }
+        }
+        $this->assign('data', $data);
+        return $this->fetch();
+    }
+
+    /**
+     * 同步微信模版消息
+     */
+    public function synchronousWechatTemplate()
+    {
+        if (!SystemConfigService::get('wechat_appid') || !SystemConfigService::get('wechat_appsecret')) return JsonService::fail('请先配置公众号');
+        try {
+            $data = WechatTemplateService::getIndustry();
+            $data = count($data) > 0 ? $data->toArray() : [];
+        } catch (\Exception $e) {
+            return JsonService::fail($e->getMessage());
+        }
+        if ($data['primary_industry']['first_class'] == 'IT科技' && $data['primary_industry']['second_class'] == '互联网|电子商务' &&
+            $data['secondary_industry']['first_class'] == 'IT科技' && $data['secondary_industry']['second_class'] == 'IT软件与服务') {
+            $this->set_template();
+        } else {
+            try {
+                WechatTemplateService::setIndustry(1, 2);
+            } catch (\Exception $e) {
+                return JsonService::fail('同步失败,请检查公众号配置');
+            }
+            $this->set_template();
+        }
+        return JsonService::successful('同步完成');
+    }
+
+    /**模版消息同步
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function set_template()
+    {
+        $list = WechatTemplateModel::where('status', 1)->select();
+        foreach ($list as $key => $value) {
+            try {
+                $res = WechatTemplateService::addTemplate($value['tempkey']);
+            } catch (\Exception $e) {
+                continue;
+            }
+            if ($res['errcode'] == 0 && $res['errmsg'] == 'ok' && $res['template_id']) {
+                $data['tempid'] = $res['template_id'];
+                WechatTemplateModel::edit($data, $value['tempkey'], 'tempkey');
+            }
+        }
+        return JsonService::successful('模版消息同步完成');
+    }
+
+    /**
+     * 消息通知获取
+     * @return
+     * */
+    public function system_message_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['title', '']
+        ]);
+        return JsonService::successlayui(MessageModel::systemMessageList($where));
+    }
+
+    /**添加/编辑
+     * @return mixed|void
+     * @throws \think\exception\DbException
+     */
+    public function create()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 添加和修改讲师
+     * @param int $id 修改
+     * @return JsonService
+     * */
+    public function save_message()
+    {
+        $data = parent::postMore([
+            ['name', ''],
+            ['template_const', ''],
+            ['tempkey', ''],
+            ['temp_id', ''],
+            ['sms_content', ''],
+            ['is_wechat', 1],
+            ['is_sms', 1],
+        ]);
+        if (!$data['name']) return JsonService::fail('请输入消息名称');
+        if (!$data['template_const']) return JsonService::fail('请输入模版常数');
+        if (!$data['tempkey']) return JsonService::fail('请编辑模板编号');
+        $data['add_time'] = time();
+        if (!MessageModel::be(['name' => $data['name']])) {
+            $res = MessageModel::set($data);
+        } else {
+            return JsonService::fail('消息已存在');
+        }
+        if ($res)
+            return JsonService::successful('添加成功');
+        else
+            return JsonService::fail('添加失败');
+    }
+
+    /**
+     * 编辑模板消息
+     * @param $id
+     * @return mixed|\think\response\Json|void
+     */
+    public function edit($tempkey)
+    {
+        if (!$tempkey) return $this->failed('数据不存在');
+        $template = WechatTemplateModel::where('tempkey', $tempkey)->find();
+        $status = MessageModel::where('tempkey', $tempkey)->value('is_wechat');
+        $f = array();
+        $f[] = Form::input('tempkey', '模板编号', $template->getData('tempkey'))->disabled(1);
+        $f[] = Form::input('name', '模板名', $template->getData('name'))->disabled(1);
+        $f[] = Form::input('content', '内容', $template->getData('content'))->type('textarea')->disabled(1);
+        $f[] = Form::input('tempid', '模板ID', $template->getData('tempid'));
+        $f[] = Form::radio('status', '状态', $status)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('编辑模板消息', $f, Url::build('update', compact('tempkey')), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**微信模版保存
+     * @param Request $request
+     * @param $tempkey
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function update(Request $request, $tempkey)
+    {
+        $data = parent::postMore([
+            'tempid',
+            ['status', 0]
+        ], $request);
+        if ($data['tempid'] == '') return JsonService::fail('请输入模板ID');
+        if (!$tempkey) return JsonService::fail('数据不存在');
+        $template = WechatTemplateModel::where('tempkey', $tempkey)->find();
+        if (!$template) return JsonService::fail('数据不存在!');
+        WechatTemplateModel::edit($data, $tempkey, 'tempkey');
+        MessageModel::where('tempkey', $tempkey)->update(['is_wechat' => $data['status']]);
+        return JsonService::successful('修改成功!');
+    }
+
+    /**
+     * 编辑短信模板消息
+     * @param $id
+     * @return mixed|\think\response\Json|void
+     */
+    public function sms($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $template = MessageModel::where('id', $id)->find();
+        $f = array();
+        $f[] = Form::input('temp_id', '模板编号', $template->getData('temp_id'))->disabled(1);
+        $f[] = Form::input('name', '模板名', $template->getData('name'))->disabled(1);
+        $f[] = Form::input('sms_content', '内容', $template->getData('sms_content'))->type('textarea')->disabled(1);
+        $f[] = Form::radio('is_sms', '状态', $template->getData('is_sms'))->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
+        $form = Form::make_post_form('编辑短信模板消息', $f, Url::build('sms_update', compact('id')), 2);
+        $this->assign(compact('form'));
+        return $this->fetch('public/form-builder');
+    }
+
+    /**短信状态保存
+     * @param Request $request
+     * @param $id
+     */
+    public function sms_update(Request $request, $id)
+    {
+        $data = parent::postMore([
+            ['is_sms', 0]
+        ], $request);
+        if (!$id) return JsonService::fail('数据不存在');
+        MessageModel::edit($data, $id);
+        return JsonService::successful('修改成功!');
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return JsonService
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        ($field == '' || $id == '' || $value == '') && JsonService::fail('缺少参数');
+        $message = MessageModel::where('id', $id)->find();
+        if ($field == 'is_wechat' && $value == 1 && $message['tempkey'] == '') {
+            return JsonService::fail('微信模板编号不能为空');
+        }
+        if ($field == 'is_sms' && $value == 1 && $message['temp_id'] == '') {
+            return JsonService::fail('短信模板ID不能为空');
+        }
+        $res = MessageModel::where('id', $id)->update([$field => $value]);
+        if ($res)
+            return JsonService::successful('保存成功');
+        else
+            return JsonService::fail('保存失败');
+    }
+
+    /**
+     * 删除讲师
+     * @param int $id 修改的主键
+     * @return json
+     * */
+    public function delete($id = 0)
+    {
+        if (!$id) return JsonService::fail('缺少参数');
+        if (MessageModel::del($id))
+            return JsonService::successful('删除成功');
+        else
+            return JsonService::fail(MessageModel::getErrorInfo('删除失败'));
+    }
+}

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

xqd
@@ -0,0 +1,146 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\setting
+ */
+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'), 2);
+        $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)), 2);
+        $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();
+    }
+}

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

xqd
@@ -0,0 +1,745 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\express\storage\Express;
+use service\SystemConfigService;
+use app\admin\model\system\SmsAccessToken;
+use app\admin\model\system\Express as ExpressModel;
+
+/**
+ * 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->expressHandle = new Express();
+        $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::getMore([
+            ['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'];
+            if ($type == 'expr_query') {
+                $express = ExpressModel::expressList();
+                $express = array_combine(array_column($express, 'code'), $express);
+                foreach ($result['data'] as $key => $value) {
+                    $result['data'][$key]['name'] = $express[$value['content']['com']]['name'] ?? '';
+                    $result['data'][$key]['num'] = $value['content']['num'] ?? '';
+                    $result['data'][$key]['code'] = $value['content']['com'] ?? '';
+                }
+            }
+        }
+        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('申请成功');
+        }
+    }
+
+    /**
+     * 开通物流服务页面
+     * @return string
+     * @throws \Exception
+     */
+    public function express_open()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 处理开通物流服务
+     */
+    public function go_express_open()
+    {
+        return Json::successful('开通成功', $this->expressHandle->open());
+    }
+
+    /**
+     * 获取快递公司列表
+     */
+    public function express_list()
+    {
+        [$type, $page, $limit] = parent::postMore([
+            ['sign', 1],
+            ['page', 1],
+            ['limit', 10]
+        ], null, true);
+        return Json::successful($this->expressHandle->express($type, $page, $limit));
+    }
+
+    /**
+     * 获取电子面单模版
+     */
+    public function express_temp()
+    {
+        [$com, $page, $limit] = parent::postMore([
+            ['com', 0],
+            ['page', 1],
+            ['limit', 10]
+        ], null, true);
+        if (!$com) {
+            return Json::fail('请选择快递');
+        }
+        return Json::successful($this->expressHandle->temp($com, $page, $limit));
+    }
+}

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

xqd
@@ -0,0 +1,143 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 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

xqd
@@ -0,0 +1,149 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 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

xqd
@@ -0,0 +1,176 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 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_id', 0],
+            ['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,id 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('缺少参数');
+        $res =parent::getDataModification('grade',$id,$field,$value);
+        if ($res)
+            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 =parent::getDataModification('grade',$id,'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'] && !$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('请先删除下级分类');
+        $res =parent::getDataModification('grade',$id,'is_del',1);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+}

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

xqd
@@ -0,0 +1,461 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\system\WebRecommend;
+use app\admin\model\system\WebRecommendRelation;
+use app\admin\model\system\Recommend;
+use app\admin\model\system\RecommendRelation;
+use app\admin\model\special\Lecturer as LecturerModel;
+use app\admin\model\merchant\Merchant as MerchantModel;
+use app\admin\model\merchant\MerchantAdmin as MerchantAdminModel;
+use app\merchant\model\merchant\MerchantMenus;
+use app\admin\model\user\User;
+use service\JsonService;
+use service\FormBuilder as Form;
+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', []],
+            ['phone', ''],
+            ['explain', ''],
+            ['introduction', ''],
+            ['sort', 0],
+            ['is_show', 1],
+        ]);
+        $data['lecturer_name'] = preg_replace("#(^( |\s)+|( |\s)+$)#", "", $data['lecturer_name']);
+        if (!$data['lecturer_name']) return JsonService::fail('请输入讲师名称');
+        if (mb_strlen($data['lecturer_name']) > 8) return JsonService::fail('讲师名称不能超过8个字');
+        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::be(['lecturer_name' => $data['lecturer_name'], 'lecturer_head' => $data['lecturer_head'], 'label' => $data['label'], 'phone' => $data['phone'], 'is_del' => 0])) {
+                $res = LecturerModel::set($data);
+            } else {
+                return JsonService::fail('讲师已存在');
+            }
+            if ($res)
+                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 = parent::getDataModification('lecturer', $id, 'is_show', (int)$is_show);
+        if ($res) {
+            $mer_id = LecturerModel::where('id', $id)->value('mer_id');
+            if ($mer_id) {
+                $data['estate'] = $is_show;
+                MerchantModel::edit($data, $mer_id, 'id');
+            }
+            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('缺少参数');
+        $res = parent::getDataModification('lecturer', $id, $field, $value);
+        if ($res)
+            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);
+    }
+
+    /**
+     * 添加推荐
+     * @param int $special_id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function web_recommend($lecturer_id = 0)
+    {
+        if (!$lecturer_id) $this->failed('缺少参数');
+        $lecturer = LecturerModel::get($lecturer_id);
+        if (!$lecturer) $this->failed('没有查到此讲师');
+        if ($lecturer->is_del) $this->failed('此讲师已删除');
+        $form = Form::create(Url::build('save_web_recommend', ['lecturer_id' => $lecturer_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () {
+                $model = WebRecommend::where(['is_show' => 1, 'type' => 2]);
+                $list = $model->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_web_recommend($lecturer_id = 0)
+    {
+        if (!$lecturer_id) $this->failed('缺少参数');
+        $data = parent::postMore([
+            ['recommend_id', 0],
+            ['sort', 0],
+        ]);
+        if (!$data['recommend_id']) return JsonService::fail('请选择推荐');
+        $recommend = WebRecommend::get($data['recommend_id']);
+        if (!$recommend) return JsonService::fail('导航菜单不存在');
+        $data['add_time'] = time();
+        $data['type'] = $recommend->type;
+        $data['link_id'] = $lecturer_id;
+        if (WebRecommendRelation::be(['type' => $recommend->type, 'link_id' => $lecturer_id, 'recommend_id' => $data['recommend_id']])) return JsonService::fail('已推荐,请勿重复推荐');
+        if (WebRecommendRelation::set($data))
+            return JsonService::successful('推荐成功');
+        else
+            return JsonService::fail('推荐失败');
+    }
+
+    /**取消推荐
+     * @param int $id
+     */
+    public function cancel_web_recommendation($id = 0, $lecturer_id = 0)
+    {
+        if (!$id || !$lecturer_id) return JsonService::fail('缺少参数');
+        if (WebRecommendRelation::be(['id' => $id, 'link_id' => $lecturer_id])) {
+            $res = WebRecommendRelation::where(['id' => $id, 'link_id' => $lecturer_id])->delete();
+            if ($res)
+                return JsonService::successful('取消推荐成功');
+            else
+                return JsonService::fail('取消推荐失败');
+        } else {
+            return JsonService::fail('推荐不存在');
+        }
+    }
+
+    /**
+     * 添加推荐
+     * @param int $special_id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function recommend($lecturer_id = 0)
+    {
+        if (!$lecturer_id) $this->failed('缺少参数');
+        $lecturer = LecturerModel::get($lecturer_id);
+        if (!$lecturer) $this->failed('没有查到此讲师');
+        if ($lecturer->is_del) $this->failed('此讲师已删除');
+        $form = Form::create(Url::build('save_recommend', ['lecturer_id' => $lecturer_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () {
+                $model = Recommend::where(['is_show' => 1, 'type' => 6]);
+                $list = $model->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($lecturer_id = 0)
+    {
+        if (!$lecturer_id) $this->failed('缺少参数');
+        $data = parent::postMore([
+            ['recommend_id', 0],
+            ['sort', 0],
+        ]);
+        if (!$data['recommend_id']) return JsonService::fail('请选择推荐');
+        $recommend = Recommend::get($data['recommend_id']);
+        if (!$recommend) return JsonService::fail('导航菜单不存在');
+        $data['add_time'] = time();
+        $data['type'] = $recommend->type;
+        $data['link_id'] = $lecturer_id;
+        if (RecommendRelation::be(['type' => $recommend->type, 'link_id' => $lecturer_id, 'recommend_id' => $data['recommend_id']])) return JsonService::fail('已推荐,请勿重复推荐');
+        if (RecommendRelation::set($data))
+            return JsonService::successful('推荐成功');
+        else
+            return JsonService::fail('推荐失败');
+    }
+
+    /**取消推荐
+     * @param int $id
+     */
+    public function cancel_recommendation($id = 0, $lecturer_id = 0)
+    {
+        if (!$id || !$lecturer_id) return JsonService::fail('缺少参数');
+        if (RecommendRelation::be(['id' => $id, 'link_id' => $lecturer_id])) {
+            $res = RecommendRelation::where(['id' => $id, 'link_id' => $lecturer_id])->delete();
+            if ($res)
+                return JsonService::successful('取消推荐成功');
+            else
+                return JsonService::fail('取消推荐失败');
+        } else {
+            return JsonService::fail('推荐不存在');
+        }
+    }
+
+    /**生成讲师后台
+     * @return mixed
+     */
+    public function mercreate($id)
+    {
+        $lecturer = LecturerModel::get($id);
+        $this->assign([
+            'title' => '添加讲师后台',
+            'lecturer' => json_encode($lecturer),
+            'action' => Url::build('save'),
+            'menus' => json(MerchantMenus::ruleList())->getContent()
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 添加讲师商户
+     */
+    public function save()
+    {
+        $data = parent::postMore([
+            'account',
+            ['id', 0],
+            ['uid', 0],
+            'conf_pwd',
+            'pwd',
+            'mer_name',
+            'real_name',
+            'mer_phone',
+            'mer_avatar',
+            'mer_special_divide',
+            'mer_store_divide',
+            'mer_event_divide',
+            'mer_data_divide',
+            'mer_test_divide',
+            'gold_divide',
+            'mark',
+            'mer_address',
+            ['checked_menus', [], '', 'rules'],
+            ['is_source', 0],
+            ['is_audit', 0],
+            ['status', 0]
+        ]);
+        if (!is_array($data['rules']) || !count($data['rules'])) return JsonService::fail('请选择最少一个权限');
+        $data['rules'] = implode(',', $data['rules']);
+        if (!$data['account']) return JsonService::fail('请输入讲师后台账号');
+        if (MerchantAdminModel::where('account', trim($data['account']))->where('is_del', 0)->count()) return JsonService::fail('商户账号已存在,请使用别的商户账号注册');
+        if (!$data['pwd']) return JsonService::fail('请输入讲师后台登陆密码');
+        if ($data['pwd'] != $data['conf_pwd']) return JsonService::fail('两次输入密码不想同');
+        if (!$data['mer_name']) return JsonService::fail('请输入讲师后台名称');
+        if (!$data['uid']) return JsonService::fail('请输入绑定的用户ID');
+        $user = User::where('uid', $data['uid'])->find();
+        if (!$user) {
+            return JsonService::fail('绑定的用户不存在');
+        } else {
+            if ($user['business'] == 1) {
+                return JsonService::fail('该用户已是讲师');
+            }
+        }
+        $id = $data['id'];
+        $data['pwd'] = trim(md5($data['pwd']));
+        $data['reg_time'] = time();
+        $data['add_time'] = time();
+        $data['reg_admin_id'] = $this->adminId;
+        $data['lecturer_id'] = $id;
+        $data['estate'] = 1;
+        $admin = array();
+        $admin['account'] = trim($data['account']);
+        $admin['pwd'] = $data['pwd'];
+        unset($data['id']);
+        unset($data['conf_pwd']);
+        unset($data['account']);
+        unset($data['pwd']);
+        MerchantModel::beginTrans();
+        $res = MerchantModel::set($data);
+        $res1 = false;
+        if ($res) {
+            $admin['uid'] = $data['uid'];
+            $admin['mer_id'] = $res->id;
+            $admin['real_name'] = $data['mer_name'];
+            $admin['rules'] = $data['rules'];
+            $admin['phone'] = $data['mer_phone'];
+            $admin['add_time'] = time();
+            $admin['status'] = 1;
+            $admin['level'] = 0;
+            $res1 = MerchantAdminModel::set($admin);
+        }
+        $bool = false;
+        if ($res1 && $res) $bool = true;
+        MerchantModel::checkTrans($bool);
+        if ($bool) {
+            LecturerModel::where('id', $id)->update(['mer_id' => $res->id, 'phone' => $data['mer_phone']]);
+            Special::where('lecturer_id', $id)->update(['mer_id' => $res->id]);
+            User::where('uid', $data['uid'])->update(['business' => 1]);
+            return JsonService::successful('添加讲师后台成功!');
+        } else {
+            return JsonService::successful('添加讲师后台失败!');
+        }
+
+    }
+}

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

xqd
@@ -0,0 +1,176 @@
+<?php
+
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 traits\CurdControllerTrait;
+use service\JsonService as Json;
+use service\UploadService as Upload;
+use think\Request;
+use app\admin\model\special\SpecialReply as SpecialReplyModel;
+use app\admin\model\special\Special;
+use think\Url;
+
+/**
+ * 评论管理 控制器
+ * Class SpecialReply
+ * @package app\admin\controller\special
+ */
+class SpecialReply extends AuthController
+{
+
+    use CurdControllerTrait;
+
+    /**
+     * 显示资源列表
+     * @return \think\Response
+     */
+    public function index($special_id = 0)
+    {
+        $this->assign('special_id', $special_id);
+        return $this->fetch();
+    }
+
+    /**
+     * 评论列表
+     */
+    public function getSpecialReplyList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['special_name', ''],
+            ['is_reply', ''],
+            ['special_id', 0],
+            ['title', ''],
+            ['comment', '']
+        ], $this->request);
+        return Json::successlayui(SpecialReplyModel::specialReplyList($where));
+    }
+
+    /**
+     * @param $id
+     * @return \think\response\Json|void
+     */
+    public function delete($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $data['is_del'] = 1;
+        if (!SpecialReplyModel::edit($data, $id))
+            return Json::fail(SpecialReplyModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+    /**评论回复
+     * @param Request $request
+     */
+    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'] = 1;
+        $res = SpecialReplyModel::edit($save, $data['id']);
+        if (!$res)
+            return Json::fail(SpecialReplyModel::getErrorInfo('回复失败,请稍候再试!'));
+        else
+            return Json::successful('回复成功!');
+    }
+
+    /**回复加精
+     * @param int $id
+     */
+    public function refining_reply($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $save['is_selected'] = 1;
+        $res = SpecialReplyModel::edit($save, $id);
+        if (!$res)
+            return Json::fail(SpecialReplyModel::getErrorInfo('加精失败,请稍候再试!'));
+        else
+            return Json::successful('加精成功!');
+    }
+
+    /**
+     * 创建虚拟评论
+     *
+     * */
+    public function create_false()
+    {
+        $this->assign('list', Special::PreWhere()->field('id,title')->select());
+        return $this->fetch();
+    }
+
+    /**
+     * 提交虚拟评论
+     */
+    public function save_false()
+    {
+        $data = parent::postMore([
+            ['nickname', 0],
+            ['avatar', ''],
+            ['special_id', 0],
+            ['satisfied_score', 1],
+            ['comment', ''],
+            ['pics', []]
+        ]);
+        $data['type'] = 0;
+        $special_id = $data['special_id'];
+        $banner = [];
+        foreach ($data['pics'] as $item) {
+            $banner[] = $item['pic'];
+        }
+        if (!$data['nickname']) return Json::fail('请输入昵称');
+        if (!$data['avatar']) return Json::fail('请上传头像');
+        if (!$data['special_id']) return Json::fail('请选择专题');
+        if (!$data['comment']) return Json::fail('请编辑评论内容');
+        $res = SpecialReplyModel::helpeFalse($data, $banner);
+        if ($res === false)
+            return Json::fail(SpecialReplyModel::getErrorInfo());
+        else {
+            SpecialReplyModel::uodateScore($special_id);
+            return Json::successful('虚拟评论成功');
+        }
+    }
+
+    public function specialList()
+    {
+        $list = Special::PreWhere()->where('type', 'not in', 4)->field('id,title')->select();
+        return Json::successful($list);
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        if (!$field || !$id || $value == '') Json::fail('缺少参数3');
+
+        $res = SpecialReplyModel::where('id', $id)->update([$field => $value]);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+}

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

xqd
@@ -0,0 +1,145 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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;
+use app\admin\model\special\SpecialTask;
+
+/**
+ * 素材分类控制器
+ * Class SpecialTaskCategory
+ * @package app\admin\controller\special
+ */
+class SpecialTaskCategory extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    /**
+     * 素材列表
+     */
+    public function get_category_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', 0],
+            ['cate_name', ''],
+        ]);
+        return Json::successful(SpecialTaskCategoryModel::getAllList($where));
+    }
+
+    /**
+     * 创建分类
+     * @param int $id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0)
+    {
+        $cate = $id > 0 ? SpecialTaskCategoryModel::get($id) : [];
+        $this->assign(['cate' => json_encode($cate), 'id' => $id]);
+        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, 'mer_id' => 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('缺少参数');
+        $res = parent::getDataModification('task_category', $id, $field, $value);
+        if ($res)
+            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) {
+            $cate = SpecialTaskCategoryModel::get($id);
+            if (!$cate['pid'] && $post['pid'] && SpecialTaskCategoryModel::be(['pid' => $id, 'mer_id' => 0, 'is_del' => 0])) return Json::fail('无法移动有下级的分类');
+            if (SpecialTaskCategoryModel::where(['title' => $post['title'], 'mer_id' => 0, 'is_del' => 0])->where('id', '<>', $id)->count() >= 1) return Json::fail('分类名称已存在');
+            $res = SpecialTaskCategoryModel::edit($post, $id);
+            if ($res)
+                return Json::successful('修改成功');
+            else
+                return Json::fail('修改失败');
+        } else {
+            $post['add_time'] = time();
+            $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('缺少参数');
+        $cate = SpecialTaskCategoryModel::get($id);
+        if (!$cate['pid']) {
+            $count = SpecialTaskCategoryModel::where('pid', $id)->where('is_del', 0)->count();
+            if ($count) return Json::fail('暂无法删除,请删除下级分类');
+        }
+        if (SpecialTask::where('pid', $id)->where('is_del', 0)->count()) return Json::fail('暂无法删除,请先去除素材');
+        $res = parent::getDataModification('task_category', $id, 'is_del', 1);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+}

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

xqd
@@ -0,0 +1,1995 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\Special as SpecialModel;
+use app\admin\model\special\Special;
+use app\admin\model\special\SpecialBuy;
+use app\admin\model\special\Lecturer as LecturerModel;
+use app\admin\model\special\SpecialContent;
+use app\admin\model\special\SpecialSource;
+use app\admin\model\special\SpecialSubject;
+use app\admin\model\special\SpecialTask;
+use app\admin\model\special\SpecialWatch;
+use app\admin\model\special\LearningRecords;
+use app\admin\model\system\Recommend;
+use app\admin\model\system\WebRecommend;
+use app\admin\model\system\RecommendRelation;
+use app\admin\model\system\WebRecommendRelation;
+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;
+use app\admin\model\merchant\Merchant;
+use app\admin\model\questions\Certificate;
+use app\admin\model\questions\CertificateRelated;
+use app\admin\model\questions\Relation;
+use app\admin\model\questions\TestPaper;
+use app\admin\model\download\DataDownload;
+
+/**课程管理-图文专题控制器
+ * Class SpecialType
+ * @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()
+    {
+        $special_type = $this->request->param('special_type');
+        if (!$special_type) echo "<script>top.location.reload();</script>";
+        $subjectlist = SpecialSubject::specialCategoryAll();
+        $mer_list = Merchant::getMerchantList();
+        $this->assign([
+            'special_title' => SPECIAL_TYPE[$special_type],
+            'special_type' => $special_type,
+            'subject_list' => $subjectlist,
+            'mer_list' => $mer_list
+        ]);
+        $template = $this->switch_template($special_type, request()->action());
+        if (!$template) $template = "";
+        return $this->fetch($template);
+    }
+
+    public function groupList()
+    {
+        $subjectlist = SpecialSubject::specialCategoryAll();
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['subject_list' => $subjectlist, 'mer_list' => $mer_list]);
+        return $this->fetch('special/group_list/index');
+    }
+
+    /**
+     * 专题拼团列表
+     */
+    public function pink_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['subject_id', 0],
+            ['mer_id', 0],
+            ['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],
+            ['mer_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));
+    }
+
+    /**专题审核
+     * @return mixed
+     */
+    public function examine()
+    {
+        $subjectlist = SpecialSubject::specialCategoryAll();
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['subject_list' => $subjectlist, 'mer_list' => $mer_list]);
+        return $this->fetch('special/special_examine/index');
+    }
+
+    /**
+     * 获取专题审核列表数据
+     */
+    public function specialExamineList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['subject_id', 0],
+            ['mer_id', 0],
+            ['type', ''],
+            ['status', ''],
+            ['store_name', ''],
+            ['start_time', ''],
+            ['end_time', '']
+        ]);
+        return Json::successlayui(SpecialModel::getSpecialExamineList($where));
+    }
+
+    /**不通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function fail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!SpecialModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $special = SpecialModel::get($id);
+        if (!$special) return Json::fail('操作记录不存!');
+        if ($special->status != 0) return Json::fail('您已审核,请勿重复操作');
+        SpecialModel::beginTrans();
+        $res = SpecialModel::changeFail($id, $special['mer_id'], $fail_msg['message']);
+        if ($res) {
+            SpecialModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            SpecialModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    /**通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function succ($id)
+    {
+        if (!SpecialModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $special = SpecialModel::get($id);
+        if (!$special) return Json::fail('操作记录不存!');
+        if ($special->status != 0) return Json::fail('您已审核,请勿重复操作');
+        SpecialModel::beginTrans();
+        $res = SpecialModel::changeSuccess($id, $special['mer_id']);
+        if ($res) {
+            SpecialModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            SpecialModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    public function examineDetails($id, $special_type)
+    {
+        if (!$id) return Json::fail('参数错误');
+        if ($special_type < 6) {
+            $special = SpecialModel::getOne($id, $special_type == SPECIAL_LIVE ? $special_type : 0);
+            list($specialInfo, $liveInfo) = $special;
+        } else {
+            $specialInfo = SpecialModel::getsingleOne($id);
+            $liveInfo = [];
+        }
+        if (!$specialInfo) return Json::fail('专题不存在');
+        $this->assign(['liveInfo' => json_encode($liveInfo), 'special' => json_encode($specialInfo)]);
+        return $this->fetch('special/special_examine/special');
+    }
+
+    /**获取单个素材内容
+     * @param int $id
+     * @param int $special_id
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function getSources($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $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);
+        $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([
+            'id' => $id,
+            'special' => $task,
+            'alicloud_account_id' => $alicloud_account_id,
+            'configuration_item_region' => $configuration_item_region,
+            'demand_switch' => $demand_switch
+        ]);
+        return $this->fetch('special/special_examine/source');
+    }
+
+
+    /**轻专题添加
+     * @param int $id
+     */
+    public function single_add($id = 0)
+    {
+        $special_type = $this->request->param('special_type');
+        if ($id) {
+            $special = SpecialModel::getsingleOne($id);
+            if (!$special) return Json::fail('专题不存在');
+            $this->assign(['special' => json_encode($special)]);
+        }
+        $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(['id' => $id, 'special_type' => $special_type, 'alicloud_account_id' => $alicloud_account_id, 'configuration_item_region' => $configuration_item_region, 'demand_switch' => $demand_switch]);
+        return $this->fetch('special/special_single/add');
+    }
+
+    /**保存、编辑轻专题
+     * @param int $id
+     */
+    public function save_single_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],
+            ['light_type', 0],
+            ['is_mer_visible', 0],
+            ['validity', 0],
+            ['label', []],
+            ['image', ''],
+            ['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', ''],
+            ['phrase', ''],
+            ['is_fake_pink', 0],
+            ['sort', 0],
+            ['fake_pink_number', 0],
+            ['member_money', 0],
+            ['member_pay_type', 0],
+            ['pay_type', 0],//支付方式:免费、付费、密码
+            ['is_try', 1],
+            ['try_content', ''],
+            ['try_time', 0],
+            ['link', ''],
+            ['videoId', ''],
+            ['file_type', ''],
+            ['file_name', ''],
+            ['is_alone', 0],
+            ['brokerage_ratio', 0],
+            ['brokerage_two', 0]
+        ]);
+
+        if (!$data['subject_id']) return Json::fail('请选择分类');
+        if (!$data['title']) return Json::fail('请输入专题标题');
+        if (!$data['abstract']) return Json::fail('请输入专题简介');
+        if (!count($data['label'])) return Json::fail('请输填写标签');
+        if (!$data['image']) return Json::fail('请上传专题封面图');
+        if (!$data['poster_image']) return Json::fail('请上传推广海报');
+        if ($data['validity'] < 0) return Json::fail('专题有效期不能小于0');
+        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;
+            $data['is_alone'] = 0;
+            $data['brokerage_ratio'] = 0;
+            $data['brokerage_two'] = 0;
+            $data['is_try'] = 0;
+            $data['try_content'] = '';
+            $data['try_time'] = 0;
+        }
+        if ($data['is_alone'] && bcadd($data['brokerage_ratio'], $data['brokerage_two'], 2) > 100) return Json::fail('两级返佣比例之和不能大于100');
+        if ($data['member_pay_type'] != MEMBER_PAY_MONEY) {
+            $data['member_money'] = 0;
+        }
+        $data['pink_strar_time'] = strtotime($data['pink_strar_time']);
+        $data['pink_end_time'] = strtotime($data['pink_end_time']);
+        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 (bcsub($data['pink_end_time'], $data['pink_strar_time'], 0) <= 0) 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('虚拟拼团比例未填写或者比例非法');
+            $times = bcsub($data['pink_end_time'], $data['pink_strar_time'], 0);
+            $pink_time = bcmul($data['pink_time'], 3600, 0);
+            if ($pink_time > $times) return Json::fail('拼团时效不能大于拼团活动区间时间');
+        }
+        $data['label'] = json_encode($data['label']);
+        $content = htmlspecialchars($data['content']);
+        $link = '';
+        $videoId = '';
+        $file_type = '';
+        $file_name = '';
+        if ($data['videoId'] && $data['light_type'] != 1) {
+            $content = '';
+            $videoId = $data['videoId'];
+            $file_type = $data['file_type'];
+            $file_name = $data['file_name'];
+        } else if ($data['light_type'] != 1 && $data['link'] && $data['videoId'] == '') {
+            $link = $data['link'];
+        }
+        if ($data['is_try']) {
+            if ($data['light_type'] > 1) {
+                $try_content = '';
+                $try_time = $data['try_time'];
+            } else {
+                $try_time = 0;
+                $try_content = $data['try_content'];
+            }
+        } else {
+            $try_content = '';
+            $try_time = 0;
+        }
+        $is_try = $data['is_try'];
+        SpecialModel::beginTrans();
+        try {
+            unset($data['content']);
+            unset($data['link']);
+            unset($data['is_try']);
+            unset($data['try_time']);
+            unset($data['try_content']);
+            unset($data['videoId']);
+            unset($data['file_type']);
+            unset($data['file_name']);
+            if ($id) {
+                SpecialModel::update($data, ['id' => $id]);
+                SpecialContent::update(['content' => $content, 'is_try' => $is_try, 'try_time' => $try_time, 'try_content' => $try_content, 'link' => $link, 'videoId' => $videoId, 'file_type' => $file_type, 'file_name' => $file_name], ['special_id' => $id]);
+                SpecialModel::commitTrans();
+                return Json::successful('修改成功');
+            } else {
+                $data['add_time'] = time();
+                $data['is_light'] = 1;
+                $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, 'is_try' => $is_try, 'try_time' => $try_time, 'try_content' => $try_content, 'link' => $link, 'videoId' => $videoId, 'file_type' => $file_type, 'file_name' => $file_name, 'add_time' => time()]);
+                if ($res1 && $res2) {
+                    SpecialModel::commitTrans();
+                    return Json::successful('添加成功');
+                } else {
+                    SpecialModel::rollbackTrans();
+                    return Json::fail('添加失败');
+                }
+            }
+        } catch (\Exception $e) {
+            SpecialModel::rollbackTrans();
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    /**
+     * 添加页面
+     * @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) return Json::fail('专题不存在');
+            list($specialInfo, $liveInfo) = $special;
+            $this->assign(['liveInfo' => json_encode($liveInfo), 'special' => json_encode($specialInfo)]);
+        }
+        $this->assign(['id' => $id, 'special_type' => $special_type]);
+        $template = $this->switch_template($special_type, request()->action());
+        if (!$template) $template = "";
+        return $this->fetch($template);
+    }
+
+    /**查看专题关联的素材
+     * @param int $id
+     */
+    public function source_material($id = 0, $special_type = 1, $order = 0)
+    {
+        $this->assign(['id' => $id, 'special_type' => $special_type, 'order' => $order]);
+        return $this->fetch('special/task/source_material');
+    }
+
+    /**获得已关联的素材
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function get_source_sure_list($id, $order = 0)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20]
+        ]);
+        $list = SpecialSource::getSpecialSourceList($id, $where['page'], $where['limit'], $order);
+        return Json::successlayui($list);
+    }
+
+    /**素材排序
+     * @param $id
+     * @param $value
+     */
+    public function update_source_sure($id, $value, $field = '')
+    {
+        if (!$id) return Json::fail('参数错误');
+        $res = SpecialSource::where('id', $id)->update([$field => $value]);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**素材排序
+     * @param $id
+     * @param $value
+     */
+    public function del_source_sure($id, $special_id)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $res = SpecialSource::where('id', $id)->delete();
+        if ($res) {
+            SpecialModel::where('id', $special_id)->setDec('quantity', 1);
+            return Json::successful('删除成功');
+        } else
+            return Json::fail('删除失败');
+    }
+
+    /**添加素材
+     * @param int $id
+     * @param string $ids
+     */
+    public function add_source_sure($id = 0, $ids = '', $special_type = 1)
+    {
+        if (!$id || !$ids) return Json::fail('参数错误');
+        $res = SpecialSource::addSpecialSource($ids, $id, $special_type);
+        if ($res)
+            return Json::successful('添加成功');
+        else
+            return Json::fail('添加失败');
+    }
+
+    /**查看专题关联的素材
+     * @param int $id
+     */
+    public function special_material($id = 0, $special_type = 1, $order = 0)
+    {
+        $this->assign(['id' => $id, 'order' => $order, 'special_type' => $special_type]);
+        return $this->fetch('special/task/special_material');
+    }
+
+    /**获得专栏已关联的专题
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function get_special_sure_list($id, $order = 0)
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20]
+        ]);
+        $data = SpecialSource::getSpecialList($id, $where['page'], $where['limit'], $order);
+        foreach ($data['data'] as $k => &$v) {
+            if ($v['type'] == 6) $v['type'] = $v['light_type'];
+            $v['types'] = parent::specialTaskType($v['type']);
+        }
+        return Json::successlayui($data);
+    }
+
+    /**获取编辑数据
+     * @param $id
+     * @param $special_type
+     * @throws Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function get_check_source_sure($id, $special_type)
+    {
+        if (!$id) {
+            $data['sourceCheckList'] = [];
+            $data['storeCheckList'] = [];
+        } else {
+            $special = SpecialModel::get($id);
+            if (!$special) return Json::fail('专题不存在');
+            if ($special_type != SPECIAL_LIVE) {
+                $specialSourceId = SpecialSource::getSpecialSource($id, false, $special->sort_order);
+                $specialSourceId = count($specialSourceId) > 0 ? $specialSourceId->toArray() : [];
+                $sourceCheckList = [];
+                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);
+            }
+            $data['sourceCheckList'] = $sourceCheckList;
+            $data['storeCheckList'] = $storeCheckList;
+        }
+        return Json::successful($data);
+    }
+
+    /**
+     * 素材页面渲染
+     * @return
+     * */
+    public function source_index()
+    {
+        $special_type = $this->request->param('special_type');
+        $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('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' => SpecialTaskCategory::taskCategoryAll()]);
+        return $this->fetch('special/task/source_index');
+    }
+
+    /**收费专题
+     * @param int $id
+     */
+    public function is_pay_status_c($id = 0)
+    {
+        $this->assign('source_id', $id);
+        return $this->fetch('special/task/special_pay');
+    }
+
+    /**
+     * @param int $source_id
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function is_pay_source_list($source_id = 0)
+    {
+        $special_id = SpecialSource::where(['source_id' => $source_id, 'pay_status' => 1])->where('type', 'in', [1, 2, 3])->column('special_id');
+        $special = SpecialModel::where('id', 'in', $special_id)->field('id,title,image')->select();
+        $special = count($special) > 0 ? $special->toArray() : [];
+        return Json::successlayui(count($special), $special);
+    }
+
+    /**
+     * 后台素材列表
+     */
+    public function get_source_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['is_show', ''],
+            ['limit', 20],
+            ['title', ''],
+            ['pid', ''],
+            ['type', ''],
+            ['order', ''],
+        ]);
+        $special_task = SpecialTask::getTaskList($where);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                $special_task['data'][$k]['use'] = SpecialSource::where(['source_id' => $v['id']])->where('type', 'in', [1, 2, 3])->count();
+                $special_task['data'][$k]['is_pay_status'] = SpecialSource::where(['source_id' => $v['id'], 'pay_status' => 1])->count();
+                $special_task['data'][$k]['recommend'] = RecommendRelation::where('a.link_id', $v['id'])->where('a.type', 'in', [10])->alias('a')
+                    ->join('__RECOMMEND__ r', 'a.recommend_id=r.id')->column('a.id,r.title');
+                $special_task['data'][$k]['types'] = parent::specialTaskType($v['type']);
+            }
+        }
+        return Json::successlayui($special_task);
+    }
+
+    /**
+     * 图文、音频、视频、专栏专题素材列表获取
+     * @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 = [];
+        if (isset($where['special_id']) && $where['special_id'] && $where['special_type'] == SPECIAL_SEVEN) {
+            $special_source = Relation::setWhere(3, $where['special_id'])->column('relation_id');
+        }
+        if (isset($where['special_id']) && $where['special_id'] && $where['special_type'] == SPECIAL_STORE) {
+            $special_source = Relation::setWhere(5, $where['special_id'])->column('relation_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])->column('special_id');
+        } else if (isset($where['special_id']) && $where['special_id'] && in_array($where['special_type'], [SPECIAL_IMAGE_TEXT, SPECIAL_AUDIO, SPECIAL_VIDEO, SPECIAL_COLUMN])) {
+            $special_source = SpecialSource::where(['special_id' => $where['special_id']])->column('source_id');
+        }
+        $special_task = SpecialTask::getTaskList2($where, $special_source);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                $special_task['data'][$k]['is_check'] = 0;
+                $special_task['data'][$k]['pay_status'] = PAY_MONEY;
+                if ($v['type'] == 6) $v['type'] = $v['light_type'];
+                $special_task['data'][$k]['types'] = parent::specialTaskType($v['type']);
+            }
+        }
+        return Json::successlayui($special_task);
+    }
+
+    /**
+     * 图文、音频、视频、专栏专题素材列表获取 关联
+     * @return json
+     * */
+    public function get_relation_source_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['is_show', 1],
+            ['limit', 20],
+            ['title', ''],
+            ['pid', ''],
+            ['type', ''],
+            ['order', ''],
+            ['mer_id', 0],
+            ['special_id', 0],
+            ['special_type', 0],
+            ['check_source_sure', '']
+        ]);
+        $special_source = [];
+        if (isset($where['special_id']) && $where['special_id'] && $where['special_type'] == SPECIAL_SEVEN) {
+            $special_source = Relation::setWhere(3, $where['special_id'])->column('relation_id');
+        }
+        if (isset($where['special_id']) && $where['special_id'] && $where['special_type'] == SPECIAL_STORE) {
+            $special_source = Relation::setWhere(5, $where['special_id'])->column('relation_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])->column('special_id');
+        } else if (isset($where['special_id']) && $where['special_id'] && in_array($where['special_type'], [SPECIAL_IMAGE_TEXT, SPECIAL_AUDIO, SPECIAL_VIDEO, SPECIAL_COLUMN])) {
+            $special_source = SpecialSource::where(['special_id' => $where['special_id']])->column('source_id');
+        }
+        $special_task = SpecialModel::getRelationList($where, $special_source);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                $special_task['data'][$k]['is_check'] = 0;
+                $special_task['data'][$k]['pay_status'] = PAY_MONEY;
+                if ($v['type'] == 6) $v['type'] = $v['light_type'];
+                $special_task['data'][$k]['types'] = parent::specialTaskType($v['type']);
+            }
+        }
+        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])->column('special_id');
+        }
+        $special_task = StoreProduct::storeProductList($where, $special_source);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                $special_task['data'][$k]['is_check'] = 0;
+                $special_task['data'][$k]['LAY_CHECKED'] = false;
+            }
+        }
+        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],
+            ['special_id', 0],
+            ['pid', 0],
+            ['is_show', 1],
+            ['is_try', 1],
+            ['try_content', ''],
+            ['try_time', 0]
+        ]);
+        $special_id = $data['special_id'];
+        $data['type'] = $special_type;
+        if (!$data['title']) return Json::fail('请输入课程标题');
+        if (!$data['image']) return Json::fail('请上传封面图');
+        if ($data['is_try']) {
+            if ($special_type > 1) {
+                $data['try_content'] = '';
+            } else {
+                $data['try_time'] = 0;
+            }
+        } else {
+            $data['try_content'] = '';
+            $data['try_time'] = 0;
+        }
+        if ($id) {
+            unset($data['is_show']);
+            SpecialTask::update($data, ['id' => $id]);
+            return Json::successful('修改成功');
+        } else {
+            $data['add_time'] = time();
+            $res = SpecialTask::set($data);
+            if ($res) {
+                if ($special_id) {
+                    SpecialSource::addSpecialSource($res->id, $special_id, $special_type);
+                }
+                return Json::successful('添加成功');
+            } else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 统一添加素材
+     */
+    public function addSources($id = 0, $special_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([
+            'id' => $id,
+            'special_id' => $special_id,
+            'alicloud_account_id' => $alicloud_account_id,
+            'configuration_item_region' => $configuration_item_region,
+            'demand_switch' => $demand_switch
+        ]);
+        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('排序不能为负数');
+        } else {
+            if ($field == 'is_show' && $model_type == "task") {
+                $model_source = parent::switch_model('source');
+                $count = $model_source::where('source_id', $id)->count();
+                if ($count) Json::fail('素材使用中,请先在专题中移除!');
+            }
+        }
+        $res = parent::getDataModification($model_type, $id, $field, $value);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**
+     * 编辑详情
+     * @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()
+    {
+        $subjectlist = SpecialSubject::specialCategoryAll();
+        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],
+            ['is_mer_visible', 0],
+            ['validity', 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],
+            ['sort_order', 0],
+            ['fake_pink_number', 0],
+            ['sum', 0],
+            ['member_money', 0],
+            ['member_pay_type', 0],
+            ['pay_type', 0],//支付方式:免费、付费、密码
+            ['is_alone', 0],
+            ['brokerage_ratio', 0],
+            ['brokerage_two', 0]
+        ]);
+        $data['type'] = $special_type;
+        $data['check_source_sure'] = json_decode($data['subjectIds']);
+        $data['check_store_sure'] = json_decode($data['storeIds']);
+        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 (!$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['validity'] < 0) return Json::fail('专题有效期不能小于0');
+        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;
+            $data['is_alone'] = 0;
+            $data['brokerage_ratio'] = 0;
+            $data['brokerage_two'] = 0;
+        }
+        if ($data['is_alone'] && bcadd($data['brokerage_ratio'], $data['brokerage_two'], 2) > 100) return Json::fail('两级返佣比例之和不能大于100');
+        if ($data['member_pay_type'] != MEMBER_PAY_MONEY) {
+            $data['member_money'] = 0;
+        }
+        $data['pink_strar_time'] = strtotime($data['pink_strar_time']);
+        $data['pink_end_time'] = strtotime($data['pink_end_time']);
+        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 (bcsub($data['pink_end_time'], $data['pink_strar_time'], 0) <= 0) 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('虚拟拼团比例未填写或者比例非法');
+            $times = bcsub($data['pink_end_time'], $data['pink_strar_time'], 0);
+            $pink_time = bcmul($data['pink_time'], 3600, 0);
+            if ($pink_time > $times) return Json::fail('拼团时效不能大于拼团活动区间时间');
+        }
+        $content = htmlspecialchars($data['content']);
+        $data['label'] = json_encode($data['label']);
+        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'];
+            $liveInfo['is_reminded'] = 0;
+            unset($liveInfo['live_time'], $liveInfo['password']);
+        }
+        $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['check_store_sure']);
+            $data['banner'] = json_encode($banner);
+            unset($data['content']);
+            if ($id) {
+                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) {
+                    if (count($sourceCheckList) > 0) {
+                        $save_source = LiveGoods::saveAddLiveGoods($sourceCheckList, $id, 0);
+                    } else {
+                        $save_source = LiveGoods::delLiveGoods($id, 0);
+                    }
+                    if (count($storeCheckList) > 0) {
+                        $save_store = LiveGoods::saveAddLiveGoods($storeCheckList, $id, 1);
+                    } else {
+                        $save_store = LiveGoods::delLiveGoods($id, 1);
+                    }
+                } else {
+                    if (count($sourceCheckList) > 0) {
+                        $save_source = SpecialSource::saveSpecialSource($sourceCheckList, $id, $special_type, $data);
+                    } else {
+                        $save_source = SpecialSource::delSpecialSource($id);
+                    }
+                    $save_store = true;
+                }
+                if (!$save_source || !$save_store) {
+                    SpecialModel::rollbackTrans();
+                    return Json::fail('添加失败');
+                }
+                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;
+                if (SpecialModel::be(['title' => $data['title'], 'is_show' => 1, 'is_del' => 0])) return Json::fail('该专题已存在');
+                $res1 = SpecialModel::insertGetId($data);
+                $res2 = SpecialContent::set(['special_id' => $res1, 'content' => $content, 'add_time' => time()]);
+                $res3 = true;
+                if ($special_type == SPECIAL_LIVE) {
+                    $liveInfo['special_id'] = $res1;
+                    $liveInfo['stream_name'] = LiveStudio::getliveStreamName();
+                    $liveInfo['live_image'] = $data['image'];
+                    $res3 = LiveStudio::set($liveInfo);
+                }
+                if ($special_type == SPECIAL_LIVE) {
+                    if (count($sourceCheckList) > 0) {
+                        $res4 = LiveGoods::saveAddLiveGoods($sourceCheckList, $res1, 0);
+                    } else {
+                        $res4 = LiveGoods::delLiveGoods($res1, 0);
+                    }
+                    if (count($storeCheckList) > 0) {
+                        $res5 = LiveGoods::saveAddLiveGoods($storeCheckList, $res1, 1);
+                    } else {
+                        $res5 = LiveGoods::delLiveGoods($res1, 1);
+                    }
+                } else {
+                    if (count($sourceCheckList) > 0) {
+                        $res4 = SpecialSource::saveSpecialSource($sourceCheckList, $res1, $special_type, $data);
+                    } else {
+                        $res4 = SpecialSource::delSpecialSource($res1);
+                    }
+                    $res5 = true;
+                }
+                if ($res1 && $res2 && $res3 && $res4 && $res5) {
+                    SpecialModel::commitTrans();
+                    return Json::successful('添加成功');
+                } else {
+                    SpecialModel::rollbackTrans();
+                    return Json::fail('添加失败');
+                }
+            }
+        } catch (\Exception $e) {
+            SpecialModel::rollbackTrans();
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    /**
+     * 拼团设置
+     * @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)->min(0.00),
+            Form::number('pink_number', '拼团人数', $special->pink_number)->min(0),
+            Form::number('pink_time', '拼团时效(h)', $special->pink_time ? $special->pink_time : 24)->min(0),
+            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)->min(0),
+        ];
+        $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['fake_pink_number'] < 0) return Json::fail('拼团时效不能小于0');
+        if (bcsub($data['pink_money'], 0, 2) <= 0) 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]);
+            $times = bcsub($data['pink_end_time'], $data['pink_strar_time'], 0);
+            $pink_time = bcmul($data['pink_time'], 3600, 0);
+            if ($pink_time > $times) {
+                return Json::fail('拼团时效不能大于拼团活动区间时间');
+            }
+        }
+        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 = parent::switch_model($model_type);
+        if (!$model_table) return Json::fail('缺少参数');
+        try {
+            $res_get = $model_table::get($id);
+            $model_table::beginTrans();
+            if (!$res_get) return Json::fail('删除的数据不存在');
+            if ($model_type == 'special' && $res_get) {
+                $model_source = parent::switch_model('source');
+                $res = $model_source::where('special_id', $id)->delete();
+                $res_get->where('id', $id)->update(['is_del' => 1]);
+            } else if ($model_type == 'task' && $res_get) {
+                $model_source = parent::switch_model('source');
+                $res_get->where('id', $id)->update(['is_del' => 1]);
+                $model_source::where('source_id', $id)->delete();
+            }
+            $model_table::commitTrans();
+            return Json::successful('删除成功');
+        } catch (\Exception $e) {
+            $model_table::rollbackTrans();
+            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 = parent::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('转换的数据不存在');
+            parent::getDataModification($model_type, $id, '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('此专题已删除');
+        $is_pink = $special->is_pink;
+        $form = Form::create(Url::build('save_recommend', ['special_id' => $special_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () use ($is_pink) {
+                $model = Recommend::where(['is_show' => 1, 'is_fixed' => 0]);
+                if ($is_pink) {
+                    $model = $model->where('type', 'in', [0, 8]);
+                } else {
+                    $model = $model->where('type', 0);
+                }
+                $list = $model->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 $special_id
+     * @param int $type 0=专题 1=直播
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function web_recommend($special_id = 0, $type = 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_web_recommend', ['special_id' => $special_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () use ($type) {
+                $model = WebRecommend::where(['is_show' => 1, 'type' => $type]);
+                $list = $model->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_web_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 = WebRecommend::get($data['recommend_id']);
+        if (!$recommend) return Json::fail('导航菜单不存在');
+        $data['add_time'] = time();
+        $data['type'] = $recommend->type;
+        $data['link_id'] = $special_id;
+        if (WebRecommendRelation::be(['type' => $recommend->type, 'link_id' => $special_id, 'recommend_id' => $data['recommend_id']])) return Json::fail('已推荐,请勿重复推荐');
+        if (WebRecommendRelation::set($data))
+            return Json::successful('推荐成功');
+        else
+            return Json::fail('推荐失败');
+    }
+
+    /**取消推荐
+     * @param int $id
+     */
+    public function cancel_web_recommendation($id = 0, $special_id = 0)
+    {
+        if (!$id || !$special_id) $this->failed('缺少参数');
+        if (WebRecommendRelation::be(['id' => $id, 'link_id' => $special_id])) {
+            $res = WebRecommendRelation::where(['id' => $id, 'link_id' => $special_id])->delete();
+            if ($res)
+                return Json::successful('取消推荐成功');
+            else
+                return Json::fail('取消推荐失败');
+        } else {
+            return Json::fail('推荐不存在');
+        }
+    }
+
+    /**素材推荐
+     * @param int $source_id
+     */
+    public function sourceRecommend($source_id = 0)
+    {
+        if (!$source_id) $this->failed('缺少参数');
+        $source = SpecialTask::get($source_id);
+        if (!$source) $this->failed('没有查到此素材');
+        if ($source->is_del) $this->failed('此素材已删除');
+        $form = Form::create(Url::build('save_recommend', ['special_id' => $source_id]), [
+            Form::select('recommend_id', '推荐')->setOptions(function () use ($source_id) {
+                $model = Recommend::where(['is_show' => 1, 'is_fixed' => 0, 'type' => 10]);
+                $list = $model->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 $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');
+    }
+
+    /**
+     * @param int $coures_id
+     * @return mixed
+     */
+    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', SpecialTaskCategory::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');
+        $mer_list = Merchant::getMerchantList();
+        $this->assign([
+            'mer_list' => $mer_list,
+            'coures_id' => $coures_id,
+            'special_title' => SPECIAL_TYPE[$special_type],
+            'special_type' => $special_type,
+            'activity_type' => $this->request->param('activity_type', 1),
+            'special_id' => $special_id,
+            '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');
+    }
+
+    /**
+     * 专题弹幕列表和添加
+     * */
+    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;
+            case 6:
+                return 'special/special_single/' . $template_type;
+                break;
+            default:
+                return $this->failed('没有对应模板 ');
+        }
+    }
+
+    /**关联证书
+     * @param int $id
+     */
+    public function certificate($related_id = 0)
+    {
+        if (!$related_id) return Json::fail('参数错误');
+        $certificate = CertificateRelated::where(['related' => $related_id, 'obtain' => 1])->find();
+        if ($certificate) {
+            $id = $certificate['id'];
+        } else {
+            $id = 0;
+            $certificate = [];
+        }
+        $this->assign(['related_id' => $related_id, 'id' => $id, 'certificate' => json_encode($certificate)]);
+        return $this->fetch('special/task/certificate');
+    }
+
+    /**获取对应证书
+     * @param int $obtain
+     */
+    public function certificateLists($obtain = 1)
+    {
+        $list = Certificate::where(['is_del' => 0, 'status' => 1, 'obtain' => $obtain])->order('sort desc,add_time desc')->select();
+        $list = count($list) > 0 ? $list->toArray() : [];
+        return Json::successful($list);
+    }
+
+    /**试卷关联证书
+     * @param int $id
+     * @param int $obtain
+     */
+    public function certificateRecord($id = 0, $obtain = 1)
+    {
+        $data = parent::postMore([
+            ['cid', 0],
+            ['condition', ''],
+            ['related', 0],
+            ['is_show', 0]
+        ]);
+        $data['obtain'] = $obtain;
+        $res = CertificateRelated::addCertificateRelated($data, $id);
+        if ($res) {
+            return Json::successful('关联成功');
+        } else {
+            return Json::fail('关联失败');
+        }
+    }
+
+    /**学习记录
+     * @param int $id
+     */
+    public function learningRecords($id = 0, $uid = 0)
+    {
+        $this->assign(['id' => $id, 'uid' => $uid, 'year' => getMonth('y')]);
+        return $this->fetch('special/task/learning_records');
+    }
+
+    /**学习进度
+     * @param int $id
+     */
+    public function percentage($uid = 0, $special_id = 0, $type = 0, $is_light = 0)
+    {
+        $this->assign(['special_id' => $special_id, 'uid' => $uid, 'type' => $type, 'is_light' => $is_light]);
+        return $this->fetch('special/task/percentage');
+    }
+
+    /**专题的学习记录
+     * @param $id
+     */
+    public function specialLearningRecordsList($id, $uid = 0)
+    {
+        $where = parent::getMore([
+            ['id', 0],
+            ['page', 1],
+            ['limit', 20],
+            ['excel', 0],
+            ['data', '']
+        ]);
+        $where['id'] = $where['id'] >= 0 ? $where['id'] : $id;
+        if ($uid) $where['uid'] = $uid;
+        return Json::successlayui(LearningRecords::specialLearningRecordsLists($where, $where['id']));
+    }
+
+    /**学习情况
+     * @param $special_id
+     * @param $uid
+     * @param $type
+     */
+    public static function percentageData()
+    {
+        $where = parent::getMore([
+            ['special_id', 0],
+            ['page', 1],
+            ['limit', 20],
+            ['uid', 0],
+            ['is_light', 0],
+            ['type', 0]
+        ]);
+        $data = SpecialWatch::percen_tage_specials($where);
+        return Json::successlayui($data);
+    }
+
+    /**专题关联的考试或练习
+     * @param $id
+     * @param $relationship
+     * @return mixed
+     */
+    public function testPaperRelation($id = 0, $relationship = 1)
+    {
+        $this->assign(['id' => $id, 'relationship' => $relationship]);
+        return $this->fetch('special/task/test_paper');
+    }
+
+    /**获取关联的试卷
+     * @param int $id
+     * @param int $relationship 1=练习 2=考试
+     */
+    public function getRelationTestPaperList($id = 0, $relationship = 1, $page = 1, $limit = 10)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $data = Relation::getRelationTestPaper($id, $relationship, $page, $limit);
+        return Json::successlayui($data);
+    }
+
+    /**专题关联试卷排序
+     * @param int $id
+     * @param int $data_id
+     * @param $value
+     * @param int $relationship 1=练习 2=考试 4=资料
+     */
+    public function upRelationSort($id, $data_id, $value, $relationship)
+    {
+        if (!$id || !$data_id) Json::fail('缺少参数');
+        $res = Relation::updateRelationSort($id, $data_id, $relationship, $value);
+        if ($res)
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败');
+    }
+
+    /**专题关联试卷删除
+     * @param int $id
+     * @param int $data_id
+     * @param int $relationship 1=练习 2=考试
+     */
+    public function delRelation($id, $data_id, $relationship)
+    {
+        if (!$id || !$data_id) Json::fail('缺少参数');
+        $res = Relation::delRelation($id, $data_id, $relationship);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+    /**关联试卷
+     * @param int $id
+     */
+    public function relation($id = 0, $relationship = 1)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['id' => $id, 'mer_list' => $mer_list, 'relationship' => $relationship]);
+        return $this->fetch('special/task/relation');
+    }
+
+    /**专题关联试卷、资料
+     * @param int $id
+     */
+    public function addRelation($id, $ids, $relationship)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $res = Relation::setRelations($id, $ids, $relationship);
+        if ($res)
+            return Json::successful('关联成功');
+        else
+            return Json::fail('关联失败');
+    }
+
+    /**
+     * 获取试卷列表
+     */
+    public function getTestPapersList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['special_id', 0],
+            ['relationship', 1],
+            ['status', 1],
+            ['is_show', 1],
+            ['mer_id', 0],
+            ['title', '']
+        ]);
+        $source = [];
+        if (isset($where['special_id']) && $where['special_id'] && $where['relationship']) {
+            $source = Relation::setWhere($where['relationship'], $where['special_id'])->column('relation_id');
+        }
+        switch ($where['relationship']) {
+            case 1:
+                $where['type'] = 1;
+                break;
+            case 2:
+                $where['type'] = 2;
+                break;
+        }
+        $TestPapers = TestPaper::testPaperLists($where, $source);
+        if (isset($TestPapers['data']) && $TestPapers['data']) {
+            foreach ($TestPapers['data'] as $k => $v) {
+                $TestPapers['data'][$k]['is_check'] = 0;
+            }
+        }
+        return Json::successlayui($TestPapers);
+    }
+
+    /**专题关联的资料
+     * @param $id
+     * @param $relationship
+     * @return mixed
+     */
+    public function dataDownloadRelation($id = 0, $relationship = 4)
+    {
+        $this->assign(['id' => $id, 'relationship' => $relationship]);
+        return $this->fetch('special/task/data_download');
+    }
+
+    /**获取关联的资料
+     * @param int $id
+     * @param int $relationship 4=资料
+     */
+    public function getRelationDataDownloadList($id = 0, $relationship = 4, $page = 1, $limit = 10)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $data = Relation::getRelationDataDownload($id, $relationship, $page, $limit);
+        return Json::successlayui($data);
+    }
+
+    /**关联资料
+     * @param int $id
+     */
+    public function download($id = 0, $relationship = 4)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['id' => $id, 'mer_list' => $mer_list, 'relationship' => $relationship]);
+        return $this->fetch('special/task/download');
+    }
+
+    /**
+     * 获取资料列表
+     */
+    public function getDataDownloadList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['data_id', 0],
+            ['relationship', 4],
+            ['status', 1],
+            ['is_show', 1],
+            ['mer_id', 0],
+            ['title', '']
+        ]);
+        $data = [];
+        if (isset($where['data_id']) && $where['data_id'] && $where['relationship']) {
+            $data = Relation::setWhere($where['relationship'], $where['data_id'])->column('relation_id');
+        }
+        $download = DataDownload::dataDownloadLists($where, $data);
+        if (isset($download['data']) && $download['data']) {
+            foreach ($download['data'] as $k => $v) {
+                $download['data'][$k]['is_check'] = 0;
+            }
+        }
+        return Json::successlayui($download);
+    }
+}

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

xqd
@@ -0,0 +1,165 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\Special;
+use think\Url;
+use service\FormBuilder as Form;
+use service\JsonService as Json;
+use app\admin\controller\AuthController;
+
+/**
+ * 课程分类控制器
+ * Class Subject
+ * @package app\admin\controller\special
+ */
+class Subject extends AuthController
+{
+    public function index()
+    {
+        return $this->fetch();
+    }
+
+    public function get_subject_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['pid', $this->request->param('pid', '')],
+            ['name', ''],
+        ]);
+        return Json::successful(SpecialSubject::get_subject_list($where));
+    }
+
+    /**
+     * 创建分类
+     * @param int $id
+     * @return mixed
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0)
+    {
+        $cate = $id > 0 ? SpecialSubject::get($id) : [];
+        $this->assign(['cate' => json_encode($cate), 'id' => $id]);
+        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()
+    {
+        $cate = SpecialSubject::specialCategoryAll(1);
+        $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 save($id = 0)
+    {
+        $post = parent::postMore([
+            ['name', ''],
+            ['pic', ''],
+            ['grade_id', 0],
+            ['sort', 0],
+            ['is_show', 0],
+        ]);
+        if (!$post['name']) return Json::fail('请输入分类名称');
+        if ($post['grade_id'] && !$post['pic']) return Json::fail('请选择分类图标');
+        if ($id) {
+            $cate = SpecialSubject::get($id);
+            if (!$cate['grade_id'] && $post['grade_id'] && SpecialSubject::be(['grade_id' => $id, 'is_del' => 0])) return Json::fail('无法移动有下级的分类');
+            if (SpecialSubject::where(['name' => $post['name'], 'is_del' => 0])->where('id', '<>', $id)->count() >= 1) return Json::fail('分类名称已存在');
+            $res = SpecialSubject::edit($post, $id);
+            if ($res)
+                return Json::successful('修改成功');
+            else
+                return Json::fail('修改失败');
+        } else {
+            $post['add_time'] = time();
+            if (SpecialSubject::be(['name' => $post['name'], 'is_del' => 0])) {
+                return Json::fail('分类名称已存在!');
+            }
+            $res = SpecialSubject::set($post);
+            if ($res)
+                return Json::successful('添加成功');
+            else
+                return Json::fail('添加失败');
+        }
+    }
+
+    /**
+     * 快速编辑
+     *
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        ($field == '' || $id == '' || $value == '') && Json::fail('缺少参数');
+        $res = parent::getDataModification('subject', $id, $field, $value);
+        if ($res)
+            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 = parent::getDataModification('subject', $id, '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('缺少参数');
+        $subject = SpecialSubject::get($id);
+        if ($subject['grade_id']) {
+            if (Special::where('subject_id', $id)->where('is_del', 0)->count()) return Json::fail('暂无法删除,请先去除专题关联');
+        } else {
+            if (SpecialSubject::where('grade_id', $id)->where('is_del', 0)->count()) return Json::fail('暂无法删除,请删除下级分类');
+        }
+        $res = parent::getDataModification('subject', $id, 'is_del', 1);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除成功');
+    }
+}

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

xqd
@@ -0,0 +1,194 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 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 Task
+ * @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 =parent::getDataModification('task',$id,'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('缺少参数');
+        $res =parent::getDataModification('task',$id,$field,$value);
+        if ($res)
+            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('保存失败或者您没有修改什么');
+        }
+    }
+}

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

xqd
@@ -0,0 +1,182 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\store
+ */
+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 = parent::getDataModification('store_cate', $id, '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('缺少参数');
+        $res = parent::getDataModification('store_cate', $id, $field, $value);
+        if ($res)
+            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) {
+            if (CategoryModel::where(['cate_name' => $data['cate_name']])->where('id', '<>', $id)->count() >= 1) return Json::fail('分类名称已存在');
+            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('删除成功!');
+    }
+}

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

xqd
@@ -0,0 +1,563 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\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;
+use app\admin\model\questions\Relation;
+use app\admin\model\merchant\Merchant;
+
+/**
+ * 产品管理
+ * 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());
+        $this->assign('mer_list', Merchant::getMerchantList());
+        //出售中产品
+        $onsale = ProductModel::where(['is_show' => 1, 'status' => 1, 'is_del' => 0])->count();
+        //待上架产品
+        $forsale = ProductModel::where(['is_show' => 0, 'status' => 1, 'is_del' => 0])->count();
+        //仓库中产品
+        $warehouse = ProductModel::where(['is_del' => 0, 'status' => 1])->count();
+        //已经售馨产品
+        $outofstock = ProductModel::getModelObject()->where(ProductModel::setData(4))->count();
+        //警戒库存
+        $policeforce = ProductModel::getModelObject()->where(ProductModel::setData(5))->count();
+        //回收站
+        $recycle = ProductModel::where(['is_del' => 1, 'status' => 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', ''],
+            ['mer_id', ''],
+            ['excel', 0],
+            ['status', 1],
+            ['type', $this->request->param('type')]
+        ]);
+        return Json::successlayui(ProductModel::ProductList($where));
+    }
+
+    /**商品审核
+     * @return mixed
+     */
+    public function examine()
+    {
+        $this->assign('cate', CategoryModel::getTierList());
+        $this->assign('mer_list', Merchant::getMerchantList());
+        return $this->fetch();
+    }
+
+    /**
+     * 异步查找产品
+     *
+     * @return json
+     */
+    public function product_examine_ist()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['store_name', ''],
+            ['cate_id', ''],
+            ['mer_id', ''],
+            ['status', ''],
+        ]);
+        return Json::successlayui(ProductModel::productExamineList($where));
+    }
+
+    /**不通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function fail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!ProductModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $special = ProductModel::get($id);
+        if (!$special) return Json::fail('操作记录不存!');
+        if ($special->status != 0) return Json::fail('您已审核,请勿重复操作');
+        ProductModel::beginTrans();
+        $res = ProductModel::changeFail($id, $special['mer_id'], $fail_msg['message']);
+        if ($res) {
+            ProductModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            ProductModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    /**通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function succ($id)
+    {
+        if (!ProductModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $special = ProductModel::get($id);
+        if (!$special) return Json::fail('操作记录不存!');
+        if ($special->status != 0) return Json::fail('您已审核,请勿重复操作');
+        ProductModel::beginTrans();
+        $res = ProductModel::changeSuccess($id, $special['mer_id']);
+        if ($res) {
+            ProductModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            ProductModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    public function examineDetails($id)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $details = ProductModel::get($id);
+        if (!$details) return Json::fail('商品不存在');
+        $this->assign(['details' => json_encode($details)]);
+        return $this->fetch('product');
+    }
+
+    /**
+     * 设置单个产品上架|下架
+     *
+     * @return json
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        ($is_show == '' || $id == '') && Json::fail('缺少参数');
+        $res = parent::getDataModification('product', $id, '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('缺少参数');
+        $res = parent::getDataModification('product', $id, $field, $value);
+        if ($res)
+            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();
+    }
+
+    /**商品分类
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function getCateList()
+    {
+        $list = CategoryModel::where(['is_show' => 1, 'pid' => 0])->order('sort desc,add_time desc')->select();
+        $list = count($list) > 0 ? $list->toArray() : [];
+        return Json::successful($list);
+    }
+
+    /**
+     * 保存新建的资源
+     *
+     * @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],
+            ['is_alone', 0],
+            ['brokerage_ratio', 0],
+            ['brokerage_two', 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 ($data['is_alone'] && bcadd($data['brokerage_ratio'], $data['brokerage_two'], 2) > 100) return Json::fail('两级返佣比例之和不能大于100');
+        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('推荐不存在');
+        }
+    }
+
+    /**
+     * 删除指定资源
+     *
+     * @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])) {
+            $res = parent::getDataModification('product', $id, 'is_del', 0);
+            if (!$res)
+                return Json::fail(ProductModel::getErrorInfo('恢复失败,请稍候再试!'));
+            else
+                return Json::successful('成功恢复产品!');
+        } else {
+            $res = parent::getDataModification('product', $id, 'is_del', 1);
+            if (!$res)
+                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('修改失败');
+    }
+
+    /**关联课程
+     * @param int $id
+     * @return mixed
+     */
+    public function knowledge($id = 0)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $this->assign(['id' => $id]);
+        return $this->fetch();
+    }
+
+    /**获取商品关联的专题
+     * @param int $id
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function knowledge_points($id = 0)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $data = Relation::getQuestionsRelationSpecial($id, 5);
+        foreach ($data['data'] as $k => &$v) {
+            if ($v['type'] == 6) $v['type'] = $v['light_type'];
+            $v['types'] = parent::specialTaskType($v['type']);
+        }
+        return Json::successlayui($data);
+    }
+
+    /**关联专题
+     * @param int $id
+     */
+    public function relation($id = 0)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['id' => $id,'mer_list' => $mer_list]);
+        return $this->fetch('relation');
+    }
+
+    /**商品关联课程
+     * @param int $id
+     */
+    public function add_knowledge_points($id, $special_ids)
+    {
+        if (!$id) Json::fail('缺少参数');
+        $res = Relation::setRelations($id, $special_ids, 5);
+        if ($res)
+            return Json::successful('关联成功');
+        else
+            return Json::fail('关联失败');
+    }
+
+    /**商品关联课程排序
+     * @param int $id
+     * @param int $special_id
+     * @param $value
+     */
+    public function up_knowledge_points_sort($id, $special_id, $value)
+    {
+        if (!$id || !$special_id) Json::fail('缺少参数');
+        $res = Relation::updateRelationSort($id, $special_id, 5, $value);
+        if ($res)
+            return Json::successful('修改成功');
+        else
+            return Json::fail('修改失败');
+    }
+
+    /**删除关联专题
+     * @param int $id
+     * @param int $special_id
+     * @throws \think\exception\DbException
+     */
+    public function delete_knowledge_points($id = 0, $special_id = 0)
+    {
+        if (!$id || !$special_id) Json::fail('缺少参数');
+        $res = Relation::delRelation($id, $special_id, 5);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+}

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

xqd
@@ -0,0 +1,174 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 app\admin\model\store\StoreProduct;
+use think\Url;
+
+/**
+ * 评论管理 控制器
+ * Class StoreProductReply
+ * @package app\admin\controller\store
+ */
+class StoreProductReply extends AuthController
+{
+
+    use CurdControllerTrait;
+
+    /**
+     * 显示资源列表
+     * @return \think\Response
+     */
+    public function index($product_id = 0)
+    {
+        $this->assign('product_id', $product_id);
+        return $this->fetch();
+    }
+
+    /**
+     * 评论列表
+     */
+    public function productReplyList()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['limit', 20],
+            ['store_name', ''],
+            ['is_reply', ''],
+            ['product_id', 0],
+            ['title', ''],
+            ['comment', '']
+        ], $this->request);
+        return Json::successlayui(ProductReplyModel::storeProductReplyList($where));
+    }
+
+    /**
+     * @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('删除成功!');
+    }
+
+    /**评论回复
+     * @param Request $request
+     */
+    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'] = 1;
+        $res = ProductReplyModel::edit($save, $data['id']);
+        if (!$res)
+            return Json::fail(ProductReplyModel::getErrorInfo('回复失败,请稍候再试!'));
+        else
+            return Json::successful('回复成功!');
+    }
+
+    /**回复加精
+     * @param int $id
+     */
+    public function refining_reply($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $save['is_selected'] = 1;
+        $res = ProductReplyModel::edit($save, $id);
+        if (!$res)
+            return Json::fail(ProductReplyModel::getErrorInfo('加精失败,请稍候再试!'));
+        else
+            return Json::successful('加精成功!');
+    }
+
+    /**
+     * 创建虚拟评论
+     *
+     * */
+    public function create_false()
+    {
+        $this->assign('list', StoreProduct::PreWhere()->field('id,store_name')->select());
+        return $this->fetch();
+    }
+
+    /**
+     * 提交虚拟评论
+     */
+    public function save_false()
+    {
+        $data = parent::postMore([
+            ['nickname', 0],
+            ['avatar', ''],
+            ['product_id', 0],
+            ['product_score', 1],
+            ['service_score', 1],
+            ['delivery_score', 1],
+            ['comment', ''],
+            ['pics', []]
+        ]);
+        $data['type'] = 1;
+        $banner = [];
+        foreach ($data['pics'] as $item) {
+            $banner[] = $item['pic'];
+        }
+        if (!$data['nickname']) return Json::fail('请输入昵称');
+        if (!$data['avatar']) return Json::fail('请上传头像');
+        if (!$data['product_id']) return Json::fail('请选择商品');
+        if (!$data['comment']) return Json::fail('请编辑评论内容');
+        $res = ProductReplyModel::helpeFalse($data, $banner);
+        if ($res === false)
+            return Json::fail(ProductReplyModel::getErrorInfo());
+        else
+            return Json::successful('虚拟评论成功');
+    }
+
+    public function productList()
+    {
+        $list = StoreProduct::PreWhere()->field('id,store_name')->select();
+        return Json::successful($list);
+    }
+
+    /**
+     * 快速编辑
+     * @param string $field 字段名
+     * @param int $id 修改的主键
+     * @param string value 修改后的值
+     * @return json
+     */
+    public function set_value($field = '', $id = '', $value = '')
+    {
+        if (!$field || !$id || $value == '') Json::fail('缺少参数3');
+
+        $res = ProductReplyModel::where('id', $id)->update([$field => $value]);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+}

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

xqd
@@ -0,0 +1,91 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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
+ */
+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 del_home_redis()
+    {
+        $subjectUrl = getUrlToDomain();
+        del_redis_hash($subjectUrl . "wap_index_has", "recommend_list");
+        del_redis_hash($subjectUrl . "web_index_has", "recommend_list");
+        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);
+        }
+    }
+}
+
+

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

xqd
@@ -0,0 +1,138 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 service\JsonService as Json;
+use think\Request;
+use think\Url;
+use app\admin\model\system\Express as ExpressModel;
+
+
+/**
+ * 物流公司管理控制器
+ * Class Express
+ * @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)->min(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'])->min(0),
+            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

xqd
@@ -0,0 +1,84 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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

xqd
@@ -0,0 +1,139 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 systemClear
+ */
+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('兼容失败!');
+        }
+
+    }
+}
+
+

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

xqd
@@ -0,0 +1,186 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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()
+    {
+        $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

xqd
@@ -0,0 +1,230 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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

xqd
@@ -0,0 +1,248 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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

xqd
@@ -0,0 +1,44 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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

xqd
@@ -0,0 +1,29 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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
+{
+
+}

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

xqd
@@ -0,0 +1,461 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\ump\EventPrice;
+use service\JsonService as Json;
+use think\Request;
+use think\Url;
+use app\admin\model\user\User;
+use app\admin\model\user\UserBill;
+use service\FormBuilder as Form;
+use app\admin\model\ump\EventRegistration as EventRegistrationModel;
+use app\admin\model\ump\EventSignUp as EventSignUpModel;
+use app\admin\model\ump\EventData as EventDataModel;
+use app\admin\model\ump\EventPrice as EventPriceModel;
+use app\admin\model\merchant\MerchantFlowingWater;
+use app\admin\model\merchant\Merchant;
+use service\AlipayTradeWapService;
+use behavior\wechat\PaymentBehavior;
+use service\HookService;
+
+/**活动控制器
+ * Class EventRegistration
+ * @package app\admin\controller\ump
+ */
+class EventRegistration extends AuthController
+{
+    public function index()
+    {
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['mer_list' => $mer_list]);
+        return $this->fetch();
+    }
+
+    /**
+     * 活动列表
+     */
+    public function event_registration_list()
+    {
+        $where = parent::getMore([
+            ['title', ''],
+            ['status', 1],
+            ['is_show', ''],
+            ['mer_id', ''],
+            ['page', 1],
+            ['limit', 20],
+        ], $this->request);
+        return Json::successlayui(EventRegistrationModel::systemPage($where));
+    }
+
+    /**活动审核
+     * @return mixed
+     */
+    public function examine()
+    {
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['mer_list' => $mer_list]);
+        return $this->fetch();
+    }
+
+    /**
+     * 异步查找产品
+     *
+     * @return json
+     */
+    public function event_examine_ist()
+    {
+        $where = parent::getMore([
+            ['title', ''],
+            ['page', 1],
+            ['limit', 20],
+            ['mer_id', ''],
+            ['status', ''],
+        ]);
+        return Json::successlayui(EventRegistrationModel::eventExamineList($where));
+    }
+
+    public function examineDetails($id)
+    {
+        if (!$id) return Json::fail('参数错误');
+        $details = EventRegistrationModel::get($id);
+        if (!$details) return Json::fail('活动不存在');
+        $details->activity_rules = htmlspecialchars_decode($details->activity_rules);
+        $details->content = htmlspecialchars_decode($details->content);
+        $event = EventDataModel::eventDataList($id);
+        $price = EventPriceModel::eventPriceList($id);
+        $this->assign(['details' => json_encode($details), 'event' => json_encode($event), 'price' => json_encode($price)]);
+        return $this->fetch('activity');
+    }
+
+    /**不通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function fail($id)
+    {
+        $fail_msg = parent::postMore([
+            ['message', ''],
+        ]);
+        if (!EventRegistrationModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $special = EventRegistrationModel::get($id);
+        if (!$special) return Json::fail('操作记录不存!');
+        if ($special->status != 0) return Json::fail('您已审核,请勿重复操作');
+        EventRegistrationModel::beginTrans();
+        $res = EventRegistrationModel::changeFail($id, $special['mer_id'], $fail_msg['message']);
+        if ($res) {
+            EventRegistrationModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            EventRegistrationModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    /**通过
+     * @param $id
+     * @throws \think\exception\DbException
+     */
+    public function succ($id)
+    {
+        if (!EventRegistrationModel::be(['id' => $id, 'status' => 0])) return Json::fail('操作记录不存在或状态错误!');
+        $special = EventRegistrationModel::get($id);
+        if (!$special) return Json::fail('操作记录不存!');
+        if ($special->status != 0) return Json::fail('您已审核,请勿重复操作');
+        EventRegistrationModel::beginTrans();
+        $res = EventRegistrationModel::changeSuccess($id, $special['mer_id']);
+        if ($res) {
+            EventRegistrationModel::commitTrans();
+            return Json::successful('操作成功!');
+        } else {
+            EventRegistrationModel::rollbackTrans();
+            return Json::fail('操作失败!');
+        }
+    }
+
+    /**编辑
+     * @param string $is_show
+     * @param string $id
+     */
+    public function set_show($is_show = '', $id = '')
+    {
+        if ($is_show == '' || $id == '') return Json::fail('缺少参数');
+        $res = parent::getDataModification('event', $id, 'is_show', (int)$is_show);
+        if ($res)
+            return Json::successful($is_show == 1 ? '显示成功' : '隐藏成功');
+        else
+            return Json::fail($is_show == 1 ? '显示失败' : '隐藏失败');
+    }
+
+    /**获得添加
+     * @return mixed|void
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function create($id = 0)
+    {
+        $news = [];
+        $event = [];
+        $price = [];
+        if ($id) {
+            $news = EventRegistrationModel::eventRegistrationOne($id);
+            $event = EventDataModel::eventDataList($id);
+            $price = EventPriceModel::eventPriceList($id);
+            if (!count($price)) {
+                $price[0] = [
+                    'event_id' => $id,
+                    'event_number' => 1,
+                    'event_price' => $news['price'],
+                    'event_mer_price' => $news['member_price'],
+                    'sort' => 0
+                ];
+            }
+        }
+        $this->assign(['id' => $id, 'news' => json_encode($news), 'event' => json_encode($event), 'price' => json_encode($price)]);
+        return $this->fetch();
+    }
+
+    /**
+     * 删除活动
+     * */
+    public function delete($id)
+    {
+        $res = EventRegistrationModel::delArticleCategory($id);
+        if (!$res)
+            return Json::fail(EventRegistrationModel::getErrorInfo('删除失败,请稍候再试!'));
+        else {
+            EventDataModel::delEventData($id);
+            EventPriceModel::delEventPrice($id);
+            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],
+            ['event', ''],//资料
+            ['event_price', ''],//价格
+            ['restrictions', 0],
+            ['is_fill', 1],
+            ['is_show', 0],
+            ['pay_type', 1],
+            'price',
+            ['member_pay_type', 1],
+            'member_price'
+        ]);
+        $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) return Json::fail('报名结束时间不能小于等于开始时间');
+        if (bcsub($data['start_time'], $data['signup_end_time'], 0) <= 0) return Json::fail('活动开始时间不能小于等于报名结束时间');
+        if (bcsub($data['end_time'], $data['start_time'], 0) <= 0) return Json::fail('活动结束时间不能小于等于开始时间');
+        $data['content'] = htmlspecialchars($data['content']);
+        $data['activity_rules'] = htmlspecialchars($data['activity_rules']);
+        if (isset($data['event']) && $data['event'] != '') {
+            $event = json_decode($data['event'], true);
+        } else {
+            $event = [];
+        }
+        if (isset($data['event_price']) && $data['event_price'] != '') {
+            $price = json_decode($data['event_price'], true);
+        } else {
+            $price = [];
+        }
+        $number = $data['number'];
+        if ($data['id']) {
+            $id = $data['id'];
+            unset($data['id'], $data['event'], $data['event_price']);
+            EventRegistrationModel::beginTrans();
+            $res1 = EventRegistrationModel::edit($data, $id, 'id');
+            $res2 = EventDataModel::eventDataAdd($id, $event);
+            $res3 = EventPriceModel::eventPriceAdd($id, $price, $number);
+            $res = $res1 && $res2 && $res3;
+            EventRegistrationModel::checkTrans($res);
+            if ($res) {
+                return Json::successful('修改活动成功!', $id);
+            } else
+                return Json::fail('修改活动失败,您并没有修改什么!', $id);
+        } else {
+            $data['add_time'] = time();
+            $data['statu'] = 0;
+            EventRegistrationModel::beginTrans();
+            $id = EventRegistrationModel::insertGetId($data);
+            $res2 = EventDataModel::eventDataAdd($id, $event);
+            $res3 = EventPriceModel::eventPriceAdd($id, $price, $number);
+            $res = $id && $res2 && $res3;
+            EventRegistrationModel::checkTrans($res);
+            if ($res)
+                return Json::successful('添加活动成功!', $id);
+            else
+                return Json::successful('添加活动失败!', $id);
+        }
+    }
+
+    /**
+     * 查看报名人员
+     */
+    public function viewStaff($id)
+    {
+        if (!$id) return Json::fail('参数错误!');
+        $activity = EventRegistrationModel::where('id', $id)->find();
+        if (!$activity) return Json::fail('活动不存在!');
+        $this->assign(['aid' => $id]);
+        return $this->fetch('view_staff');
+    }
+
+    /**报名订单订单
+     * @return mixed
+     */
+    public function order()
+    {
+        $this->assign([
+            'year' => getMonth('y'),
+            'orderCount' => EventSignUpModel::orderCount()
+        ]);
+        return $this->fetch();
+    }
+
+    /**
+     * 查看活动报名订单列表
+     */
+    public function get_sign_up_list()
+    {
+        $where = parent::getMore([
+            ['id', $this->request->param('id')],
+            ['page', 1],
+            ['limit', 20],
+            ['status', ''],
+            ['type', $this->request->param('type')],
+            ['real_name', ''],
+            ['data', ''],
+            ['excel', 0],
+        ]);
+        return Json::successlayui(EventSignUpModel::getUserSignUpAll($where));
+    }
+
+    /**
+     * 统计
+     */
+    public function getBadge()
+    {
+        $where = parent::postMore([
+            ['id', $this->request->param('id')],
+            ['status', ''],
+            ['type', ''],
+            ['data', ''],
+            ['real_name', '']
+        ]);
+        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, 'paid' => 1, 'is_del' => 0])->update(['status' => 1]);
+        if ($res) return Json::successful('核销成功');
+        else return Json::fail('核销失败');
+    }
+
+    /**
+     * 修改退款状态
+     * @param $id
+     * @return \think\response\Json|void
+     */
+    public function refund_y($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $product = EventSignUpModel::get($id);
+        if (!$product) return Json::fail('数据不存在!');
+        if ($product['paid'] == 1) {
+            $f = array();
+            $f[] = Form::input('order_id', '退款单号', $product->getData('order_id'))->disabled(1);
+            $f[] = Form::number('refund_price', '退款金额', $product->getData('pay_price'))->precision(2)->min(0.01);
+            $form = Form::make_post_form('退款处理', $f, Url::build('updateRefundY', array('id' => $id)), 4);
+            $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 Json::fail('数据不存在');
+        $product = EventSignUpModel::get($id);
+        if (!$product) return Json::fail('数据不存在!');
+        if ($product['pay_price'] == $product['refund_price']) return Json::fail('已退完支付金额!不能再退款了');
+        if (!$data['refund_price']) return Json::fail('请输入退款金额');
+        $refund_price = $data['refund_price'];
+        $data['refund_price'] = bcadd($data['refund_price'], $product['refund_price'], 2);
+        $bj = bccomp((float)$product['pay_price'], (float)$data['refund_price'], 2);
+        if ($bj < 0) return Json::fail('退款金额大于支付金额,请修改退款金额');
+        $data['refund_status'] = 2;
+        $refund_data['pay_price'] = $product['pay_price'];
+        $refund_data['refund_price'] = $refund_price;
+        if ($product['pay_type'] == 'weixin') {
+            try {
+                HookService::listen('wechat_pay_order_refund', $product['order_id'], $refund_data, true, PaymentBehavior::class);
+            } catch (\Exception $e) {
+                return Json::fail($e->getMessage());
+            }
+        } else if ($product['pay_type'] == 'yue') {
+            EventSignUpModel::beginTrans();
+            $res = User::bcInc($product['uid'], 'now_money', $refund_price, 'uid');
+            EventSignUpModel::checkTrans($res);
+            if (!$res) return Json::fail('余额退款失败!');
+        } else if ($product['pay_type'] == 'zhifubao') {
+            $res = AlipayTradeWapService::init()->AliPayRefund($product['order_id'], $product['trade_no'], $refund_price, '活动订单退款', 'refund');
+            if (empty($res) || $res != 10000) {
+                return Json::fail('支付宝退款失败!');
+            }
+        }
+        $data['refund_reason_time'] = time();
+        $resEdit = EventSignUpModel::edit($data, $id);
+        if ($resEdit) {
+            $pay_type = $product['pay_type'] == 'yue' ? 'now_money' : $product['pay_type'];
+            if ($product['pay_type'] == 'yue') {
+                $balance = User::where(['uid' => $product['uid']])->value('now_money');
+            } else {
+                $balance = 0;
+            }
+            UserBill::income('活动订单退款', $product['uid'], $pay_type, 'pay_sign_up_refund', $refund_price, $product['id'], $balance, '活动订单退款' . floatval($refund_price) . '元');
+            MerchantFlowingWater::orderRefund($id, $product['mer_id'], 4);
+            return Json::successful('修改成功!');
+        } else {
+            return Json::successful('修改失败!');
+        }
+    }
+
+    /**订单详情
+     * @param string $oid
+     * @return mixed|void
+     * @throws \think\exception\DbException
+     */
+    public function order_info($oid = '')
+    {
+        if (!$oid || !($orderInfo = EventSignUpModel::get($oid)))
+            return $this->failed('订单不存在!');
+        $userInfo = User::getAllUserinfo($orderInfo['uid']);
+        $this->assign(compact('orderInfo', 'userInfo'));
+        return $this->fetch();
+    }
+
+    /**订单删除
+     * @param int $id
+     */
+    public function order_delete($id = 0)
+    {
+        if (!$id) return Json::fail('参数错误!');
+        $data['is_del'] = 1;
+        EventSignUpModel::edit($data, $id);
+        return Json::successful('删除成功!');
+    }
+}
+

+ 175 - 0
application/admin/controller/ump/SpecialBatch.php

xqd
@@ -0,0 +1,175 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\ump\SpecialExchange;
+use app\admin\model\ump\SpecialBatch as SpecialBatchModel;
+use service\JsonService as Json;
+use app\admin\model\special\Special;
+
+/**
+ * 专题兑换码管理控制器
+ * Class SpecialBatch
+ * @package app\admin\controller\ump
+ */
+class SpecialBatch extends AuthController
+{
+    public function index()
+    {
+        $list = Special::PreWhere()->field('id,title')->select();
+        $this->assign(['activity_type' => 1, 'special' => $list]);
+        return $this->fetch('batch_index');
+    }
+
+    public function specialList()
+    {
+        $list = Special::PreWhere()->field('id,title')->select();
+        return Json::successful($list);
+    }
+
+    public function batch_list()
+    {
+        $where = parent::getMore([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['title', ''],
+            ['special_id', 0],
+            ['page', 1],
+            ['limit', 20]
+        ]);
+        $batch_list = SpecialBatchModel::getBatchList($where);
+        return Json::successlayui($batch_list);
+    }
+
+    public function add_batch()
+    {
+        return $this->fetch();
+    }
+
+    public function save_batch()
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['special_id', 0],
+            ['total_num', 1],
+            ['status', 0],
+            ['remark', '']
+        ]);
+        if (!isset($data['special_id']) || $data['special_id'] <= 0 || !is_numeric($data['special_id'])) 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 {
+            SpecialBatchModel::beginTrans();
+            $special_id = $data['special_id'];
+            $data['add_time'] = time();
+            $batch_id = SpecialBatchModel::addBatch($data);
+            $batch_card = SpecialExchange::addCard($batch_id, $data['total_num'], $special_id);
+            if ($batch_id && $batch_card) {
+                $qrcodeUrl = SpecialExchange::qrcodes_url($special_id, 5);
+                SpecialBatchModel::where('id', $batch_id)->update(['qrcode' => $qrcodeUrl]);
+            }
+            SpecialBatchModel::commitTrans();
+            return Json::successful('添加成功');
+        } catch (\Exception $e) {
+            SpecialBatchModel::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 ($model_type == 'special_batch' && $field != 'remark') {
+            $use = SpecialExchange::where('card_batch_id', $id)->where('use_uid', '>', 0)->count();
+            if ($use) return Json::fail('此批次卡片已经在使用当中,无法进行此非法操作');
+        }
+        if ($model_type == 'special_exchange' && $id) {
+            $card = SpecialExchange::where(['id' => $id, 'use_uid' => ['>', 0]])->find();
+            if ($card) return Json::fail('此卡片已经在使用当中,无法进行此非法操作');
+        }
+        $res1 = true;
+        if ($model_type == 'special_batch') {
+            $res = SpecialBatchModel::saveFieldByWhere(['id' => $id], [$field => $value]);
+            if ($res && $field == 'status') {
+                $res1 = SpecialExchange::saveFieldByWhere(['card_batch_id' => $id], [$field => $value]);
+            }
+        } else {
+            $res = SpecialExchange::saveFieldByWhere(['id' => $id], [$field => $value]);
+        }
+        if ($res && $res1)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    /**兑换码列表
+     * @return mixed
+     */
+    public function card_index()
+    {
+        $data = parent::getMore([
+            ['activity_type', 2],
+            ['card_batch_id', 0],
+
+        ]);
+        $batch_list = SpecialBatchModel::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([
+            ['start_time', ''],
+            ['end_time', ''],
+            ['exchange_code', ''],
+            ['phone', ''],
+            ['card_batch_id', 0],
+            ['is_use', ''],
+            ['is_status', ''],
+            ['page', 1],
+            ['limit', 20],
+            ['excel', $excel],
+        ]);
+        $where['card_batch_id'] = $where['card_batch_id'] > 0 ? $where['card_batch_id'] : $card_batch_id;
+        $card_list = SpecialExchange::getCardList($where);
+        return Json::successlayui($card_list);
+    }
+
+    /**删除
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        $res = SpecialBatchModel::delSpecialBatch($id);
+        if (!$res)
+            return Json::fail(SpecialBatchModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+}

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

xqd
@@ -0,0 +1,153 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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
+ */
+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();
+    }
+
+}

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

xqd
@@ -0,0 +1,156 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 MemberCard
+ * @package app\admin\controller\user
+ */
+class MemberCard extends AuthController
+{
+    public function index()
+    {
+        $this->assign(['activity_type' => 1]);
+        return $this->fetch('batch_index');
+    }
+
+    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()
+    {
+        return $this->fetch();
+    }
+
+    public function save_batch()
+    {
+        $data = parent::postMore([
+            ['title', ''],
+            ['use_day', 1],
+            ['total_num', 1],
+            ['status', 0],
+            ['remark', '']
+        ]);
+        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();
+            $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('此批次卡片已经在使用当中,无法进行此非法操作');
+            }
+        }
+        if ($model_type == 'member_card_batch' && $field != 'remark') {
+            $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('此卡片已经在使用当中,无法进行此非法操作');
+        }
+        $res = parent::getDataModification($model_type, $id, $field, $value);
+        if ($res)
+            return Json::successful('保存成功');
+        else
+            return Json::fail('保存失败');
+    }
+
+    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);
+    }
+
+    /**删除
+     * @param int $id
+     */
+    public function delete($id = 0)
+    {
+        $res = MemberCardBatch::delMemberCard($id);
+        if (!$res)
+            return Json::fail(MemberCardModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+}

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

xqd
@@ -0,0 +1,45 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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
+ * @package app\admin\controller\user
+ */
+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));
+    }
+
+}

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

xqd
@@ -0,0 +1,137 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 MemberShip
+ * @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, 'membership' => json_encode($membership)]);
+        return $this->fetch();
+    }
+
+    /**编辑会员
+     * @param int $id
+     */
+    public function save_sytem_vip($id = 0)
+    {
+        $post = parent::postMore([
+            ['title', ''],
+            ['img', ''],
+            ['vip_day', 0],
+            ['free_day', 0],
+            ['original_price', 0],
+            ['price', 0],
+            ['sort', 0],
+            ['is_permanent', 0],
+            ['is_publish', 0],
+            ['is_free', 0],
+            ['is_alone', 0],
+            ['brokerage_ratio', 0],
+            ['brokerage_two', 0]
+        ]);
+        if ($post['title'] == '') return Json::fail('请输入会员标题');
+        if ($post['is_permanent'] == 0 && $post['vip_day'] <= 0 && $post['is_free'] == 0) return Json::fail('会员有有效期时,请设置会员有效期');
+        if ($post['is_free'] == 1 && $post['free_day'] <= 0) return Json::fail('免费会员有有效期时,请设置会员有效期');
+        if (bcsub($post['original_price'], 0, 0) < 0) return Json::fail('请输入会员原价');
+        if (bcsub($post['price'], 0, 0) < 0) return Json::fail('请输入会员原价');
+        if ($post['is_free'] == 1) {
+            $post['vip_day'] = $post['free_day'];
+            $post['is_alone'] = 0;
+            $post['brokerage_ratio'] = 0;
+            $post['brokerage_two'] = 0;
+            unset($post['free_day']);
+        }
+        if ($post['is_alone'] && bcadd($post['brokerage_ratio'], $post['brokerage_two'], 2) > 100) return Json::fail('两级返佣比例之和不能大于100');
+        MembershipModel::beginTrans();
+        try {
+            if ($id) {
+                MembershipModel::update($post, ['id' => $id]);
+                MembershipModel::commitTrans();
+                return Json::successful('修改成功');
+            } else {
+                $post['add_time'] = time();
+                MembershipModel::set($post);
+                MembershipModel::commitTrans();
+                return Json::successful('添加成功');
+            }
+        } catch (\Exception $e) {
+            MembershipModel::rollbackTrans();
+            return Json::fail($e->getMessage());
+        }
+    }
+
+    /**会员状态设置
+     * @param string $is_publish
+     * @param string $id
+     */
+    public function set_publish($is_publish = '', $id = '')
+    {
+        if ($is_publish == '' || $id == '') return Json::fail('缺少参数');
+        $res = parent::getDataModification('ship', $id, 'is_publish', $is_publish);
+        if ($res)
+            return Json::successful($is_publish == 1 ? '发布成功' : '隐藏成功');
+        else
+            return Json::fail($is_publish == 1 ? '发布失败' : '隐藏失败');
+    }
+
+    /**会员删除
+     * @param string $id
+     */
+    public function delete($id = '')
+    {
+        if ($id == '') return Json::fail('缺少参数');
+        $res = parent::getDataModification('ship', $id, 'is_del', 1);
+        if ($res)
+            return Json::successful('删除成功');
+        else
+            return Json::fail('删除失败');
+    }
+
+
+}

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

xqd
@@ -0,0 +1,132 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 SignPoster
+ * @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', '签到语录')->maxlength(30);
+        $f[] = Form::number('sort', '排序')->max(99999)->min(0);
+        $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];
+        $time = strtotime($data['sign_time']);
+        $data['sign_time'] = strtotime(date('Y-m-d', $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'))->maxlength(30);
+        $f[] = Form::number('sort', '排序', $poster->getData('sort'))->max(99999)->min(0);
+        $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];
+        $time = strtotime($data['sign_time']);
+        $data['sign_time'] = strtotime(date('Y-m-d', $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('删除失败');
+    }
+
+}

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

xqd
@@ -0,0 +1,1047 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\Special;
+use app\admin\model\special\SpecialSubject;
+use app\admin\model\special\SpecialSource;
+use app\admin\model\special\SpecialBuy;
+use service\FormBuilder as Form;
+use service\JsonService;
+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\admin\model\user\UserBill;
+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\admin\model\order\DataDownloadOrder;
+use app\admin\model\download\DataDownload;
+use app\wap\model\store\StoreOrder as StoreOrderModel;
+use service\SystemConfigService;
+use app\admin\model\user\MemberRecord as MemberRecordModel;
+use app\admin\model\user\MemberShip;
+use app\admin\model\questions\TestPaperObtain;
+use app\admin\model\questions\TestPaper;
+use app\admin\model\download\DataDownloadBuy;
+use app\admin\model\merchant\Merchant;
+
+/**
+ * 用户管理控制器
+ * 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 get_member_list()
+    {
+        $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() : [];
+        return Json::successful($list);
+    }
+
+    /**
+     * 赠送会员
+     */
+    public function members($uid = 0)
+    {
+        if (!$uid) return Json::fail('参数错误');
+        $this->assign('uid', $uid);
+        return $this->fetch();
+    }
+
+    /**赠送会员
+     * @param int $uid
+     */
+    public function gift_members()
+    {
+        $data = parent::postMore([
+            ['uid', 0],
+            ['type', 0],
+            ['day', 0],
+            ['member', 0],
+        ]);
+        if (!$data['uid']) return Json::fail('参数错误');
+        $uid = $data['uid'];
+        $userInfo = UserModel::where('uid', $uid)->find();
+        if (!$userInfo) return Json::fail('用户不存在!');
+        if ($userInfo['level'] && $userInfo['is_permanent']) return Json::fail('该用户是永久会员,无需续费!');
+        if (!$data['type']) {
+            if (!$data['member']) return Json::fail('请选择会员等级');
+            $member = MemberShip::where(['id' => $data['member'], 'is_publish' => 1, 'is_del' => 0, '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('赠送失败');
+            }
+        } else {
+            if (!$data['day']) return Json::fail('请填写会员天数');
+            $resMer = MemberShip::setUserCustomMember($data['day'], $userInfo);
+            if ($resMer) {
+                return Json::successful('赠送成功');
+            } 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('清除会员失败');
+        }
+    }
+
+    /**设置用户的推广人
+     * @param string $uid
+     */
+    public function add_superior($uid = '')
+    {
+        if (!$uid) return Json::fail('参数错误!');
+        $form = Form::create(Url::build('set_superior', ['uid' => $uid]), [
+            Form::input('spread_uid', '推广人uid')
+        ]);
+        $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 set_superior($uid = '')
+    {
+        if (!$uid) return Json::fail('参数错误');
+        $data = parent::postMore([
+            ['spread_uid', 0],
+        ]);
+        if (!$data['spread_uid']) return Json::fail('请填写推广人uid');
+        $userInfo = UserModel::where('uid', $data['spread_uid'])->find();
+        if (!$userInfo) return Json::fail('推广人不存在');
+        $uids = explode(',', $uid);
+        if (in_array($data['spread_uid'], $uids)) {
+            $key = array_search($data['spread_uid'], $uids);
+            unset($uids[$key]);
+        }
+        $res = UserModel::where('uid', 'in', $uids)->update(['spread_uid' => $data['spread_uid']]);
+        if ($res) {
+            return Json::successful('设置用户的推广人成功');
+        } else {
+            return Json::fail('设置用户的推广人失败');
+        }
+    }
+
+    /**发送试卷
+     * @param int $uid
+     * @return mixed
+     */
+    public function send($uid = 0)
+    {
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['uid' => $uid,'mer_list' => $mer_list]);
+        return $this->fetch();
+    }
+
+    /**发送提交
+     * @param $uid
+     * @param $tid
+     */
+    public function sendTestPaper($uid, $tid)
+    {
+        $tid = explode(',', $tid);
+        $res = TestPaperObtain::addUidSend($uid, $tid);
+        if ($res) {
+            return Json::successful('发送成功');
+        } else {
+            return Json::fail('发送失败');
+        }
+    }
+
+    /**赠送专题
+     * @param int $uid
+     * @return mixed
+     */
+    public function relation($uid = 0)
+    {
+        $mer_list = Merchant::getMerchantList();
+        $this->assign(['uid' => $uid, 'mer_list' => $mer_list]);
+        return $this->fetch();
+    }
+
+    /**
+     * 图文、音频、视频、专栏专题素材列表获取 关联
+     * @return json
+     * */
+    public function get_relation_source_list()
+    {
+        $where = parent::getMore([
+            ['page', 1],
+            ['is_show', 1],
+            ['limit', 20],
+            ['title', ''],
+            ['pid', ''],
+            ['type', ''],
+            ['mer_id', 0],
+            ['special_type', 0],
+        ]);
+        $special_source = [];
+
+        $special_task = Special::getRelationList($where, $special_source);
+        if (isset($special_task['data']) && $special_task['data']) {
+            foreach ($special_task['data'] as $k => $v) {
+                $special_task['data'][$k]['is_check'] = 0;
+                $special_task['data'][$k]['pay_status'] = PAY_MONEY;
+                if ($v['type'] == 6) $v['type'] = $v['light_type'];
+                $special_task['data'][$k]['types'] = parent::specialTaskType($v['type']);
+            }
+        }
+        return Json::successlayui($special_task);
+    }
+
+    public function user_data($uid = 0)
+    {
+        $spread = UserModel::where(['spread_uid' => $uid])->column('uid');
+        $count['pay_count'] = SpecialBuy::where(['uid' => $uid, 'is_del' => 0])->group('special_id')->count();
+        $count['bill_count'] = UserBill::where(['category' => 'now_money'])->where('uid', $uid)
+            ->where('type', 'in', ['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', ['brokerage'])
+            ->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(SpecialSubject::specialCategoryAll(1)));
+        $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('uid', $uid);
+        return $this->fetch();
+    }
+
+    public function get_member_record($uid)
+    {
+        $data = MemberRecordModel::userOneRecord($uid);
+        return Json::successlayui($data);
+    }
+
+    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());
+    }
+
+    /**赠送专题
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function save_give()
+    {
+        $data = parent::getMore([
+            ['uid', 0],
+            ['special_id', 0],
+        ]);
+        if (!$data['uid']) return Json::fail('请选择被赠送的用户');
+        if (!$data['special_id']) return Json::fail('请选择要赠送的专题');
+        $special = Special::PreWhere()->where(['id' => $data['special_id']])->find();
+        if (SpecialBuy::be(['uid' => $data['uid'], 'special_id' => $data['special_id'], 'is_del' => 0, 'type' => 3])) 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::PreWhere()->where(['id' => $v['source_id']])->find();
+                    if ($task_special['is_show'] == 1) {
+                        SpecialBuy::setBuySpecial('', $data['uid'], $v['source_id'], 3, $task_special['validity'], $data['special_id']);
+                    }
+                }
+            }
+        }
+        $res = SpecialBuy::setBuySpecial('', $data['uid'], $data['special_id'], 3, $special['validity']);
+        if ($res) {
+            TestPaperObtain::setTestPaper('', $data['uid'], $data['special_id'], 3);
+            DataDownloadBuy::setDataDownload('', $data['uid'], $data['special_id'], 2);
+            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(UserBill::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', ''],
+        ]);
+        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('nowMoney', '当前余额', $user->getData('now_money'))->disabled(1);
+        $f[] = Form::number('money', '金额')->min(0);
+        $f[] = Form::radio('is_promoter', '推广员', $user->getData('is_promoter'))->options([
+            ['value' => 0, 'label' => '关闭'],
+            ['value' => 1, 'label' => '推广员'],
+        ]);
+        $f[] = Form::radio('is_write_off', '核销员', $user->getData('is_write_off'))->options([
+            ['value' => 0, 'label' => '关闭'],
+            ['value' => 1, 'label' => '开启'],
+        ]);
+        $f[] = Form::radio('status', '状态', $user->getData('status'))->options([['value' => 1, 'label' => '开启'], ['value' => 0, 'label' => '锁定']]);
+        $form = Form::make_post_form('添加用户通知', $f, Url::build('update', array('id' => $uid)), 2);
+        $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_write_off', 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, $edit['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, $edit['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_write_off'] = $data['is_write_off'];
+        $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 access($uid = 0)
+    {
+        $this->assign([
+            'uid' => $uid,
+            'count' => UserModel::getCountData($uid),
+        ]);
+        return $this->fetch();
+    }
+
+    public function getUserBuySpecilList($uid, $page = 1, $limit = 20)
+    {
+        $list = SpecialBuy::where(['a.uid' => $uid, 'a.is_del' => 0])
+            ->join("__SPECIAL__ s", 's.id=a.special_id')->order('a.add_time desc')
+            ->alias('a')->field(['a.*', 's.title'])->page((int)$page, (int)$limit)->select();
+        $list = count($list) ? $list->toArray() : [];
+        return Json::successful($list);
+    }
+
+    public function getUserBuyDataList($uid, $page = 1, $limit = 20)
+    {
+        $list = DataDownloadBuy::where(['a.uid' => $uid, 'a.is_del' => 0])
+            ->join("DataDownload d", 'd.id=a.data_id', 'left')->order('a.add_time desc')
+            ->alias('a')->field(['a.*', 'd.title'])
+            ->page((int)$page, (int)$limit)->select();
+        $list = count($list) ? $list->toArray() : [];
+        return Json::successful($list);
+    }
+
+    public function getUserBuyTestPaperList($uid, $page = 1, $limit = 20)
+    {
+        $list = TestPaperObtain::where(['a.uid' => $uid, 'a.is_del' => 0])
+            ->join("TestPaper t", 't.id=a.test_id', 'left')->order('a.add_time desc')
+            ->alias('a')->field(['a.*', 't.title'])
+            ->page((int)$page, (int)$limit)->select();
+        $list = count($list) ? $list->toArray() : [];
+        return Json::successful($list);
+    }
+
+    public function del_data_buy($id = 0)
+    {
+        if ($id == 0) return Json::fail('缺少参数');
+        $dataBuy = DataDownloadBuy::get($id);
+        if (!$dataBuy) return Json::fail('记录不存在');
+        $res = DataDownloadBuy::where('id', $id)->update(['is_del' => 1]);
+        if ($res) {
+            return Json::successful('删除成功');
+        } else
+            return Json::fail('删除失败');
+    }
+
+    public function del_test_buy($id = 0)
+    {
+        if ($id == 0) return Json::fail('缺少参数');
+        $testBuy = TestPaperObtain::get($id);
+        if (!$testBuy) return Json::fail('记录不存在');
+        $res = TestPaperObtain::where('id', $id)->update(['is_del' => 1]);
+        if ($res) {
+            return Json::successful('删除成功');
+        } else
+            return Json::fail('删除失败');
+    }
+
+    public function get_order_buy_list($uid, $page = 1, $limit = 20)
+    {
+        $data = SpecialBuy::getOrderPayList($uid, $page, $limit);
+        return JsonService::successful($data);
+    }
+
+    /**
+     * 会员详情
+     */
+    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')->order('a.add_time desc')
+            ->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';
+            } else if ($value['type'] == '买商品赠送') {
+                $value['order_id'] = '买商品赠送';
+                $value['total_num'] = '1';
+                $value['pay_price'] = '0';
+            } else 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('缺少参数');
+        $specialBuy = SpecialBuy::get($id);
+        if (!$specialBuy) return Json::fail('记录不存在');
+        $special = Special::get($specialBuy['special_id']);
+        $res = SpecialBuy::where('id', $id)->update(['is_del' => 1]);
+        if ($special['type'] == SPECIAL_COLUMN) {
+            $res2 = SpecialBuy::where(['uid' => $specialBuy['uid'], 'type' => $specialBuy['type'], 'column_id' => $specialBuy['special_id'], 'is_del' => 0])->update(['is_del' => 1]);
+            $res = $res && $res2;
+        }
+        if ($res) {
+            switch ($specialBuy['type']) {
+                case '支付获得':
+                case '拼团获得':
+                case '领取礼物获得':
+                case '兑换获得':
+                    $source = 2;
+                    $type = 1;
+                    break;
+                case '赠送获得':
+                case '买商品赠送':
+                    $source = 3;
+                    $type = 2;
+                    break;
+            }
+            TestPaperObtain::delTestPaper($specialBuy['order_id'], $specialBuy['uid'], $specialBuy['special_id'], $source);
+            DataDownloadBuy::delDataDownload($specialBuy['order_id'], $specialBuy['uid'], $specialBuy['special_id'], $type);
+            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(UserBill::getOneSignList(compact('uid', 'page', 'limit')));
+    }
+
+    /**
+     * 获取某用户的余额变动记录
+     */
+    public function getOneBalanceChangList($uid, $page = 1, $limit = 20)
+    {
+        return Json::successful(UserBill::getOneBalanceChangList(compact('uid', 'page', 'limit')));
+    }
+}

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

xqd
@@ -0,0 +1,320 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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'), 2);
+        $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('发送成功!');
+    }
+}

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

xqd
@@ -0,0 +1,41 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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
+ * @package app\admin\controller\user
+ */
+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));
+    }
+
+}

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

xqd
@@ -0,0 +1,267 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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', 0],
+            ['data', ''],
+            ['subscribe', ''],
+            ['order', ''],
+            ['page', 1],
+            ['limit', 20],
+            ['user_type', ''],
+        ]);
+        return JsonService::successlayui(User::agentSystemPage($where));
+    }
+
+    public function get_badge_list()
+    {
+        $where = parent::postMore([
+            ['data', ''],
+            ['nickname', ''],
+            ['excel', ''],
+        ]);
+        return JsonService::successful(User::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(User::getStairOrderList($where));
+    }
+
+    public function get_stair_order_badge()
+    {
+        $where = parent::getMore([
+            ['uid', ''],
+            ['data', ''],
+            ['order_id', ''],
+            ['type', ''],
+        ]);
+        return JsonService::successful(User::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(User::getStairList($where));
+    }
+
+    public function get_stair_badge()
+    {
+        $where = parent::getMore([
+            ['uid', ''],
+            ['data', ''],
+            ['nickname', ''],
+            ['type', ''],
+        ]);
+        return JsonService::successful(User::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

xqd
@@ -0,0 +1,48 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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

xqd
@@ -0,0 +1,200 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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('删除成功!');
+    }
+
+
+}

+ 144 - 0
application/admin/controller/wechat/RoutineTemplate.php

xqd
@@ -0,0 +1,144 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 service\RoutineTemplateService;
+use think\Cache;
+use think\Request;
+use think\Url;
+use app\admin\model\wechat\RoutineTemplate as RoutineTemplateModel;
+use app\admin\model\system\SystemConfig;
+
+/**
+ * 微信订阅消息控制器
+ * Class RoutineTemplate
+ * @package app\admin\controller\wechat
+ */
+class RoutineTemplate extends AuthController
+{
+
+    protected $cacheTag = '_system_routine_wechat';
+
+    public function index()
+    {
+        $where = parent::getMore([
+            ['name', ''],
+            ['status', '']
+        ], $this->request);
+        $this->assign('where', $where);
+        $this->assign(RoutineTemplateModel::SystemPage($where));
+        try {
+            $industry = Cache::tag($this->cacheTag)->remember('_wechat_routine_industry', function () {
+                $cache = RoutineTemplateService::getCategory();
+                if (!$cache) return [];
+                Cache::tag($this->cacheTag, ['_wechat_routine_industry']);
+                return $cache;
+            }, 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'), 2);
+        $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'] != '' && RoutineTemplateModel::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();
+        RoutineTemplateModel::set($data);
+        return Json::successful('添加模板消息成功!');
+    }
+
+    /**
+     * 编辑模板消息
+     * @param $id
+     * @return mixed|\think\response\Json|void
+     */
+    public function edit($id)
+    {
+        if (!$id) return $this->failed('数据不存在');
+        $product = RoutineTemplateModel::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')), 2);
+        $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 = RoutineTemplateModel::get($id);
+        if (!$product) return Json::fail('数据不存在!');
+        RoutineTemplateModel::edit($data, $id);
+        return Json::successful('修改成功!');
+    }
+
+    /**
+     * 删除模板消息
+     * @param $id
+     * @return \think\response\Json
+     */
+    public function delete($id)
+    {
+        if (!$id) return Json::fail('数据不存在!');
+        if (!RoutineTemplateModel::del($id))
+            return Json::fail(RoutineTemplateModel::getErrorInfo('删除失败,请稍候再试!'));
+        else
+            return Json::successful('删除成功!');
+    }
+
+
+}

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

xqd
@@ -0,0 +1,186 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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')), 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 (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

xqd
@@ -0,0 +1,43 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 WechatMessage
+ * @package app\admin\controller\wechat
+ */
+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();
+    }
+
+
+}
+

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

xqd
@@ -0,0 +1,294 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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;
+use app\admin\model\article\ArticleContent;
+
+/**
+ * 图文信息
+ * 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'), 2);
+        $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')), 2);
+        $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) {
+                ArticleContent::where('nid', $cate['new_id'])->delete();
+                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' => '/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);
+                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'];
+                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

xqd
@@ -0,0 +1,143 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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'), 2);
+        $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')), 2);
+        $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

xqd
@@ -0,0 +1,394 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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')), 4);
+        $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')), 4);
+        $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'), 4);
+        $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]), 4);
+        $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'), 4);
+        $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')), 4);
+        $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();
+    }
+
+}
+

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

xqd
@@ -0,0 +1,336 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 static $AccessKeyId = ''; //阿里云AccessKeyId
+
+    protected static $accessKeySecret = ''; //阿里云AccessKeySecret
+
+    protected static $end_point = ''; //EndPoint(地域节点)
+
+    protected static $OssBucket = ''; //存储空间名称
+
+    protected static $uploadUrl = ''; //空间域名 Domain
+    /**
+     * 初始化
+     */
+    protected function init()
+    {
+        self::$AccessKeyId = SystemConfigService::get('accessKeyId');//阿里云AccessKeyId
+        self::$accessKeySecret = SystemConfigService::get('accessKeySecret');//阿里云AccessKeySecret
+        self::$end_point = SystemConfigService::get('end_point');//EndPoint
+        self::$OssBucket = SystemConfigService::get('OssBucket');//存储空间名称
+        self::$uploadUrl = SystemConfigService::get('uploadUrl');//空间域名 Domain
+        if (self::$AccessKeyId == '' || self::$accessKeySecret == '') return Json::fail('阿里云AccessKeyId或阿里云AccessKeySecret没有配置');
+        if (self::$end_point == '') return Json::fail('EndPoint没有配置');
+        if (self::$OssBucket == '') return Json::fail('存储空间名称没有配置');
+        if (self::$uploadUrl == '') return Json::fail('空间域名没有配置');
+        return AliyunOss::instance([
+            'AccessKey' => self::$AccessKeyId,
+            'AccessKeySecret' => self::$accessKeySecret,
+            'OssEndpoint' => self::$end_point,
+            'OssBucket' => self::$OssBucket,
+            'uploadUrl' => self::$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],
+            ['title', '']
+        ]);
+        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');
+        $title = input('title') != NULL ? input('title') : '';
+        try {
+            $aliyunOss = $this->init();
+            $res = $aliyunOss->upload('file');
+            if ($res) {
+                SystemAttachmentModel::attachmentAdd($res['key'], $title, 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 updateImageTitle()
+    {
+        $data = parent::postMore([
+            ['att_id', 0],
+            ['title', '']
+        ]);
+        $res = SystemAttachmentModel::attachmentTitle($data);
+        if ($res)
+            Json::successful('修改成功');
+        else
+            Json::fail('修改失败!');
+    }
+
+    /**
+     * 移动图片分类显示
+     */
+    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'), 5);
+        $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', '分类名称')->maxlength(6);
+        $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'])) return Json::fail('分类名称不能为空!');
+        if (mb_strlen($data['name'], 'utf-8') > 6) return Json::fail('分类名称过长');
+        $res = Category::create($data);
+        if ($res)
+            return Json::successful('添加成功');
+        else
+            return 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'))->maxlength(6);
+        $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('请输入分类名称');
+        if (mb_strlen($data['name'], 'utf-8') > 6) 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

xqd
@@ -0,0 +1,62 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 Widgets
+ * @package app\admin\controller\widget
+ *
+ */
+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');
+    }
+
+
+}

BIN
application/admin/model/.DS_Store


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

xqd
@@ -0,0 +1,221 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\WebRecommendRelation;
+use app\admin\model\system\SystemAdmin;
+use traits\ModelTrait;
+use basic\ModelBasic;
+use think\Db;
+
+/**
+ * 新闻管理 Model
+ * Class Article
+ * @package app\admin\model\article
+ */
+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 (isset($where['store_name']) && $where['store_name']) $model->where("{$alias}title", 'LIKE', "%$where[store_name]%");
+        if (isset($where['cid']) && $where['cid']) $model->where("{$alias}cid", $where['cid']);
+        if (isset($where['order']) && $where['order'])
+            $model->order($alias . self::setOrder($where['order']));
+        else
+            $model->order($alias . 'sort desc,id desc');
+        if (isset($where['is_show']) && $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')->field('A.*')->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');
+            $item['recommend'] = RecommendRelation::where('a.link_id', $item['id'])->where('a.type', 1)->alias('a')
+                ->join('__RECOMMEND__ r', 'a.recommend_id=r.id')->column('a.id,r.title');
+            $item['web_recommend'] = WebRecommendRelation::where('a.link_id', $item['id'])->where('a.type', 4)->alias('a')
+                ->join('__WEB_RECOMMEND__ r', 'a.recommend_id=r.id')->column('a.id,r.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);
+    }
+
+}

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

xqd
@@ -0,0 +1,94 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\article
+ */
+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)->order('sort desc');
+        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;
+    }
+
+}

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

xqd
@@ -0,0 +1,28 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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\article
+ */
+class ArticleContent extends ModelBasic
+{
+
+    use ModelTrait;
+
+    const name = 'content';
+
+}

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

xqd
@@ -0,0 +1,41 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 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 Search
+ * @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();
+    }
+}

+ 208 - 0
application/admin/model/download/DataDownload.php

xqd
@@ -0,0 +1,208 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\download;
+
+use think\Db;
+use traits\ModelTrait;
+use basic\ModelBasic;
+use app\admin\model\download\DataDownloadCategpry;
+use app\admin\model\system\RecommendRelation;
+use app\admin\model\system\WebRecommendRelation;
+use service\SystemConfigService;
+use app\admin\model\merchant\Merchant;
+use service\WechatTemplateService;
+use app\wap\model\routine\RoutineTemplate;
+use app\admin\model\wechat\WechatUser;
+
+/**资料 model
+ * Class DataDownload
+ * @package app\admin\model\download
+ */
+class DataDownload extends ModelBasic
+{
+    use ModelTrait;
+
+    /**字段过滤
+     * @param string $alias
+     * @param null $model
+     * @return DataDownload
+     */
+    public static function PreWhere($alias = '', $model = null)
+    {
+        if (is_null($model)) $model = new self();
+        if ($alias) {
+            $model = $model->alias($alias);
+            $alias .= '.';
+        }
+        return $model->where([$alias . 'is_show' => 1, $alias . 'is_del' => 0, $alias . 'status' => 1]);
+    }
+
+    /**条件处理
+     * @param $where
+     * @return DataDownload
+     */
+    public static function setWhere($where)
+    {
+        $model = new self();
+        $time['data'] = '';
+        if (isset($where['start_time']) && isset($where['end_time']) && $where['start_time'] != '' && $where['end_time'] != '') {
+            $time['data'] = $where['start_time'] . ' - ' . $where['end_time'];
+            $model = $model->getModelTime($time, $model, 'add_time');
+        }
+        if (isset($where['title']) && $where['title']) {
+            $model = $model->where('title|id|abstract', 'like', "%$where[title]%");
+        }
+        if (isset($where['cate_id']) && $where['cate_id']) {
+            $model = $model->where('cate_id', $where['cate_id']);
+        }
+        if (isset($where['mer_id']) && $where['mer_id'] != '') {
+            $model = $model->where('mer_id', $where['mer_id']);
+        }
+        if (isset($where['is_show']) && $where['is_show'] != '') {
+            $model = $model->where('is_show', $where['is_show']);
+        }
+        if (isset($where['status']) && $where['status'] != '') {
+            $model = $model->where('status', $where['status']);
+        } else {
+            $model = $model->where('status', 'in', [-1, 0]);
+        }
+        return $model->where('is_del', 0);
+    }
+
+    /**获取列表
+     * @param $where
+     * @return array
+     * @throws \think\Exception
+     */
+    public static function get_download_list($where)
+    {
+        $data = self::setWhere($where)->order('sort DESC,id DESC')
+            ->page((int)$where['page'], (int)$where['limit'])->select();
+        foreach ($data as $key => $item) {
+            $item['recommend'] = RecommendRelation::where('a.link_id', $item['id'])->where('a.type', 14)->alias('a')
+                ->join('__RECOMMEND__ r', 'a.recommend_id=r.id')->column('a.id,r.title');
+            $item['web_recommend'] = WebRecommendRelation::where('a.link_id', $item['id'])->where('a.type', 3)->alias('a')
+                ->join('__WEB_RECOMMEND__ r', 'a.recommend_id=r.id')->column('a.id,r.title');
+            $item['add_time'] = ($item['add_time'] != 0 || $item['add_time']) ? date('Y-m-d H:i:s', $item['add_time']) : '';
+            $item['cate_name'] = DataDownloadCategpry::where('id', $item['cate_id'])->value('title');
+            if ($item['mer_id']) {
+                $item['mer_name'] = Merchant::where('id', $item['mer_id'])->value('mer_name');
+            } else {
+                $item['mer_name'] = '总平台';
+            }
+        }
+        $data = count((array)$data) ? $data->toArray() : [];
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+
+    /**获取资料
+     * @param $where
+     */
+    public static function dataDownloadLists($where, $source)
+    {
+        $data = self::setWhere($where)->where('id', 'not in', $source)->page($where['page'], $where['limit'])->select();
+        foreach ($data as $key => $item) {
+            if ($item['mer_id']) {
+                $item['mer_name'] = Merchant::where('id', $item['mer_id'])->value('mer_name');
+            } else {
+                $item['mer_name'] = '总平台';
+            }
+        }
+        $count = self::setWhere($where)->where('id', 'not in', $source)->count();
+        return compact('data', 'count');
+    }
+
+    /**获取列表
+     * @param $where
+     * @return array
+     * @throws \think\Exception
+     */
+    public static function get_download_examine_list($where)
+    {
+        $data = self::setWhere($where)->order('sort DESC,id DESC')
+            ->page((int)$where['page'], (int)$where['limit'])->select();
+        foreach ($data as $key => $item) {
+            $item['fail_time'] = date('Y-m-d H:i:s', $item['fail_time']);
+            $item['add_time'] = ($item['add_time'] != 0 || $item['add_time']) ? date('Y-m-d H:i:s', $item['add_time']) : '';
+            $item['cate_name'] = DataDownloadCategpry::where('id', $item['cate_id'])->value('title');
+            if ($item['mer_id']) {
+                $item['mer_name'] = Merchant::where('id', $item['mer_id'])->value('mer_name');
+            } else {
+                $item['mer_name'] = '总平台';
+            }
+        }
+        $data = count((array)$data) ? $data->toArray() : [];
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+
+    /**审核失败
+     * @param $id
+     * @param $fail_msg
+     * @return bool
+     * @throws \think\exception\DbException
+     */
+    public static function changeFail($id, $mer_id, $fail_message)
+    {
+        $fail_time = time();
+        $status = -1;
+        $uid = Merchant::where('id', $mer_id)->value('uid');
+        try {
+            $wechat_notification_message = SystemConfigService::get('wechat_notification_message');
+            if ($wechat_notification_message == 1) {
+                WechatTemplateService::sendTemplate(WechatUser::uidToOpenid($uid), WechatTemplateService::EXAMINE_RESULT, [
+                    'first' => '尊敬的讲师,您添加的资料审核结果已出。',
+                    'keyword1' => '审核失败',
+                    'keyword2' => date('Y-m-d H:i:s', time()),
+                    'remark' => '失败原因:' . $fail_message
+                ], '');
+            } else {
+                $dat['phrase5']['value'] = '资料审核失败';
+                $dat['time24']['value'] = date('Y-m-d H:i:s', time());
+                $dat['thing4']['value'] = '资料失败原因:' . $fail_message;
+                RoutineTemplate::sendExamineResult($dat, $uid, '');
+            }
+        } catch (\Exception $e) {
+        }
+        return self::edit(compact('fail_time', 'fail_message', 'status'), $id);
+    }
+
+    /**审核成功
+     * @param $id
+     * @return bool
+     */
+    public static function changeSuccess($id, $mer_id)
+    {
+        $success_time = time();
+        $status = 1;
+        $uid = Merchant::where('id', $mer_id)->value('uid');
+        try {
+            $wechat_notification_message = SystemConfigService::get('wechat_notification_message');
+            if ($wechat_notification_message == 1) {
+                WechatTemplateService::sendTemplate(WechatUser::uidToOpenid($uid), WechatTemplateService::EXAMINE_RESULT, [
+                    'first' => '尊敬的讲师,您添加的资料审核结果已出。',
+                    'keyword1' => '审核成功',
+                    'keyword2' => date('Y-m-d H:i:s', time()),
+                    'remark' => '感恩您的努力付出,谢谢!'
+                ], '');
+            } else {
+                $dat['phrase5']['value'] = '资料审核成功';
+                $dat['time24']['value'] = date('Y-m-d H:i:s', time());
+                $dat['thing4']['value'] = '您添加的资料审核结果已出!';
+                RoutineTemplate::sendExamineResult($dat, $uid, '');
+            }
+        } catch (\Exception $e) {
+        }
+        return self::edit(compact('status', 'success_time'), $id);
+    }
+}

+ 147 - 0
application/admin/model/download/DataDownloadBuy.php

xqd
@@ -0,0 +1,147 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\download;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+use app\admin\model\questions\Relation;
+use app\admin\model\download\DataDownload;
+use app\admin\model\order\DataDownloadOrder;
+use app\admin\model\special\Special;
+use app\admin\model\special\SpecialSource;
+
+/**
+ * 获得资料 Model
+ */
+class DataDownloadBuy extends ModelBasic
+{
+    use ModelTrait;
+
+    protected function getAddTimeAttr($value)
+    {
+        return date('Y-m-d H:i:s', $value);
+    }
+
+    protected function getTypeAttr($value)
+    {
+        $name = '';
+        switch ($value) {
+            case 0:
+                $name = '支付获得';
+                break;
+            case 1:
+                $name = '领取获得';
+                break;
+            case 2:
+                $name = '赠送获得';
+                break;
+        }
+        return $name;
+    }
+
+    /**购买专题获得资料
+     * @param $order_id
+     * @param $uid
+     * @param $special_id
+     * @return bool
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function setDataDownload($order_id, $uid, $special_id, $type = 0)
+    {
+        if (!$uid || !$special_id) return false;
+        $special = Special::PreWhere()->where(['id'=>$special_id])->find();
+        if ($special['type'] == 5) {
+            $special_source = SpecialSource::getSpecialSource($special['id']);
+            if (!$special_source) return false;
+            foreach ($special_source as $k => $v) {
+                $task_special = Special::PreWhere()->where(['id'=>$v['source_id']])->find();
+                if (!$task_special) continue;
+                if ($task_special['is_show'] != 1) continue;
+                $data_ids = Relation::setWhere(4, $task_special['id'])->column('relation_id');
+                if (count($data_ids) <= 0) continue;
+                foreach ($data_ids as $ks => $value) {
+                    self::setUserDataDownload($order_id, $value, $uid, $type);
+                }
+            }
+        } else {
+            $data_ids = Relation::setWhere(4, $special_id)->column('relation_id');
+            if (count($data_ids) <= 0) return false;
+            foreach ($data_ids as $kf => $value) {
+                self::setUserDataDownload($order_id, $value, $uid, $type);
+            }
+        }
+    }
+
+    /** 用户获得资料
+     * @param $order_id
+     * @param $data_id
+     * @param $uid
+     * @param $type
+     * @return bool|object
+     */
+    public static function setUserDataDownload($order_id, $data_id, $uid, $type)
+    {
+        $add_time = time();
+        if (self::be(['uid' => $uid, 'data_id' => $data_id, 'type' => $type, 'is_del' => 0])) return false;
+        return self::set(compact('order_id', 'data_id', 'uid', 'type', 'add_time'));
+    }
+
+    /**删除专题时清除资料
+     * @param $order_id
+     * @param $uid
+     * @param $special_id
+     * @return bool
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function delDataDownload($order_id, $uid, $special_id, $type)
+    {
+        if (!$uid || !$special_id) return false;
+        $special = Special::PreWhere()->where(['id'=>$special_id])->find();
+        if ($special['type'] == SPECIAL_COLUMN) {
+            $special_source = SpecialSource::getSpecialSource($special['id']);
+            if (!$special_source) return false;
+            foreach ($special_source as $k => $v) {
+                $task_special = Special::PreWhere()->where(['id'=>$v['source_id']])->find();
+                if (!$task_special) continue;
+                if ($task_special['is_show'] != 1) continue;
+                $data_ids = Relation::setWhere(4, $task_special['id'])->column('relation_id');
+                if (count($data_ids) <= 0) continue;
+                foreach ($data_ids as $ks => $value) {
+                    self::delUserDataDownload($order_id, $value, $uid, $type);
+                }
+            }
+        } else {
+            $data_ids = Relation::setWhere(4, $special_id)->column('relation_id');
+            if (count($data_ids) <= 0) return false;
+            foreach ($data_ids as $kf => $value) {
+                self::delUserDataDownload($order_id, $value, $uid, $type);
+            }
+        }
+    }
+
+    /** 清除资料
+     * @param $order_id
+     * @param $data_id
+     * @param $uid
+     * @param $type
+     * @return bool|object
+     */
+    public static function delUserDataDownload($order_id, $data_id, $uid, $type)
+    {
+        if (!self::be(['order_id' => $order_id, 'uid' => $uid, 'data_id' => $data_id, 'type' => $type, 'is_del' => 0])) return false;
+        return self::where(['order_id' => $order_id, 'uid' => $uid, 'data_id' => $data_id, 'type' => $type, 'is_del' => 0])->update(['is_del' => 1]);
+    }
+}

+ 92 - 0
application/admin/model/download/DataDownloadCategpry.php

xqd
@@ -0,0 +1,92 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\model\download;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+use service\UtilService as Util;
+use app\admin\model\download\DataDownload;
+
+/**
+ * Class DataDownloadCategpry 二级分类
+ * @package app\admin\model\download
+ */
+class DataDownloadCategpry extends ModelBasic
+{
+    use ModelTrait;
+
+    public static function specialCategoryAll($type = 0)
+    {
+        $model = self::where(['is_del' => 0, 'is_show' => 1]);
+        if ($type == 1) {
+            $model = $model->where('pid', 0);
+        }
+        $list = $model->order('sort desc,add_time desc')->select();
+        $list = count($list) > 0 ? $list->toArray() : [];
+        $list = Util::sortListTier($list, 0, 'pid');
+        return $list;
+    }
+
+    public static function get_download_cate_list($where)
+    {
+        $data = self::setWhere($where)->column('id,pid');
+        $list = [];
+        foreach ($data as $ket => $item) {
+            $cate = self::where('id', $ket)->find();
+            if ($cate) {
+                $cate = $cate->toArray();
+                $cate['data_count'] = 0;
+                if ($item > 0) {
+                    $cate['data_count'] = DataDownload::where('is_del', 0)->where('cate_id', $ket)->count();
+                } else {
+                    $pids = self::categoryId($ket);
+                    $cate['data_count'] = DataDownload::where('is_del', 0)->where('cate_id', 'in', $pids)->count();
+                }
+                array_push($list, $cate);
+                unset($cate);
+            }
+            if ($item > 0 && !array_key_exists($item, $data)) {
+                $cate = self::where('id', $item)->find();
+                if ($cate) {
+                    $cate = $cate->toArray();
+                    $cate['data_count'] = 0;
+                    array_push($list, $cate);
+                }
+            }
+        }
+        return $list;
+    }
+
+    public static function setWhere($where)
+    {
+        $model = self::order('sort desc,add_time desc')->where('is_del', 0);
+        if ($where['title']) $model = $model->where('title', 'like', "%$where[title]%");
+        if ($where['pid']) $model = $model->where('pid', $where['pid']);
+        return $model;
+    }
+
+    public static function getSubjectAll()
+    {
+        return self::order('sort desc,add_time desc')->where(['is_show' => 1, 'is_del' => 0])->field('title,id')->select();
+    }
+
+    /**获取一个分类下的所有分类ID
+     * @param int $pid
+     */
+    public static function categoryId($pid = 0)
+    {
+        $data = self::where('is_del', 0)->where('pid', $pid)->column('id');
+        array_push($data, $pid);
+        return $data;
+    }
+}

+ 91 - 0
application/admin/model/download/DataDownloadRecords.php

xqd
@@ -0,0 +1,91 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\download;
+
+use basic\ModelBasic;
+use traits\ModelTrait;
+use think\Db;
+use app\admin\model\download\DataDownload;
+use service\PhpSpreadsheetService;
+
+/**资料下载
+ * Class DataDownloadRecords
+ * @package app\admin\model\download
+ */
+class DataDownloadRecords extends ModelBasic
+{
+    use ModelTrait;
+
+
+    /**条件处理
+     * @param $where
+     */
+    public static function getOrderWhere($where, $id)
+    {
+        $model = self::alias('r')->join('User u', 'r.uid=u.uid', 'left')
+            ->join('DataDownload d', 'r.data_id=d.id', 'left')
+            ->where('r.data_id', $id);
+        if ($where['data'] != '') {
+            $model = self::getModelTime($where, $model, 'r.add_time');
+        }
+        $model = $model->order('r.add_time desc')->field('r.uid,r.data_id,r.add_time,r.update_time,r.number,d.id,d.title,d.money,d.member_money,u.nickname,u.phone,u.level');
+        return $model;
+    }
+
+    /**下载记录
+     * @param $where
+     * @param $id
+     */
+    public static function specialLearningRecordsLists($where, $id)
+    {
+        $model = self::getOrderWhere($where, $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 $key => &$value) {
+            $value['last_study_time'] = $value['update_time'];
+            $value['price'] = $value['level'] > 0 ? $value['member_money'] : $value['money'];
+        }
+        if (isset($where['excel']) && $where['excel'] == 1) {
+            self::SaveExcel($data);
+        }
+        $count = self::getOrderWhere($where, $id)->count();
+        return compact('count', 'data');
+    }
+
+    /**
+     * 保存并下载excel
+     * $list array
+     * return
+     */
+    public static function SaveExcel($list)
+    {
+        $export = [];
+        foreach ($list as $index => $item) {
+            $export[] = [
+                $item['uid'],
+                $item['nickname'],
+                $item['phone'],
+                $item['level'] == 1 ? '会员' : '非会员',
+                $item['title'],
+                $item['number'],
+                $item['price'],
+                $item['last_study_time']
+            ];
+        }
+        $filename = '下载记录' . time() . '.xlsx';
+        $head = ['UID', '昵称', '电话', '身份', '资料名称', '下载次数', '价格', '最后学习时间'];
+        PhpSpreadsheetService::outdata($filename, $export, $head);
+    }
+}

+ 70 - 0
application/admin/model/educational/Classes.php

xqd
@@ -0,0 +1,70 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\educational;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+use app\admin\model\educational\Teacher;
+
+/**
+ * 班级管理 Model
+ * Class Classes
+ * @package app\admin\model\educational
+ */
+class Classes extends ModelBasic
+{
+    use ModelTrait;
+
+    public static function setWhere($where)
+    {
+        $model = self::order('sort desc,add_time desc')->where('is_del', 0);
+        if ($where['status'] != '') $model = $model->where('status', $where['status']);
+        if ($where['title'] != '') $model = $model->where('title', 'like', "%$where[title]%");
+        return $model;
+    }
+
+    /**试题列表
+     * @param $where
+     */
+    public static function getClassesLists($where)
+    {
+        $data = self::setWhere($where)->page($where['page'], $where['limit'])->select();
+        foreach ($data as $key => &$value) {
+            if ($value['status'] == 1) {
+                $value['status'] = '开班';
+            } else {
+                $value['status'] = '结班';
+            }
+            if ($value['teacher_id']) {
+                $title = Teacher::where('id', 'in', explode(',', $value['teacher_id']))->column('name');
+                $value['teacher'] = implode(',', $title);
+            } else {
+                $value['teacher'] = '请在右侧操作中关联老师';
+            }
+            $value['start_time'] = date('Y-m-d H:i:s', $value['start_time']);
+            $value['end_time'] = date('Y-m-d H:i:s', $value['end_time']);
+        }
+        $count = self::setWhere($where)->count();
+        return compact('data', 'count');
+    }
+
+    /**
+     * 全部班级
+     */
+    public static function classesList()
+    {
+        $list = self::order('sort desc,add_time desc')->where(['is_del' => 0])->field('id,title')->select();
+        $list = count($list) > 0 ? $list->toArray() : [];
+        return $list;
+    }
+
+}

+ 49 - 0
application/admin/model/educational/ContactPhone.php

xqd
@@ -0,0 +1,49 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\admin\model\educational;
+
+use traits\ModelTrait;
+use basic\ModelBasic;
+use service\UtilService as Util;
+use app\admin\model\educational\Teacher;
+
+/**
+ * 学员联系方式
+ * Class ContactPhone
+ * @package app\admin\model\educational
+ */
+class ContactPhone extends ModelBasic
+{
+    use ModelTrait;
+
+    /**添加学员联系方法
+     * @param array $data
+     */
+    public static function contactPhoneAdd($id = 0, $data = [])
+    {
+        if (!$id) return false;
+        self::where('sid', $id)->delete();
+        foreach ($data as $k => &$time) {
+            $time['sid'] = $id;
+            self::set($time);
+        }
+        return true;
+    }
+
+    /**
+     * 学员联系方法列表
+     */
+    public static function contactPhoneList($id = 0)
+    {
+        return self::where(['sid' => $id])->order('id asc')->select();
+    }
+}

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff