瀏覽代碼

【程序目录】更新

wuhaotian 6 月之前
父節點
當前提交
cfa6c33680
共有 100 個文件被更改,包括 3483 次插入556 次删除
  1. 2 2
      crmeb/.version
  2. 91 0
      crmeb/LICENSE.txt
  3. 56 15
      crmeb/app/README.md
  4. 3 3
      crmeb/app/Request.php
  5. 30 6
      crmeb/app/adminapi/controller/Common.php
  6. 62 0
      crmeb/app/adminapi/controller/PublicController.php
  7. 463 300
      crmeb/app/adminapi/controller/UpgradeController.php
  8. 31 0
      crmeb/app/adminapi/controller/v1/agent/AgentLevel.php
  9. 13 1
      crmeb/app/adminapi/controller/v1/agent/AgentLevelTask.php
  10. 23 0
      crmeb/app/adminapi/controller/v1/agent/Division.php
  11. 40 0
      crmeb/app/adminapi/controller/v1/agent/SpreadApply.php
  12. 9 3
      crmeb/app/adminapi/controller/v1/application/wechat/WechatNewsCategory.php
  13. 2 0
      crmeb/app/adminapi/controller/v1/diy/Diy.php
  14. 151 0
      crmeb/app/adminapi/controller/v1/diy/DiyPro.php
  15. 74 0
      crmeb/app/adminapi/controller/v1/diy/PageLink.php
  16. 25 1
      crmeb/app/adminapi/controller/v1/file/SystemAttachment.php
  17. 10 4
      crmeb/app/adminapi/controller/v1/file/SystemAttachmentCategory.php
  18. 10 1
      crmeb/app/adminapi/controller/v1/finance/UserExtract.php
  19. 1 1
      crmeb/app/adminapi/controller/v1/marketing/StoreCombination.php
  20. 9 1
      crmeb/app/adminapi/controller/v1/marketing/StoreCouponIssue.php
  21. 56 1
      crmeb/app/adminapi/controller/v1/marketing/StoreSeckill.php
  22. 1 1
      crmeb/app/adminapi/controller/v1/marketing/integral/StoreIntegralOrder.php
  23. 22 21
      crmeb/app/adminapi/controller/v1/marketing/lottery/LuckLottery.php
  24. 2 4
      crmeb/app/adminapi/controller/v1/marketing/lottery/LuckLotteryRecord.php
  25. 6 1
      crmeb/app/adminapi/controller/v1/order/StoreOrder.php
  26. 1 1
      crmeb/app/adminapi/controller/v1/order/StoreOrderInvoice.php
  27. 115 4
      crmeb/app/adminapi/controller/v1/product/StoreProduct.php
  28. 113 0
      crmeb/app/adminapi/controller/v1/product/StoreProductLabel.php
  29. 130 0
      crmeb/app/adminapi/controller/v1/product/StoreProductParam.php
  30. 65 0
      crmeb/app/adminapi/controller/v1/product/StoreProductProtection.php
  31. 100 10
      crmeb/app/adminapi/controller/v1/setting/SystemConfig.php
  32. 5 11
      crmeb/app/adminapi/controller/v1/setting/SystemOutAccount.php
  33. 69 0
      crmeb/app/adminapi/controller/v1/statistic/BalanceStatistic.php
  34. 68 0
      crmeb/app/adminapi/controller/v1/statistic/OrderStatistic.php
  35. 106 0
      crmeb/app/adminapi/controller/v1/statistic/ProductStatistic.php
  36. 74 0
      crmeb/app/adminapi/controller/v1/statistic/TradeStatistic.php
  37. 152 0
      crmeb/app/adminapi/controller/v1/statistic/UserStatistic.php
  38. 13 4
      crmeb/app/adminapi/controller/v1/system/SystemClearData.php
  39. 88 0
      crmeb/app/adminapi/controller/v1/system/SystemTicket.php
  40. 50 4
      crmeb/app/adminapi/controller/v1/user/User.php
  41. 12 0
      crmeb/app/adminapi/route/agent.php
  42. 29 2
      crmeb/app/adminapi/route/diy.php
  43. 2 1
      crmeb/app/adminapi/route/file.php
  44. 15 3
      crmeb/app/adminapi/route/marketing.php
  45. 48 0
      crmeb/app/adminapi/route/product.php
  46. 6 6
      crmeb/app/adminapi/route/route.php
  47. 11 0
      crmeb/app/adminapi/route/system.php
  48. 7 1
      crmeb/app/adminapi/route/user.php
  49. 1 10
      crmeb/app/adminapi/validate/setting/SystemConfigValidata.php
  50. 1 1
      crmeb/app/api/controller/v1/CrontabController.php
  51. 11 11
      crmeb/app/api/controller/v1/LoginController.php
  52. 5 0
      crmeb/app/api/controller/v1/PayController.php
  53. 94 29
      crmeb/app/api/controller/v1/PublicController.php
  54. 8 2
      crmeb/app/api/controller/v1/activity/StoreSeckillController.php
  55. 61 12
      crmeb/app/api/controller/v1/order/StoreOrderController.php
  56. 34 0
      crmeb/app/api/controller/v1/store/StoreProductController.php
  57. 42 0
      crmeb/app/api/controller/v1/user/SpreadApplyController.php
  58. 4 0
      crmeb/app/api/controller/v1/user/UserAddressController.php
  59. 4 3
      crmeb/app/api/controller/v1/user/UserController.php
  60. 8 3
      crmeb/app/api/controller/v1/user/UserExtractController.php
  61. 7 0
      crmeb/app/api/controller/v2/PublicController.php
  62. 11 5
      crmeb/app/api/controller/v2/activity/LuckLotteryController.php
  63. 2 2
      crmeb/app/api/controller/v2/store/StoreCartController.php
  64. 1 1
      crmeb/app/api/controller/v2/wechat/AuthController.php
  65. 2 2
      crmeb/app/api/controller/v2/wechat/WechatController.php
  66. 17 5
      crmeb/app/api/route/v1.php
  67. 2 7
      crmeb/app/api/route/v2.php
  68. 29 13
      crmeb/app/common.php
  69. 52 0
      crmeb/app/dao/activity/StoreActivityDao.php
  70. 8 0
      crmeb/app/dao/activity/bargain/StoreBargainDao.php
  71. 8 0
      crmeb/app/dao/activity/combination/StoreCombinationDao.php
  72. 37 0
      crmeb/app/dao/activity/coupon/StoreCouponIssueDao.php
  73. 6 1
      crmeb/app/dao/activity/coupon/StoreCouponIssueUserDao.php
  74. 35 8
      crmeb/app/dao/activity/lottery/LuckLotteryDao.php
  75. 6 0
      crmeb/app/dao/activity/lottery/LuckLotteryRecordDao.php
  76. 19 5
      crmeb/app/dao/activity/seckill/StoreSeckillDao.php
  77. 36 0
      crmeb/app/dao/agent/SpreadApplyDao.php
  78. 6 3
      crmeb/app/dao/diy/PageLinkDao.php
  79. 39 3
      crmeb/app/dao/order/StoreOrderDao.php
  80. 5 0
      crmeb/app/dao/order/StoreOrderRefundDao.php
  81. 23 5
      crmeb/app/dao/product/product/StoreProductDao.php
  82. 42 0
      crmeb/app/dao/product/product/StoreProductLabelCateDao.php
  83. 58 0
      crmeb/app/dao/product/product/StoreProductLabelDao.php
  84. 16 0
      crmeb/app/dao/product/product/StoreProductLogDao.php
  85. 79 0
      crmeb/app/dao/product/product/StoreProductParamDao.php
  86. 44 0
      crmeb/app/dao/product/product/StoreProductProtectionDao.php
  87. 27 0
      crmeb/app/dao/system/SystemPemDao.php
  88. 40 0
      crmeb/app/dao/system/SystemTicketDao.php
  89. 1 1
      crmeb/app/dao/system/admin/SystemAdminDao.php
  90. 6 0
      crmeb/app/dao/user/UserExtractDao.php
  91. 31 0
      crmeb/app/dao/user/UserWechatUserDao.php
  92. 1 3
      crmeb/app/event.php
  93. 1 1
      crmeb/app/jobs/MiniOrderJob.php
  94. 3 0
      crmeb/app/jobs/PinkJob.php
  95. 1 1
      crmeb/app/jobs/UnpaidOrderCancelJob.php
  96. 2 2
      crmeb/app/jobs/notice/PrintJob.php
  97. 0 1
      crmeb/app/listener/admin/AdminLoginListener.php
  98. 1 1
      crmeb/app/listener/http/HttpEndListener.php
  99. 35 2
      crmeb/app/listener/notice/NoticeListener.php
  100. 0 0
      crmeb/app/listener/order/OrderCreateAfterListener.php

+ 2 - 2
crmeb/.version

@@ -1,5 +1,5 @@
-version=CRMEB-KY v5.4
-version_code=540
+version=CRMEB-KY v5.6.1
+version_code=561
 platform=gitee
 app_id=ze7x9rxsv09l6pvsyo
 app_key=fuF7U9zaybLa5gageVQzxtxQMFnvU2OI

文件差異過大導致無法顯示
+ 91 - 0
crmeb/LICENSE.txt


+ 56 - 15
crmeb/app/README.md

@@ -1,29 +1,70 @@
-在ThinkPHP框架中,"app"目录是用于存放应用程序的核心代码和资源的目录。它是整个应用程序的主要工作目录,包含了应用的业务逻辑、控制器、模型、视图以及其他相关组件。
+### 系统目录介绍优化方案
 
-具体来说,"app"目录通常包含以下几个子目录和文件:
+#### 1. 引言
+在优化系统目录介绍时,我们的目标是使目录结构更加清晰、易于理解,并突出每个目录的核心功能和作用。
 
-app/adminapi:该目录包含管理端应用的控制器文件,用于处理用户请求、业务逻辑和数据交互等操作。
+#### 2. 目录结构优化概述
+我们将通过以下几个步骤来优化目录介绍:
+- **明确目录层级**:清晰展示主目录与子目录的关系。
+- **突出核心功能**:简要概括每个目录的主要作用和包含的文件类型。
+- **增加示例或用途说明**:对于关键目录,提供简短的示例或用途描述,帮助开发者快速理解。
 
-app/api:该目录包含用户端应用的控制器文件,用于处理用户请求、业务逻辑和数据交互等操作。
+#### 3. 优化后的目录介绍
 
-app/dao: 该目录包含数据访问对象(DAO)的类文件,用于封装数据访问操作,提供统一的数据访问接口。
+##### app/
+- **核心目录**:存放应用程序的核心代码和资源。
+- **包含内容**:业务逻辑、控制器、模型、视图等。
 
-app/http:该目录包含HTTP请求和响应跨域中间键。
+###### app/adminapi/
+- **功能**:管理端应用控制器。
+- **用途**:处理管理端用户请求、业务逻辑和数据交互。
+- **示例**:管理员登录、权限管理等。
 
-app/jobs:该目录包含所有的消息队列任务。
+###### app/api/
+- **功能**:用户端应用控制器。
+- **用途**:处理用户端请求、业务逻辑和数据交互。
+- **示例**:用户注册、商品浏览等。
 
-app/kefuapi:该目录包含客服端应用的控制器文件,用于处理用户请求、业务逻辑和数据交互等操作。
+###### app/dao/
+- **功能**:数据访问对象(DAO)。
+- **用途**:封装数据访问操作,提供统一接口。
+- **文件类型**:类文件。
 
-app/lang:该目录包含语言包文件,用于支持多语言功能。
+###### app/http/
+- **功能**:HTTP请求和响应跨域中间键。
+- **用途**:处理跨域请求,确保前后端通信顺畅。
 
-app/listener:该目录包含事件监听器的类文件,用于处理系统事件和事件通知。
+###### app/jobs/
+- **功能**:消息队列任务。
+- **用途**:处理异步任务,如邮件发送、数据同步等。
 
-app/model:该目录包含模型类文件,用于封装数据访问操作,提供统一的数据访问接口。
+###### app/kefuapi/
+- **功能**:客服端应用控制器。
+- **用途**:处理客服端请求、业务逻辑和数据交互。
+- **示例**:客服聊天、工单处理等。
 
-app/outapi:该目录包含对外接口应用的控制器文件,用于处理用户请求、业务逻辑和数据交互等操作。
+###### app/lang/
+- **功能**:语言包。
+- **用途**:支持多语言功能,提供不同语言的文本资源。
 
-app/service:该目录包含服务类文件,用于封装业务逻辑和数据交互操作,提供统一的服务接口。
+###### app/listener/
+- **功能**:事件监听器。
+- **用途**:监听和处理系统事件,如用户登录、订单生成等。
 
-除了上述目录外,"app"目录还可能包含其他自定义的子目录,用于组织应用的不同模块或功能。
+###### app/model/
+- **功能**:模型类。
+- **用途**:封装数据访问操作,提供统一接口。
+- **与dao区别**:模型类更侧重于业务逻辑层面的数据操作。
 
-总之,"app"目录是ThinkPHP应用程序的核心目录,其中的文件和目录结构定义了应用的业务逻辑、数据交互和用户界面等方面。开发者可以在该目录下编写和组织代码,实现具体的应用功能。
+###### app/outapi/
+- **功能**:对外接口应用控制器。
+- **用途**:处理外部系统请求、业务逻辑和数据交互。
+- **示例**:第三方支付回调、API对接等。
+
+###### app/service/
+- **功能**:服务类。
+- **用途**:封装业务逻辑和数据交互操作,提供统一服务接口。
+- **示例**:用户服务、订单服务等。
+
+#### 4. 结语
+通过上述优化,我们使`app`目录及其子目录的介绍更加清晰、条理分明。每个目录的核心功能和用途都得到了突出展示,有助于开发者快速理解和定位代码。同时,增加的示例和用途说明也进一步降低了理解门槛,提升了开发效率。

+ 3 - 3
crmeb/app/Request.php

@@ -34,7 +34,7 @@ class Request extends \think\Request
      * @var array
      */
     protected $except = ['menu_path', 'api_url', 'unique_auth',
-        'description', 'custom_form', 'content', 'tableField', 'url', 'customCode', 'value', 'refund_reason_wap_img'];
+        'description', 'custom_form', 'params_list', 'content', 'tableField', 'url', 'customCode', 'value', 'refund_reason_wap_img'];
 
     /**
      * 获取请求的数据
@@ -54,7 +54,7 @@ class Request extends \think\Request
                 if (!isset($param[1])) $param[1] = null;
                 if (!isset($param[2])) $param[2] = '';
                 if (is_array($param[0])) {
-                    $name = is_array($param[1]) ? $param[0][0] . '/a' : $param[0][0] . '/' . $param[0][1];
+                    $name = is_array($param[1]) ? $param[0][0] . '/a' : (sys_config('param_filter_type') == 1 ? $param[0] : $param[0][0] . '/' . $param[0][1]);
                     $keyName = $param[0][0];
                 } else {
                     $name = is_array($param[1]) ? $param[0] . '/a' : $param[0];
@@ -178,7 +178,7 @@ class Request extends \think\Request
     }
 
     /**
-     * 是否是app
+     * 是否是pc
      * @return bool
      */
     public function isPc()

+ 30 - 6
crmeb/app/adminapi/controller/Common.php

@@ -138,15 +138,26 @@ class Common extends AuthController
         return app('json')->success(compact('info'));
     }
 
-    //增长率
+    /**
+    * 计算增长率
+    * 特殊情况:
+    * 1. 当前值和上期值均为0时,返回0;
+    * 2. 上期值为0时,返回当前值;
+    * 3. 当前值为0时,返回上期值的负数。
+    *
+    * @param float $nowValue 当前值
+    * @param float $lastValue 上期值
+    * @return float 增长率
+    */
     public function growth($nowValue, $lastValue)
     {
-        if ($lastValue == 0 && $nowValue == 0) return 0;
-        if ($lastValue == 0) return round($nowValue, 2);
-        if ($nowValue == 0) return -round($lastValue, 2);
-        return bcmul(bcdiv((bcsub($nowValue, $lastValue, 2)), $lastValue, 2), 100, 2);
+       if ($lastValue == 0 && $nowValue == 0) return 0;
+       if ($lastValue == 0) return round($nowValue, 2);
+       if ($nowValue == 0) return -round($lastValue, 2);
+       return bcmul(bcdiv((bcsub($nowValue, $lastValue, 2)), $lastValue, 2), 100, 2);
     }
 
+
     /**
      * 订单图表
      */
@@ -393,6 +404,10 @@ class Common extends AuthController
         [$keyword] = $this->request->postMore([
             ['keyword', ''],
         ], true);
+        if (empty($keyword)) {
+           return app('json')->fail(400239, '关键字不能为空');
+        }
+
         // 获取系统菜单服务实例
         $menusServices = app()->make(SystemMenusServices::class);
         // 查询菜单列表
@@ -403,12 +418,15 @@ class Common extends AuthController
         $configTabServices = app()->make(SystemConfigTabServices::class);
         // 查询配置项列表
         $configList = $configServices->selectList([['info', 'like', '%' . $keyword . '%']], 'info as title,config_tab_id')->toArray();
+        // 查询配置项标签列表
         $configTabList = $configTabServices->selectList([['title', 'like', '%' . $keyword . '%']], 'title,id as config_tab_id')->toArray();
+        // 合并配置项列表和配置项标签列表
         $configAllList = array_merge($configList, $configTabList);
         // 获取配置项对应的标签ID
         $tabIds = array_unique(array_column($configAllList, 'config_tab_id'));
         // 查询配置项标签列表
         $tabList = $configTabServices->getColumn([['id', 'in', $tabIds]], 'menus_id', 'id');
+
         // 将配置项标签列表中的菜单ID与配置项列表中的菜单ID对应起来
         foreach ($configAllList as &$item1) {
             $item1['menus_id'] = $tabList[$item1['config_tab_id']] ?? 0;
@@ -417,6 +435,7 @@ class Common extends AuthController
         $configTabIds = array_values($tabList);
         // 查询配置项标签对应的菜单列表
         $configMenusList = $menusServices->getColumn([['id', 'in', $configTabIds]], 'menu_name as title,menu_path as path,id', 'id');
+
         // 将配置项列表中的菜单ID与配置项标签对应的菜单ID对应起来
         foreach ($configAllList as $item2) {
             if ($item2['menus_id'] == 0) {
@@ -429,8 +448,13 @@ class Common extends AuthController
             ];
         }
         // 将菜单列表中的路径前缀添加到每个菜单项的 path 属性上
+        $adminPrefix = '/' . Config::get('app.admin_prefix', 'admin');
         foreach ($menusList as &$item) {
-            $item['path'] = '/' . Config::get('app.admin_prefix', 'admin') . $item['path'];
+           if (strpos($item['path'], '/') !== 0) {
+               $item['path'] = $adminPrefix . '/' . ltrim($item['path'], '/');
+           } else {
+               $item['path'] = $adminPrefix . $item['path'];
+           }
         }
         // 返回 JSON 格式的菜单列表
         return app('json')->success($menusList);

+ 62 - 0
crmeb/app/adminapi/controller/PublicController.php

@@ -16,7 +16,9 @@ use app\Request;
 use app\services\system\attachment\SystemAttachmentServices;
 use app\services\system\SystemRouteServices;
 use crmeb\services\CacheService;
+use think\facade\Env;
 use think\Response;
+use think\facade\Db;
 
 class PublicController
 {
@@ -87,4 +89,64 @@ class PublicController
         app()->make(SystemRouteServices::class)->import($filePath);
         return app('json')->success(100010);
     }
+
+    /**
+     * 服务器信息
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/9/24
+     */
+    public function getSystemInfo()
+    {
+        $info['server'] = [
+            ['name' => '服务器系统', 'require' => '类UNIX', 'value' => PHP_OS],
+            ['name' => 'WEB环境', 'require' => 'Apache/Nginx/IIS', 'value' => $_SERVER['SERVER_SOFTWARE']],
+        ];
+        $gd_info = function_exists('gd_info') ? gd_info() : array();
+        $info['environment'] = [
+            ['name' => 'PHP版本', 'require' => '7.1-7.4', 'value' => phpversion()],
+            ['name' => 'MySql版本', 'require' => '5.6-8.0', 'value' => Db::query("SELECT VERSION()")[0]['VERSION()']],
+            ['name' => 'MySqli', 'require' => '开启', 'value' => function_exists('mysqli_connect')],
+            ['name' => 'Openssl', 'require' => '开启', 'value' => function_exists('openssl_encrypt')],
+            ['name' => 'Session', 'require' => '开启', 'value' => function_exists('session_start')],
+            ['name' => 'Safe_Mode', 'require' => '开启', 'value' => !ini_get('safe_mode')],
+            ['name' => 'GD', 'require' => '开启', 'value' => !empty($gd_info['GD Version'])],
+            ['name' => 'Curl', 'require' => '开启', 'value' => function_exists('curl_init')],
+            ['name' => 'Bcmath', 'require' => '开启', 'value' => function_exists('bcadd')],
+            ['name' => 'Upload', 'require' => '开启', 'value' => (bool)ini_get('file_uploads')],
+        ];
+
+        $info['permissions'] = [
+            ['name' => 'backup', 'require' => '读写', 'value' => is_readable(root_path('backup')) && is_writable(root_path('backup'))],
+            ['name' => 'public', 'require' => '读写', 'value' => is_readable(root_path('public')) && is_writable(root_path('public'))],
+            ['name' => 'runtime', 'require' => '读写', 'value' => is_readable(root_path('runtime')) && is_writable(root_path('runtime'))],
+            ['name' => '.env', 'require' => '读写', 'value' => is_readable(root_path() . '.env') && is_writable(root_path() . '.env')],
+            ['name' => '.version', 'require' => '读写', 'value' => is_readable(root_path() . '.version') && is_writable(root_path() . '.version')],
+            ['name' => '.constant', 'require' => '读写', 'value' => is_readable(root_path() . '.constant') && is_writable(root_path() . '.constant')],
+        ];
+        if (function_exists('exec')) {
+            $workermanOutput = $timerOutput = $queueOutput = [];
+            exec("ps aux | grep 'php think workerman' | grep -v grep", $workermanOutput);
+            exec("ps aux | grep 'php think timer' | grep -v grep", $timerOutput);
+            exec("ps aux | grep 'php think queue' | grep -v grep", $queueOutput);
+            $info['process'] = [
+                ['name' => '长链接', 'require' => '开启', 'value' => count($workermanOutput) > 0],
+                ['name' => '定时任务', 'require' => '开启', 'value' => count($timerOutput) > 0],
+                ['name' => '消息队列', 'require' => '开启', 'value' => count($queueOutput) > 0],
+            ];
+        } else {
+            $info['process'] = [
+                ['name' => '长链接', 'require' => '开启', 'value' => file_exists(root_path('runtime') . 'workerman.pid')],
+                ['name' => '定时任务', 'require' => '开启', 'value' => file_exists(root_path('runtime') . '.timer')],
+                ['name' => '消息队列', 'require' => '开启', 'value' => file_exists(root_path('runtime') . '.queue')],
+            ];
+        }
+        return app('json')->success($info);
+    }
+
+    public function customAdminJs()
+    {
+        return sys_config('custom_admin_js', '');
+    }
 }

文件差異過大導致無法顯示
+ 463 - 300
crmeb/app/adminapi/controller/UpgradeController.php


+ 31 - 0
crmeb/app/adminapi/controller/v1/agent/AgentLevel.php

@@ -184,4 +184,35 @@ class AgentLevel extends AuthController
         $this->services->update($id, ['status' => $status]);
         return app('json')->success(100014);
     }
+
+    /**
+     * 获取任务表单数量
+     * @param int $id 任务ID
+     * @return \think\response\Json
+     */
+    public function getTaskNumForm($id)
+    {
+        // 判断任务ID是否为0,若为0则返回错误信息
+        if ($id == 0) return app('json')->fail(100100);
+        // 调用服务层获取任务表单数量
+        $result = $this->services->getTaskNumForm($id);
+        // 返回成功信息和任务表单数量
+        return app('json')->success($result);
+    }
+
+    /**
+     * 设置任务数量
+     * @param int $id 任务ID
+     * @return \think\response\Json
+     */
+    public function setTaskNum($id)
+    {
+        // 从请求中获取任务数量
+        $data = $this->request->postMore([
+            ['task_num', 0]
+        ]);
+        // 调用服务层设置任务数量
+        $res = $this->services->setTaskNum($id, $data);
+        return app('json')->success(100014);
+    }
 }

+ 13 - 1
crmeb/app/adminapi/controller/v1/agent/AgentLevelTask.php

@@ -11,6 +11,7 @@
 namespace app\adminapi\controller\v1\agent;
 
 use app\adminapi\controller\AuthController;
+use app\services\agent\AgentLevelServices;
 use app\services\agent\AgentLevelTaskServices;
 use think\facade\App;
 
@@ -93,6 +94,10 @@ class AgentLevelTask extends AuthController
         $this->services->checkTypeTask(0, $data);
         $data['add_time'] = time();
         $this->services->save($data);
+        $levelInfo = app()->make(AgentLevelServices::class)->get((int)$data['level_id']);
+        $levelInfo->task_num = $levelInfo->task_num + 1;
+        $levelInfo->task_total_num = $levelInfo->task_total_num + 1;
+        $levelInfo->save();
         return app('json')->success(400210);
     }
 
@@ -162,8 +167,15 @@ class AgentLevelTask extends AuthController
         $levelTaskInfo = $this->services->getLevelTaskInfo((int)$id);
         if ($levelTaskInfo) {
             $res = $this->services->update($id, ['is_del' => 1]);
-            if (!$res)
+            if ($res) {
+                $levelInfo = app()->make(AgentLevelServices::class)->get((int)$levelTaskInfo['level_id']);
+                $levelInfo->task_num = $levelInfo->task_num - 1;
+                $levelInfo->task_total_num = $levelInfo->task_total_num - 1;
+                if ($levelInfo->task_num <= 0) $levelInfo->task_num = $levelInfo->task_total_num;
+                $levelInfo->save();
+            } else {
                 return app('json')->fail(100008);
+            }
         }
         return app('json')->success(100002);
     }

+ 23 - 0
crmeb/app/adminapi/controller/v1/agent/Division.php

@@ -286,4 +286,27 @@ class Division extends AuthController
         $this->services->divisionStaffSave($data);
         return app('json')->success(100000);
     }
+
+    /**
+     * 分销统计
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2025/4/8
+     */
+    public function divisionStatistics()
+    {
+        [$type, $time, $page, $limit, $sort, $order] = $this->request->getMore([
+            ['type', 0],
+            ['time', ''],
+            ['page', 1],
+            ['limit', 15],
+            ['sort', 'order_sum'],
+            ['order', 'desc'],
+        ], true);
+        $time = $time != '' ? explode('-', $time) : [];
+        $data = $this->services->divisionStatistics($type, $time, $page, $limit, $sort, $order);
+        return app('json')->success($data);
+
+    }
 }

+ 40 - 0
crmeb/app/adminapi/controller/v1/agent/SpreadApply.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace app\adminapi\controller\v1\agent;
+
+use app\adminapi\controller\AuthController;
+use app\services\agent\SpreadApplyServices;
+use think\facade\App;
+
+class SpreadApply extends AuthController
+{
+    public function __construct(App $app, SpreadApplyServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    public function applyList()
+    {
+        $where = $this->request->getMore([
+            ['status', ''],
+            ['keyword', ''],
+        ]);
+        return app('json')->success($this->services->applyList($where));
+    }
+
+    public function applyExamine($id, $uid, $status)
+    {
+        [$refusal_reason] = $this->request->postMore([
+            ['refusal_reason', ''],
+        ], true);
+        $this->services->applyExamine($id, $uid, $status, $refusal_reason);
+        return app('json')->success($status == 1 ? '审核通过' : '拒绝成功');
+    }
+
+    public function applyDelete($id)
+    {
+        $this->services->applyDelete($id);
+        return app('json')->success('删除成功');
+    }
+}

+ 9 - 3
crmeb/app/adminapi/controller/v1/application/wechat/WechatNewsCategory.php

@@ -179,9 +179,15 @@ class WechatNewsCategory extends AuthController
                         $errorLog[] = $v['nickname'] . '没有关注发送失败(不是微信公众号用户)';
                     }
                 }
-            } else return app('json')->fail(100031);
-            if (!count($errorLog)) return app('json')->success(100030);
-            else return app('json')->success(100030);
+                if (!count($errorLog)) {
+                    return app('json')->success(100030);
+                } else {
+                    return app('json')->fail(100031);
+                }
+            } else {
+                return app('json')->fail(100031);
+            }
+
         }
 
     }

+ 2 - 0
crmeb/app/adminapi/controller/v1/diy/Diy.php

@@ -610,6 +610,8 @@ class Diy extends AuthController
             ['status', 0],
             ['order_status', 0],
             ['my_banner_status', 0],
+            ['my_menus_status', 0],
+            ['business_status', 0],
             ['routine_my_banner', []],
             ['routine_my_menus', []]
         ]);

+ 151 - 0
crmeb/app/adminapi/controller/v1/diy/DiyPro.php

@@ -0,0 +1,151 @@
+<?php
+
+namespace app\adminapi\controller\v1\diy;
+
+use app\adminapi\controller\AuthController;
+use app\services\diy\DiyProServices;
+use app\services\product\product\StoreProductServices;
+use think\facade\App;
+
+class DiyPro extends AuthController
+{
+    public function __construct(App $app, DiyProServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    public function getList()
+    {
+        return app('json')->success($this->services->getList());
+    }
+
+    public function getInfo($id = 0)
+    {
+        if ($id == 0) return app('json')->fail('参数错误');
+        return app('json')->success($this->services->getInfo($id));
+    }
+
+    public function saveInfo($id = 0)
+    {
+        $data = $this->request->postMore([
+            ['name', ''],
+            ['title', ''],
+            ['value', ''],
+            ['type', 1],
+            ['cover_image', ''],
+            ['is_show', 0],
+            ['is_bg_color', 0],
+            ['is_bg_pic', 0],
+            ['bg_tab_val', 0],
+            ['color_picker', ''],
+            ['bg_pic', ''],
+            ['is_diy', 1],
+            ['is_pro', 1],
+            ['type', 2],
+        ]);
+        $value = is_string($data['value']) ? json_decode($data['value'], true) : $data['value'];
+        foreach ($value as &$item) {
+            if ($item['name'] === 'goodList') {
+                if (isset($item['selectConfig']['list'])) {
+                    unset($item['selectConfig']['list']);
+                }
+                if (isset($item['goodsList']['list']) && is_array($item['goodsList']['list'])) {
+                    $limitMax = config('database.page.limitMax', 50);
+                    if (isset($item['numConfig']['val']) && isset($item['tabConfig']['tabVal']) && $item['tabConfig']['tabVal'] == 0 && $item['numConfig']['val'] > $limitMax) {
+                        return app('json')->fail('您设置得商品个数超出系统限制,最大限制' . $limitMax . '个商品');
+                    }
+                    $item['goodsList']['ids'] = array_column($item['goodsList']['list'], 'id');
+                    unset($item['goodsList']['list'], $item['productList']['list']);
+                }
+            } elseif ($item['name'] === 'articleList') {
+                if (isset($item['selectList']['list']) && is_array($item['selectList']['list'])) {
+                    unset($item['selectList']['list']);
+                }
+            } elseif ($item['name'] === 'promotionList') {
+                if (isset($item['tabConfig']['list']) && $item['tabConfig']['list']) {
+                    $list = $item['tabConfig']['list'];
+                    foreach ($list as &$tabValue) {
+                        if (isset($tabValue['goodsList']['list']) && is_array($tabValue['goodsList']['list'])) {
+                            $limitMax = config('database.page.limitMax', 50);
+                            if (isset($tabValue['numConfig']['val']) && isset($tabValue['tabConfig']['tabVal']) && $tabValue['tabConfig']['tabVal'] == 0 && $tabValue['numConfig']['val'] > $limitMax) {
+                                return app('json')->fail('您设置得商品个数超出系统限制,最大限制' . $limitMax . '个商品');
+                            }
+                            $tabValue['goodsList']['ids'] = array_column($tabValue['goodsList']['list'], 'id');
+                        }
+                        unset($tabValue['goodsList']['list'], $item['productList']['list']);
+                    }
+                    $item['tabConfig']['list'] = $list;
+                }
+            } elseif ($item['name'] === 'newVip') {
+                unset($item['newVipList']['list']);
+            } elseif ($item['name'] === 'shortVideo') {
+                unset($item['videoList']);
+            }
+        }
+        $data['value'] = json_encode($value);
+        $data['version'] = uniqid();
+        return app('json')->success($id ? '修改成功' : '保存成功', ['id' => $this->services->saveInfo($id, $data)]);
+    }
+
+    public function delInfo($id)
+    {
+        $this->services->delInfo($id);
+        return app('json')->success('删除成功');
+    }
+
+    public function setInfoStatus($id)
+    {
+        return app('json')->success($this->services->setInfoStatus($id));
+    }
+
+    public function getProduct()
+    {
+        $where = $this->request->getMore([
+            ['cate_id', []],//搜索分类
+            ['salesOrder', ''],//销量排序
+            ['priceOrder', ''],//价格排序
+            ['store_label_id', []],//标签ID
+            ['ids', []],//商品ID
+        ]);
+        $where['is_show'] = 1;
+        $where['is_del'] = 0;
+        [$page, $limit] = $this->services->getPageValue();
+        $list = app()->make(StoreProductServices::class)->getSearchList($where, $page, $limit, ['id,store_name,cate_id,image,IFNULL(sales, 0) + IFNULL(ficti, 0) as sales,price,stock,activity,ot_price,spec_type,recommend_image,unit_name,is_vip,vip_price']);
+        return app('json')->success($list);
+    }
+
+    public function updateName($id = 0)
+    {
+        [$name] = $this->request->postMore([
+            ['name', '']
+        ], true);
+        if (!$name) return app('json')->fail('请输入名称');
+        $this->services->updateName($id, $name);
+        return app('json')->success('修改成功');
+    }
+
+    public function exportDIYData($id)
+    {
+        $value = $this->services->exportDIYData($id);
+        $filename = 'DIY数据_' . date('YmdHis', time()) . '.txt';
+        return app('json')->success('导出成功', ['value' => $value, 'filename' => $filename]);
+    }
+
+    public function importDIYData()
+    {
+        // 获取文件
+        $file = $this->request->file('file');
+        if (!$file) return app('json')->fail('请上传文件');
+
+        // 获取文件的临时路径
+        $tempPath = $file->getRealPath();
+
+        // 使用文件流读取内容
+        $content = file_get_contents($tempPath);
+
+        // 保存内容
+        $this->services->importDIYData($content);
+        return app('json')->success('导入成功');
+    }
+}

+ 74 - 0
crmeb/app/adminapi/controller/v1/diy/PageLink.php

@@ -12,6 +12,7 @@
 namespace app\adminapi\controller\v1\diy;
 
 use app\adminapi\controller\AuthController;
+use app\services\diy\DiyProServices;
 use app\services\diy\DiyServices;
 use app\services\diy\PageCategoryServices;
 use app\services\diy\PageLinkServices;
@@ -112,4 +113,77 @@ class PageLink extends AuthController
         return app('json')->success(100002);
     }
 
+    public function getLinkCategory()
+    {
+        return app('json')->success(app()->make(PageCategoryServices::class)->getSonCategoryList(1));
+    }
+
+    public function getLinkCategoryForm($cate_id, $pid)
+    {
+        return app('json')->success(app()->make(PageCategoryServices::class)->getLinkCategoryForm($cate_id, $pid));
+    }
+
+    public function getLinkCategorySave($cate_id)
+    {
+        $data = $this->request->postMore([
+            ['pid', 0],
+            ['name', ''],
+            ['type', ''],
+            ['sort', 0],
+            ['status', ''],
+        ]);
+        $res = app()->make(PageCategoryServices::class)->getLinkCategorySave($cate_id, $data);
+        return app('json')->success('保存成功');
+    }
+
+    public function getLinkCategoryDel($cate_id)
+    {
+        $res = app()->make(PageCategoryServices::class)->getLinkCategoryDel($cate_id);
+        return app('json')->success('删除成功');
+    }
+
+    public function getLinkList($cate_id, PageCategoryServices $pageCategoryServices)
+    {
+        if (!$cate_id) return app('json')->fail('参数错误');
+        $category = $pageCategoryServices->get((int)$cate_id);
+        if (!$category) {
+            return app('json')->fail(400103);
+        }
+        switch ($category['type']) {
+            case 'special':
+                /** @var DiyProServices $diyServices */
+                $diyProServices = app()->make(DiyProServices::class);
+                $data = $diyProServices->getList('link');
+                break;
+            case 'product_category':
+                /** @var StoreCategoryServices $storeCategoryServices */
+                $storeCategoryServices = app()->make(StoreCategoryServices::class);
+                $data = $storeCategoryServices->getList(['cate_name' => '', 'pid' => '', 'is_show' => '']);
+                break;
+            default:
+                $data = $this->services->getLinkList(['cate_id' => $cate_id]);
+                break;
+        }
+        return app('json')->success($data);
+    }
+
+    public function getLinkSave($id)
+    {
+        $data = $this->request->postMore([
+            ['cate_id', 0],
+            ['name', ''],
+            ['url', ''],
+            ['sort', 0],
+            ['status', 1],
+        ]);
+        $this->services->getLinkSave($id, $data);
+        return app('json')->success('保存成功');
+    }
+
+    public function getLinkDel($id)
+    {
+        $this->services->del($id);
+        return app('json')->success('删除成功');
+    }
+
 }

+ 25 - 1
crmeb/app/adminapi/controller/v1/file/SystemAttachment.php

@@ -45,7 +45,8 @@ class SystemAttachment extends AuthController
     {
         $where = $this->request->getMore([
             ['pid', 0],
-            ['real_name', '']
+            ['real_name', ''],
+            ['type', 0],
         ]);
         return app('json')->success($this->service->getImageList($where));
     }
@@ -199,4 +200,27 @@ class SystemAttachment extends AuthController
         $this->service->onlineUpload($data);
         return app('json')->success(100032);
     }
+
+    public function videoDataSave()
+    {
+        $data = $this->request->postMore([
+            ['pid', 0],
+            ['video_name', ''],
+            ['video_path', '']
+        ]);
+        $this->service->attachmentAdd(
+            $data['video_name'],
+            0,
+            'video/mp4',
+            $data['video_path'],
+            $data['video_path'],
+            $data['pid'],
+            (int)sys_config('upload_type', 1),
+            time(),
+            1,
+            1,
+            $data['video_name']
+        );;
+        return app('json')->success(100032);
+    }
 }

+ 10 - 4
crmeb/app/adminapi/controller/v1/file/SystemAttachmentCategory.php

@@ -49,7 +49,8 @@ class SystemAttachmentCategory extends AuthController
         $where = $this->request->getMore([
             ['name', ''],
             ['pid', 0],
-            ['all', 0]
+            ['all', 0],
+            ['type', 0],
         ]);
         if ($where['name'] != '' || $where['all'] == 1) $where['pid'] = '';
         return app('json')->success($this->service->getAll($where));
@@ -60,9 +61,13 @@ class SystemAttachmentCategory extends AuthController
      * @return mixed
      * @throws \FormBuilder\Exception\FormBuilderException
      */
-    public function create($id)
+    public function create()
     {
-        return app('json')->success($this->service->createForm($id));
+        [$id, $type] = $this->request->getMore([
+            ['id', 0],
+            ['type', 0],
+        ], true);
+        return app('json')->success($this->service->createForm($id, $type));
     }
 
     /**
@@ -73,7 +78,8 @@ class SystemAttachmentCategory extends AuthController
     {
         $data = $this->request->postMore([
             ['pid', 0],
-            ['name', '']
+            ['name', ''],
+            ['type', 0],
         ]);
         if (is_array($data['pid'])) $data['pid'] = end($data['pid']);
         if (!$data['name']) {

+ 10 - 1
crmeb/app/adminapi/controller/v1/finance/UserExtract.php

@@ -135,6 +135,15 @@ class UserExtract extends AuthController
     public function adopt($id)
     {
         if (!$id) app('json')->fail(100100);
-        return app('json')->success($this->services->adopt((int)$id) ? 100014 : 100015);
+        $res = $this->services->adopt((int)$id);
+        if ($res) {
+            if ($res === 'v3_extract') {
+                return app('json')->success('提现成功,等待用户确认收款');
+            } else {
+                return app('json')->success('提现成功');
+            }
+        } else {
+            return app('json')->success('操作失败');
+        }
     }
 }

+ 1 - 1
crmeb/app/adminapi/controller/v1/marketing/StoreCombination.php

@@ -169,7 +169,7 @@ class StoreCombination extends AuthController
             }
         }
         $this->services->update($id, ['is_show' => $status]);
-        return app('json')->success($status == 0 ? 100014 : 100015);
+        return app('json')->success('设置成功');
     }
 
     /**

+ 9 - 1
crmeb/app/adminapi/controller/v1/marketing/StoreCouponIssue.php

@@ -41,7 +41,7 @@ class StoreCouponIssue extends AuthController
         $where = $this->request->getMore([
             ['status', 1],
             ['coupon_title', ''],
-            ['receive_type', ''],
+            ['receive_type', '', '', 'receive_types'],
             ['type', ''],
             ['coupon_type', ''],
         ]);
@@ -74,6 +74,7 @@ class StoreCouponIssue extends AuthController
             ['sort', 0],
             ['status', 0],
             ['receive_limit', 1],
+            ['user_type', 1],
         ]);
         $res = $this->services->saveCoupon($data);
         if ($res) return app('json')->success(100000);
@@ -101,6 +102,13 @@ class StoreCouponIssue extends AuthController
         if (!$id) return app('json')->fail(100100);
         $info = $this->services->get($id);
         if ($info) $info = $info->toArray();
+        if ($info['receive_type'] == 1 || $info['receive_type'] == 3) {
+            $info['user_type'] = 1;
+        }
+        if ($info['receive_type'] == 4) {
+            $info['user_type'] = 2;
+            $info['receive_type'] = 1;
+        }
         if ($info['product_id'] != '') {
             $productIds = explode(',', $info['product_id']);
             /** @var StoreProductServices $product */

+ 56 - 1
crmeb/app/adminapi/controller/v1/marketing/StoreSeckill.php

@@ -12,6 +12,7 @@ namespace app\adminapi\controller\v1\marketing;
 
 use app\adminapi\controller\AuthController;
 use app\services\activity\seckill\StoreSeckillServices;
+use app\services\activity\StoreActivityServices;
 use app\services\product\sku\StoreProductAttrValueServices;
 use crmeb\services\CacheService;
 use think\facade\App;
@@ -43,6 +44,9 @@ class StoreSeckill extends AuthController
             [['status', 's'], ''],
             [['store_name', 's'], ''],
             [['product_id', 'd'], 0],
+            ['activity_name', ''],
+            ['time', ''],
+            ['time_ids', []],
         ]);
         return app('json')->success($this->services->systemPage($where));
     }
@@ -76,7 +80,7 @@ class StoreSeckill extends AuthController
             [['status', 'd'], 0],
             [['num', 'd'], 0],
             [['once_num', 'd'], 0],
-            [['time_id', 'd'], 0],
+            ['time_id', []],
             [['temp_id', 'd'], 0],
             [['sort', 'd'], 0],
             [['description', 's'], ''],
@@ -138,6 +142,11 @@ class StoreSeckill extends AuthController
     public function time_list()
     {
         $list['data'] = sys_data('routine_seckill_time');
+        foreach ($list['data'] as &$item) {
+            $startTime = sprintf("%02d:00", $item['time']);
+            $endTime = sprintf("%02d:00", $item['time'] + $item['continued']);
+            $item['time_name'] = $startTime . '-' . $endTime;
+        }
         return app('json')->success(compact('list'));
     }
 
@@ -181,4 +190,50 @@ class StoreSeckill extends AuthController
         ]);
         return app('json')->success($this->services->seckillOrder($id, $where));
     }
+
+    public function seckillActivityList()
+    {
+        $where = $this->request->getMore([
+            ['time', ''],
+            ['status', ''],
+            ['title', ''],
+            ['time_ids', []]
+        ]);
+        $where['is_del'] = 0;
+        $where['type'] = 1;
+        return app('json')->success(app()->make(StoreActivityServices::class)->activityList($where));
+    }
+
+    public function seckillActivityInfo($id)
+    {
+        return app('json')->success(app()->make(StoreActivityServices::class)->activityInfo($id));
+    }
+
+    public function seckillActivitySave($id)
+    {
+        $data = $this->request->postMore([
+            ['title', ''],
+            ['section_time', []],
+            ['time_ids', []],
+            ['num', 0],
+            ['once_num', 0],
+            ['status', 1],
+            ['is_commission', 0],
+            ['product_infos', []]
+        ]);
+        $this->services->seckillActivitySave($id, $data);
+        return app('json')->success('保存成功');
+    }
+
+    public function seckillActivityDel($id)
+    {
+        app()->make(StoreActivityServices::class)->activityDel($id, 1);
+        return app('json')->success('删除成功');
+    }
+
+    public function seckillActivityStatus($id, $status)
+    {
+        app()->make(StoreActivityServices::class)->activityStatus($id, $status, 1);
+        return app('json')->success('修改成功');
+    }
 }

+ 1 - 1
crmeb/app/adminapi/controller/v1/marketing/integral/StoreIntegralOrder.php

@@ -326,7 +326,7 @@ class StoreIntegralOrder extends AuthController
      */
     public function order_dump($order_id, StoreOrderDeliveryServices $storeOrderDeliveryServices)
     {
-        return app('json')->success($storeOrderDeliveryServices->orderDump($order_id));
+        return app('json')->success($storeOrderDeliveryServices->orderDump($order_id, 'integral_order'));
 
     }
 

+ 22 - 21
crmeb/app/adminapi/controller/v1/marketing/lottery/LuckLottery.php

@@ -41,11 +41,12 @@ class LuckLottery extends AuthController
      */
     public function index()
     {
-        $where = $this->request->postMore([
-            ['start_status', '', '', 'start'],
-            ['status', ''],
+        $where = $this->request->getMore([
             ['factor', ''],
-            ['store_name', '', '', 'keyword'],
+            ['start', ''],
+            ['status', ''],
+            ['time', ''],
+            ['keyword', ''],
         ]);
         return app('json')->success($this->services->getList($where));
     }
@@ -63,23 +64,7 @@ class LuckLottery extends AuthController
         if (!$id) {
             return app('json')->fail(100100);
         }
-        return app('json')->success($this->services->getlotteryInfo((int)$id));
-    }
-
-    /**
-     * 根据类型获取详情
-     * @param $factor
-     * @return mixed
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\DbException
-     * @throws \think\db\exception\ModelNotFoundException
-     */
-    public function factorInfo($factor)
-    {
-        if (!$factor) {
-            return app('json')->fail(100100);
-        }
-        return app('json')->success($this->services->getlotteryFactorInfo((int)$factor));
+        return app('json')->success($this->services->getLotteryInfo((int)$id));
     }
 
     /**
@@ -222,4 +207,20 @@ class LuckLottery extends AuthController
         $this->services->setStatus((int)$id, (int)$status);
         return app('json')->success(100014);
     }
+
+    public function factorList()
+    {
+        return app('json')->success($this->services->factorList());
+    }
+
+    public function factorUse()
+    {
+        $data = $this->request->postMore([
+            [['point', 'd'], 0],
+            [['pay', 'd'], 0],
+            [['evaluate', 'd'], 0],
+        ]);
+        $this->services->factorUse($data);
+        return app('json')->success('保存成功');
+    }
 }

+ 2 - 4
crmeb/app/adminapi/controller/v1/marketing/lottery/LuckLotteryRecord.php

@@ -42,12 +42,10 @@ class LuckLotteryRecord extends AuthController
     public function index()
     {
         $where = $this->request->postMore([
-            ['is_receive', ''],
-            ['is_deliver', ''],
             ['type', ''],
             ['keyword', ''],
-            ['data', '', '', 'time'],
-            ['factor', ''],
+            ['time', ''],
+            ['lottery_id', ''],
         ]);
         return app('json')->success($this->services->getList($where));
     }

+ 6 - 1
crmeb/app/adminapi/controller/v1/order/StoreOrder.php

@@ -908,7 +908,12 @@ class StoreOrder extends AuthController
         ], true);
         if (!$file) return app('json')->fail(400168);
         $file = public_path() . substr($file, 1);
-        $expressData = app()->make(FileService::class)->readExcel($file, 'express', 2);
+        // 获取文件后缀
+        $suffix = strtolower(pathinfo($file, PATHINFO_EXTENSION));
+        if (!in_array($suffix, ['xls', 'xlsx'])) {
+            return app('json')->fail('文件格式不正确,请上传xls或xlsx格式的文件!');
+        }
+        $expressData = app()->make(FileService::class)->readExcel($file, 'express', 2, ucfirst($suffix));
         foreach ($expressData as $item) {
             OrderExpressJob::dispatch([$item]);
         }

+ 1 - 1
crmeb/app/adminapi/controller/v1/order/StoreOrderInvoice.php

@@ -180,7 +180,7 @@ class StoreOrderInvoice extends AuthController
         foreach ($cartInfo as $item) {
             $goods[] = [
                 'store_name' => $item['cart_info']['productInfo']['store_name'],
-                'unit_price' => bcadd($item['cart_info']['sum_price'], $item['cart_info']['postage_price'], 2),
+                'unit_price' => bcadd($item['cart_info']['truePrice'], $item['cart_info']['postage_price'], 2),
                 'num' => $item['cart_info']['cart_num']
             ];
         }

+ 115 - 4
crmeb/app/adminapi/controller/v1/product/StoreProduct.php

@@ -12,6 +12,7 @@ namespace app\adminapi\controller\v1\product;
 
 
 use app\adminapi\controller\AuthController;
+use app\adminapi\controller\v1\system\SystemClearData;
 use app\services\order\StoreCartServices;
 use app\services\other\CacheServices;
 use app\services\product\product\StoreCategoryServices;
@@ -44,6 +45,12 @@ class StoreProduct extends AuthController
         $where = $this->request->getMore([
             ['store_name', ''],
             ['cate_id', ''],
+            ['spec_type', ''],
+            ['is_gift', ''],
+            ['vip_product', ''],
+            ['price_s', []],
+            ['stock_s', []],
+            ['sales_s', []],
         ]);
         $list = $this->service->getHeader($where);
         return app('json')->success(compact('list'));
@@ -127,7 +134,17 @@ class StoreProduct extends AuthController
             ['store_name', ''],
             ['cate_id', ''],
             ['type', 1],
-            ['sales', 'normal']
+            ['sales', 'normal'],
+            ['spec_type', ''],
+            ['is_gift', ''],
+            ['vip_product', ''],
+            ['price_s', []],
+            ['stock_s', []],
+            ['sales_s', []],
+            ['store_label_id', []],
+            ['logistics', ''],
+            ['time', ''],
+            ['virtual_type', ''],
         ]);
         $data = $this->service->getList($where);
         return app('json')->success($data);
@@ -246,6 +263,11 @@ class StoreProduct extends AuthController
             ['limit_type', 0],//限购类型
             ['limit_num', 0],//限购数量
             ['min_qty', 1],//起购数量
+            ['params_list', []],//商品参数
+            ['label_list', []],//商品标签
+            ['protection_list', []],//商品保障
+            ['is_gift', 0],//是否礼品
+            ['gift_price', 0],//礼品附加费
         ]);
         $this->service->save((int)$id, $data);
         return app('json')->success(100000);
@@ -282,7 +304,6 @@ class StoreProduct extends AuthController
             ['is_virtual', 0],
             ['virtual_type', 0]
         ]);
-        if ($id > 0 && $type == 1) $this->service->checkActivity($id);
         $info = $this->service->getAttr($data, $id, $type);
         return app('json')->success(compact('info'));
     }
@@ -305,7 +326,7 @@ class StoreProduct extends AuthController
             ['is_show', 1],
         ]);
         $where['is_del'] = 0;
-        $where['cate_id'] = stringToIntArray($where['cate_id']);
+        $where['cate_id'] = toIntArray($where['cate_id']);
         /** @var StoreCategoryServices $storeCategoryServices */
         $storeCategoryServices = app()->make(StoreCategoryServices::class);
         if ($where['cate_id'] !== '') {
@@ -391,9 +412,14 @@ class StoreProduct extends AuthController
         ]);
         if (!$data['file']) return app('json')->fail(400168);
         $file = public_path() . substr($data['file'], 1);
+        // 获取文件后缀
+        $suffix = strtolower(pathinfo($file, PATHINFO_EXTENSION));
+        if (!in_array($suffix, ['xls', 'xlsx'])) {
+            return app('json')->fail('文件格式不正确,请上传xls或xlsx格式的文件!');
+        }
         /** @var FileService $readExcelService */
         $readExcelService = app()->make(FileService::class);
-        $cardData = $readExcelService->readExcel($file, 'card');
+        $cardData = $readExcelService->readExcel($file, 'card', 1, ucfirst($suffix));
         return app('json')->success($cardData);
     }
 
@@ -419,4 +445,89 @@ class StoreProduct extends AuthController
         $this->service->batchSetting($data);
         return app('json')->success(100014);
     }
+
+    /**
+     * 商品类型接口
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/9/29
+     */
+    public function productTypeConfig()
+    {
+        $productTypeConfig = sys_config('product_type_config');
+        foreach ($productTypeConfig as $key => $value) {
+            $productTypeConfig[$key] = intval($value);
+        }
+        return app('json')->success(sys_config('product_type_config'));
+    }
+
+    /**
+     * 商品迁移导出
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/10/9
+     */
+    public function productExport()
+    {
+        $where = $this->request->getMore([
+            ['store_name', ''],
+            ['cate_id', ''],
+            ['type', 1],
+            ['sales', 'normal']
+        ]);
+        $where['virtual_type'] = 0;
+        return app('json')->success($this->service->productExportList($where));
+    }
+
+    /**
+     * 商品迁移导入
+     * @return \think\Response
+     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/10/9
+     */
+    public function productImport()
+    {
+        [$file] = $this->request->getMore([
+            ['file', ""]
+        ], true);
+        if (!$file) return app('json')->fail(400168);
+        $res = $this->service->productImport($file);
+        return app('json')->success('导入成功', $res);
+    }
+
+    /**
+     * 回收站商品彻底删除
+     * @param $id
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/10/9
+     */
+    public function fullDel($id)
+    {
+        app()->make(SystemClearData::class)->recycleProduct($id);
+        return app('json')->success('删除成功');
+    }
+
+    public function otherInfo($id, $type)
+    {
+        if (!$id) return app('json')->fail('参数错误');
+        return app('json')->success($this->service->otherInfo($id, $type));
+    }
+
+    public function otherSave($id, $type)
+    {
+        $data = $this->request->postMore([
+            ['is_sub', 0],
+            ['is_vip', 0],
+            ['vip_product', 0],
+            ['attr_value', []],
+        ]);
+        $this->service->otherSave($id, $type, $data);
+        return app('json')->success('保存成功');
+    }
 }

+ 113 - 0
crmeb/app/adminapi/controller/v1/product/StoreProductLabel.php

@@ -0,0 +1,113 @@
+<?php
+
+namespace app\adminapi\controller\v1\product;
+
+use app\adminapi\controller\AuthController;
+use app\services\product\product\StoreProductLabelCateServices;
+use app\services\product\product\StoreProductLabelServices;
+use think\facade\App;
+
+class StoreProductLabel extends AuthController
+{
+
+    private StoreProductLabelCateServices $labelCateServices;
+    private StoreProductLabelServices $labelServices;
+
+    public function __construct(App $app, StoreProductLabelCateServices $labelCateServices, StoreProductLabelServices $labelServices)
+    {
+        parent::__construct($app);
+        $this->labelCateServices = $labelCateServices;
+        $this->labelServices = $labelServices;
+    }
+
+    public function labelCateList()
+    {
+        $where = $this->request->getMore([
+            ['name', ''],
+        ]);
+        $where['is_del'] = 0;
+        return app('json')->success($this->labelCateServices->getLabelCateList($where));
+    }
+
+    public function labelCateForm($id)
+    {
+        return app('json')->success($this->labelCateServices->labelCateForm($id));
+    }
+
+    public function labelCateSave($id)
+    {
+        $data = $this->request->postMore([
+            ['name', ''],
+            ['sort', 0],
+        ]);
+        $this->labelCateServices->labelCateSave($id, $data);
+        return app('json')->success('保存成功');
+    }
+
+    public function labelCateDel($id)
+    {
+        $this->labelCateServices->labelCateDel($id);
+        return app('json')->success('删除成功');
+    }
+
+
+    public function labelList()
+    {
+        $where = $this->request->getMore([
+            ['name', ''],
+            ['cate_id', ''],
+            ['status', ''],
+            ['is_show', ''],
+        ]);
+        $where['is_del'] = 0;
+        return app('json')->success($this->labelServices->LabelList($where));
+    }
+
+    public function labelInfo($id)
+    {
+        return app('json')->success($this->labelServices->labelInfo($id));
+
+    }
+
+    public function labelSave()
+    {
+        $data = $this->request->postMore([
+            ['id', 0],
+            ['name', ''],
+            ['cate_id', 0],
+            ['type', 0],
+            ['font_color', ''],
+            ['bg_color', ''],
+            ['border_color', ''],
+            ['image', ''],
+            ['sort', 0],
+            ['status', 1],
+            ['is_show', 1],
+        ]);
+        $this->labelServices->labelSave($data);
+        return app('json')->success('保存成功');
+    }
+
+    public function labelDel($id)
+    {
+        $this->labelServices->labelDel($id);
+        return app('json')->success('删除成功');
+    }
+
+    public function labelIsShow($id, $is_show)
+    {
+        $this->labelServices->labelIsShow($id, $is_show);
+        return app('json')->success('修改成功');
+    }
+
+    public function labelStatus($id, $status)
+    {
+        $this->labelServices->labelStatus($id, $status);
+        return app('json')->success('修改成功');
+    }
+
+    public function labelUseList()
+    {
+        return app('json')->success($this->labelServices->labelUseList());
+    }
+}

+ 130 - 0
crmeb/app/adminapi/controller/v1/product/StoreProductParam.php

@@ -0,0 +1,130 @@
+<?php
+
+namespace app\adminapi\controller\v1\product;
+
+use app\adminapi\controller\AuthController;
+use app\services\product\product\StoreProductParamServices;
+use think\facade\App;
+
+/**
+ * 商品参数
+ * @author wuhaotian
+ * @email 442384644@qq.com
+ * @date 2024/12/17
+ */
+class StoreProductParam extends AuthController
+{
+    /**
+     * @param App $app
+     * @param StoreProductParamServices $services
+     */
+    public function __construct(App $app, StoreProductParamServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    /**
+     * 获取参数列表
+     * @return \think\Response
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    public function getParamList()
+    {
+        $where = $this->request->getMore([
+            ['name', '']
+        ]);
+        return app('json')->success($this->services->getParamList($where));
+    }
+
+    /**
+     * 获取参数详情
+     * @param $id
+     * @return \think\Response
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    public function getParamInfo($id)
+    {
+        if (!$id) return app('json')->fail('参数错误');
+        $info = $this->services->getParamInfo($id);
+        return app('json')->success($info);
+    }
+
+    /**
+     * 获取参数值
+     * @param $id
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    public function getParamValue($id)
+    {
+        if (!$id) return app('json')->fail('参数错误');
+        $info = $this->services->getParamValue($id);
+        return app('json')->success($info);
+    }
+
+    /**
+     * 保存参数
+     * @param $id
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    public function saveParamData($id)
+    {
+        $data = $this->request->postMore([
+            ['name', ''],
+            ['value', []],
+            ['sort', 0],
+            ['status', 1]
+        ]);
+        if (!$data['name']) return app('json')->fail('请输入参数名称');
+        if (!count($data['value'])) return app('json')->fail('请输入参数值');
+        $this->services->saveParamData($id, $data);
+        return app('json')->success('保存成功');
+    }
+
+    /**
+     * 修改参数状态
+     * @param $id
+     * @param $status
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    public function setParamStatus($id, $status)
+    {
+        if (!$id) return app('json')->fail('参数错误');
+        $this->services->setParamStatus($id, $status);
+        return app('json')->success('修改成功');
+    }
+
+    /**
+     * 删除参数
+     * @param $id
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    public function delParamData($id)
+    {
+        if (!$id) return app('json')->fail('参数错误');
+        $this->services->delParamData($id);
+        return app('json')->success('删除成功');
+    }
+}

+ 65 - 0
crmeb/app/adminapi/controller/v1/product/StoreProductProtection.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace app\adminapi\controller\v1\product;
+
+use app\adminapi\controller\AuthController;
+use app\services\product\product\StoreProductProtectionServices;
+use think\facade\App;
+
+class StoreProductProtection extends AuthController
+{
+    public function __construct(App $app, StoreProductProtectionServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    public function protectionList()
+    {
+        $where = $this->request->getMore([
+            ['title', ''],
+            ['status', '']
+        ]);
+        $where['is_del'] = 0;
+        return app('json')->success($this->services->protectionList($where));
+    }
+
+    public function protectionInfo($id)
+    {
+        if (!$id) return app('json')->fail('参数错误');
+        $info = $this->services->protectionInfo($id);
+        return app('json')->success($info);
+    }
+
+    public function protectionForm($id)
+    {
+        return app('json')->success($this->services->protectionForm($id));
+    }
+
+    public function protectionSave($id)
+    {
+        $data = $this->request->postMore([
+            ['title', ''],
+            ['content', ''],
+            ['image', ''],
+            ['sort', 0],
+            ['status', 0]
+        ]);
+        $this->services->protectionSave($id, $data);
+        return app('json')->success('保存成功');
+    }
+
+    public function protectionStatus($id, $status)
+    {
+        if (!$id) return app('json')->fail('参数错误');
+        $this->services->protectionStatus($id, $status);
+        return app('json')->success('修改成功');
+    }
+
+    public function protectionDel($id)
+    {
+        if (!$id) return app('json')->fail('参数错误');
+        $this->services->protectionDel($id);
+        return app('json')->success('删除成功');
+    }
+}

+ 100 - 10
crmeb/app/adminapi/controller/v1/setting/SystemConfig.php

@@ -14,6 +14,7 @@ use app\adminapi\controller\AuthController;
 use app\Request;
 use app\services\system\config\SystemConfigServices;
 use app\services\system\config\SystemConfigTabServices;
+use app\services\system\SystemPemServices;
 use crmeb\services\CacheService;
 use crmeb\services\easywechat\orderShipping\MiniOrderService;
 use think\facade\App;
@@ -352,34 +353,103 @@ class SystemConfig extends AuthController
         }
 
         if (isset($post['sign_give_point'])) {
-            if (!is_int($post['sign_give_point']) || $post['sign_give_point'] < 0) return app('json')->fail('签到赠送积分请填写大于等于0的整数');
+            if (!is_int($post['sign_give_point']) || $post['sign_give_point'] < 0) {
+                return app('json')->fail('签到赠送积分请填写大于等于0的整数');
+            }
         }
         if (isset($post['sign_give_exp'])) {
-            if ((int)$post['sign_give_exp'] < 0) return app('json')->fail('签到赠送经验请填写大于等于0的整数');
+            if ((int)$post['sign_give_exp'] < 0) {
+                return app('json')->fail('签到赠送经验请填写大于等于0的整数');
+            }
         }
         if (isset($post['integral_frozen'])) {
-            if (!ctype_digit($post['integral_frozen']) || $post['integral_frozen'] < 0) return app('json')->fail('积分冻结天数请填写大于等于0的整数');
+            if (!ctype_digit($post['integral_frozen']) || $post['integral_frozen'] < 0) {
+                return app('json')->fail('积分冻结天数请填写大于等于0的整数');
+            }
         }
         if (isset($post['store_free_postage'])) {
-            if (!is_int($post['store_free_postage']) || $post['store_free_postage'] < 0) return app('json')->fail('满额包邮请填写大于等于0的整数');
+            if (!is_int($post['store_free_postage']) || $post['store_free_postage'] < 0) {
+                return app('json')->fail('满额包邮请填写大于等于0的整数');
+            }
         }
         if (isset($post['withdrawal_fee'])) {
-            if ($post['withdrawal_fee'] < 0 || $post['withdrawal_fee'] > 100) return app('json')->fail('提现手续费范围在0-100之间');
+            if ($post['withdrawal_fee'] < 0 || $post['withdrawal_fee'] > 100) {
+                return app('json')->fail('提现手续费范围在0-100之间');
+            }
+        }
+        if (isset($post['routine_auth_type']) && count($post['routine_auth_type']) == 0) {
+            return app('json')->fail('微信和手机号登录开关至少开启一个');
         }
-        if (isset($post['routine_auth_type']) && count($post['routine_auth_type']) == 0) return app('json')->fail('微信和手机号登录开关至少开启一个');
         if (isset($post['integral_max_num'])) {
-            if (!ctype_digit($post['integral_max_num']) || $post['integral_max_num'] < 0) return app('json')->fail('积分抵扣上限请填写大于等于0的整数');
+            if (!ctype_digit($post['integral_max_num']) || $post['integral_max_num'] < 0) {
+                return app('json')->fail('积分抵扣上限请填写大于等于0的整数');
+            }
         }
         if (isset($post['customer_phone'])) {
-            if (!ctype_digit($post['customer_phone']) || strlen($post['customer_phone']) > 11) return app('json')->fail('客服手机号为11位数字');
+            if (!ctype_digit($post['customer_phone']) || strlen($post['customer_phone']) > 11) {
+                return app('json')->fail('客服手机号为11位数字');
+            }
         }
         if (isset($post['refund_time_available'])) {
-            if (!ctype_digit($post['refund_time_available'])) return app('json')->fail('售后期限必须为大于0的整数');
+            if (!ctype_digit($post['refund_time_available'])) {
+                return app('json')->fail('售后期限必须为大于0的整数');
+            }
+        }
+        if (isset($post['sms_save_type']) && sys_config('sms_account', '') != '') {
+            return app('json')->success(100001);
         }
         if (isset($post['param_filter_data'])) {
             $post['param_filter_data'] = base64_encode($post['param_filter_data']);
         }
-        if (isset($post['sms_save_type']) && sys_config('sms_account', '') != '') return app('json')->success(100001);
+        if (isset($post['product_type_config'])) {
+            if (count($post['product_type_config']) == 0) {
+                return app('json')->fail('商品类型至少选择一项');
+            }
+        }
+        if (isset($post['pay_weixin_client_cert'])) {
+            $certData = [
+                'type' => 'wechat',
+                'name' => 'pay_weixin_client_cert',
+                'path' => 'cert' . time() . rand(1000, 9999),
+                'content' => $post['pay_weixin_client_cert'] != '' ? file_get_contents($this->getPemPath($post['pay_weixin_client_cert'])) : '',
+            ];
+            $keyData = [
+                'type' => 'wechat',
+                'name' => 'pay_weixin_client_key',
+                'path' => 'key' . time() . rand(1000, 9999),
+                'content' => $post['pay_weixin_client_key'] != '' ? file_get_contents($this->getPemPath($post['pay_weixin_client_key'])) : '',
+            ];
+            $systemPemServices = app()->make(SystemPemServices::class);
+            $systemPemServices->savePem($certData);
+            $systemPemServices->savePem($keyData);
+        }
+
+        if (isset($post['merchant_cert_path'])) {
+            $merchantCertData = [
+                'type' => 'alipay',
+                'name' => 'merchant_cert_path',
+                'path' => 'merchant_cert' . time() . rand(1000, 9999),
+                'content' => $post['merchant_cert_path'] != '' ? file_get_contents($this->getPemPath($post['merchant_cert_path'])) : '',
+            ];
+            $alipayCertData = [
+                'type' => 'alipay',
+                'name' => 'alipay_cert_path',
+                'path' => 'alipay_cert' . time() . rand(1000, 9999),
+                'content' => $post['alipay_cert_path'] != '' ? file_get_contents($this->getPemPath($post['alipay_cert_path'])) : '',
+            ];
+            $alipayRootCertData = [
+                'type' => 'alipay',
+                'name' => 'alipay_root_cert_path',
+                'path' => 'alipay_root_cert' . time() . rand(1000, 9999),
+                'content' => $post['alipay_root_cert_path'] != '' ? file_get_contents($this->getPemPath($post['alipay_root_cert_path'])) : '',
+            ];
+            $systemPemServices = app()->make(SystemPemServices::class);
+            $systemPemServices->savePem($merchantCertData);
+            $systemPemServices->savePem($alipayCertData);
+            $systemPemServices->savePem($alipayRootCertData);
+        }
+
+
         foreach ($post as $k => $v) {
             $config_one = $this->services->getOne(['menu_name' => $k]);
             if ($config_one) {
@@ -392,6 +462,26 @@ class SystemConfig extends AuthController
         return app('json')->success(100001);
     }
 
+    /**
+     * 获取证书文件路径
+     * @param string $path
+     * @return string
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/10/21
+     */
+    public function getPemPath(string $path)
+    {
+        if (strstr($path, 'http://') || strstr($path, 'https://')) {
+            $path = parse_url($path)['path'] ?? '';
+        }
+        $path = root_path('runtime/pem') . ltrim($path, '/');
+        if (!file_exists($path)) {
+            $path = public_path('uploads') . ltrim($path, '/');
+        }
+        return $path;
+    }
+
     /**
      * 获取系统设置头部分类
      * @param SystemConfigTabServices $services

+ 5 - 11
crmeb/app/adminapi/controller/v1/setting/SystemOutAccount.php

@@ -91,11 +91,8 @@ class SystemOutAccount extends AuthController
         ]);
         $this->validate($data, StoreOutAccountValidate::class, 'save');
         if ($this->services->getOne(['appid' => $data['appid']])) return app('json')->fail('账号重复');
-        if (!$data['appsecret']) {
-            unset($data['appsecret']);
-        } else {
-            $data['appsecret'] = password_hash($data['appsecret'], PASSWORD_DEFAULT);
-        }
+        $data['apppwd'] = $data['appsecret'];
+        $data['appsecret'] = password_hash($data['appsecret'], PASSWORD_DEFAULT);
         $data['add_time'] = time();
         $data['rules'] = implode(',', $data['rules']);
         if (!$this->services->save($data)) {
@@ -122,12 +119,9 @@ class SystemOutAccount extends AuthController
         ]);
 
         $this->validate($data, StoreOutAccountValidate::class, 'update');
-        if (!$data['appsecret']) {
-            unset($data['appsecret']);
-        } else {
-            $data['appsecret'] = password_hash($data['appsecret'], PASSWORD_DEFAULT);
-        }
         if (!$this->services->getOne(['id' => $id])) return app('json')->fail('没有此账号');
+        $data['apppwd'] = $data['appsecret'];
+        $data['appsecret'] = password_hash($data['appsecret'], PASSWORD_DEFAULT);
         $data['rules'] = implode(',', $data['rules']);
         $res = $this->services->update($id, $data);
         if (!$res) {
@@ -256,6 +250,6 @@ class SystemOutAccount extends AuthController
             ['push_password', 0],
             ['push_token_url', '']
         ]);
-        return app('json')->success('100014',$this->services->textOutUrl($data));
+        return app('json')->success('100014', $this->services->textOutUrl($data));
     }
 }

+ 69 - 0
crmeb/app/adminapi/controller/v1/statistic/BalanceStatistic.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace app\adminapi\controller\v1\statistic;
+
+use app\adminapi\controller\AuthController;
+use app\services\user\UserMoneyServices;
+use think\facade\App;
+
+class BalanceStatistic extends AuthController
+{
+    /**
+     * @param App $app
+     * @param UserMoneyServices $services
+     */
+    public function __construct(App $app, UserMoneyServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    /**
+     * 余额统计基础信息
+     * @return mixed
+     */
+    public function getBasic()
+    {
+        $data = $this->services->getBasic();
+        return app('json')->success($data);
+    }
+
+    /**
+     * 余额统计趋势图
+     * @return mixed
+     */
+    public function getTrend()
+    {
+        $where = $this->request->getMore([
+            ['time', '']
+        ]);
+        $data = $this->services->getTrend($where);
+        return app('json')->success($data);
+    }
+
+    /**
+     * 余额来源
+     * @return mixed
+     */
+    public function getChannel()
+    {
+        $where = $this->request->getMore([
+            ['time', '']
+        ]);
+        $data = $this->services->getChannel($where);
+        return app('json')->success($data);
+    }
+
+    /**
+     * 余额类型
+     * @return mixed
+     */
+    public function getType()
+    {
+        $where = $this->request->getMore([
+            ['time', '']
+        ]);
+        $data = $this->services->getType($where);
+        return app('json')->success($data);
+    }
+}

+ 68 - 0
crmeb/app/adminapi/controller/v1/statistic/OrderStatistic.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace app\adminapi\controller\v1\statistic;
+
+use app\adminapi\controller\AuthController;
+use app\services\statistic\OrderStatisticServices;
+use think\facade\App;
+
+class OrderStatistic extends AuthController
+{
+    public function __construct(App $app, OrderStatisticServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    /**
+     * 订单统计基础信息
+     * @return mixed
+     */
+    public function getBasic()
+    {
+        $where = $this->request->getMore([
+            ['time', '']
+        ]);
+        $data = $this->services->getBasic($where);
+        return app('json')->success($data);
+    }
+
+    /**
+     * 订单统计趋势图
+     * @return mixed
+     */
+    public function getTrend()
+    {
+        $where = $this->request->getMore([
+            ['time', '']
+        ]);
+        $data = $this->services->getTrend($where);
+        return app('json')->success($data);
+    }
+
+    /**
+     * 订单来源
+     * @return mixed
+     */
+    public function getChannel()
+    {
+        $where = $this->request->getMore([
+            ['time', '']
+        ]);
+        $data = $this->services->getChannel($where);
+        return app('json')->success($data);
+    }
+
+    /**
+     * 订单类型
+     * @return mixed
+     */
+    public function getType()
+    {
+        $where = $this->request->getMore([
+            ['time', '']
+        ]);
+        $data = $this->services->getType($where);
+        return app('json')->success($data);
+    }
+}

+ 106 - 0
crmeb/app/adminapi/controller/v1/statistic/ProductStatistic.php

@@ -0,0 +1,106 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\adminapi\controller\v1\statistic;
+
+
+use app\adminapi\controller\AuthController;
+use app\services\statistic\ProductStatisticServices;
+use think\facade\App;
+
+/**
+ * Class ProductStatistic
+ * @package app\adminapi\controller\v1\statistic
+ */
+class ProductStatistic extends AuthController
+{
+    /**
+     * ProductStatistic constructor.
+     * @param App $app
+     * @param ProductStatisticServices $services
+     */
+    public function __construct(App $app, ProductStatisticServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    /**
+     * 商品基础
+     * @return mixed
+     */
+    public function getBasic()
+    {
+        $where = $this->request->getMore([
+            ['data', '', '', 'time']
+        ]);
+        return app('json')->success($this->services->getBasic($where));
+    }
+
+    /**
+     * 商品趋势
+     * @return mixed
+     */
+    public function getTrend()
+    {
+        $where = $this->request->getMore([
+            ['data', '', '', 'time']
+        ]);
+        $where['time'] = $this->getDay($where['time']);
+        return app('json')->success($this->services->getTrend($where));
+    }
+
+    /**
+     * 商品排行
+     * @return mixed
+     */
+    public function getProductRanking()
+    {
+        $where = $this->request->getMore([
+            ['data', '', '', 'time'],
+            ['sort', '']
+        ]);
+        $where['time'] = $this->getDay($where['time']);
+        return app('json')->success($this->services->getProductRanking($where));
+    }
+
+    /**
+     * 导出
+     * @return mixed
+     */
+    public function getExcel()
+    {
+        $where = $this->request->getMore([
+            ['data', '', '', 'time']
+        ]);
+        $where['time'] = $this->getDay($where['time']);
+        return app('json')->success($this->services->getTrend($where, true));
+    }
+
+    /**
+     * 格式化时间
+     * @param $time
+     * @return string
+     */
+    public function getDay($time)
+    {
+        if (strstr($time, '-') !== false) {
+            [$startTime, $endTime] = explode('-', $time);
+            if (!$startTime || !$endTime) {
+                return date("Y/m/d 00:00:00", strtotime("-30 days", time())) . '-' . date("Y/m/d 23:59:59", time());
+            } else {
+                return date('Y/m/d 00:00:00', strtotime($startTime)).'-'.date('Y/m/d 23:59:59', strtotime($endTime));
+            }
+        } else {
+            return date("Y/m/d 00:00:00", strtotime("-30 days", time())) . '-' . date("Y/m/d 23:59:59", time());
+        }
+    }
+}

+ 74 - 0
crmeb/app/adminapi/controller/v1/statistic/TradeStatistic.php

@@ -0,0 +1,74 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\adminapi\controller\v1\statistic;
+
+
+use app\adminapi\controller\AuthController;
+use app\services\statistic\TradeStatisticServices;
+use think\facade\App;
+
+/**
+ * Class TradeStatistic
+ * @package app\controller\admin\v1\statistic
+ */
+class TradeStatistic extends AuthController
+{
+    /**
+     * TradeStatistic constructor.
+     * @param App $app
+     * @param TradeStatisticServices $services
+     */
+    public function __construct(App $app, TradeStatisticServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    /**
+     * 顶部数据
+     * @return mixed
+     */
+    public function topTrade()
+    {
+        $leftToday = $this->services->getTopLeftTrade(['time' => 'today']);
+        $leftyestoday = $this->services->getTopLeftTrade(['time' => 'yestoday']);
+        $rightOne = $this->services->getTopRightOneTrade();
+        $rightTwo = $this->services->getTopRightTwoTrade();
+        $right = ['today' => $rightOne, 'month' => $rightTwo];
+        $totalleft = [$leftToday, $leftyestoday];
+        $left = [];
+        foreach ($totalleft as $k => $v) {
+            $left['name'] = "当日订单金额";
+            $left['x'] = $v['curve']['x'];
+            $left['series'][$k]['money'] = round($v['total_money'], 2);
+            $left['series'][$k]['value'] = array_values($v['curve']['y']);
+        }
+
+        $data['left'] = $left;
+        $data['right'] = $right;
+        return app('json')->success($data);
+    }
+
+    /**
+     * 底部数据
+     * @return mixed
+     */
+    public function bottomTrade()
+    {
+        $day = $this->request->getMore([
+            ['data', ""],
+        ]);
+        $bottom = $this->services->getBottomTrade($day);
+        return app('json')->success($bottom);
+    }
+
+}

+ 152 - 0
crmeb/app/adminapi/controller/v1/statistic/UserStatistic.php

@@ -0,0 +1,152 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\adminapi\controller\v1\statistic;
+
+
+use app\adminapi\controller\AuthController;
+use app\services\statistic\UserStatisticServices;
+use think\facade\App;
+
+/**
+ * Class UserStatistic
+ * @package app\adminapi\controller\v1\statistic
+ */
+class UserStatistic extends AuthController
+{
+    /**
+     * UserStatistic constructor.
+     * @param App $app
+     * @param UserStatisticServices $services
+     */
+    public function __construct(App $app, UserStatisticServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    /**
+     * 用户基础信息
+     * @return mixed
+     */
+    public function getBasic()
+    {
+        $where = $this->request->getMore([
+            ['channel_type', ''],
+            ['data', '', '', 'time']
+        ]);
+        return app('json')->success($this->services->getBasic($where));
+    }
+
+    /**
+     * 用户趋势
+     * @return mixed
+     */
+    public function getTrend()
+    {
+        $where = $this->request->getMore([
+            ['channel_type', ''],
+            ['data', '', '', 'time']
+        ]);
+        $where['time'] = $this->getDay($where['time']);
+        return app('json')->success($this->services->getTrend($where));
+    }
+
+    /**
+     * 微信用户信息
+     * @return mixed
+     */
+    public function getWechat()
+    {
+        $where = $this->request->getMore([
+            ['channel_type', ''],
+            ['data', '', '', 'time']
+        ]);
+        $where['time'] = $this->getDay($where['time']);
+        return app('json')->success($this->services->getWechat($where));
+    }
+
+    /**
+     * 微信用户趋势
+     * @return mixed
+     */
+    public function getWechatTrend()
+    {
+        $where = $this->request->getMore([
+            ['channel_type', ''],
+            ['data', '', '', 'time']
+        ]);
+        $where['time'] = $this->getDay($where['time']);
+        return app('json')->success($this->services->getWechatTrend($where));
+    }
+
+    /**
+     * 用户地域
+     * @return mixed
+     */
+    public function getRegion()
+    {
+        $where = $this->request->getMore([
+            ['channel_type', ''],
+            ['data', '', '', 'time'],
+            ['sort', 'allNum']
+        ]);
+        $where['time'] = $this->getDay($where['time']);
+        return app('json')->success($this->services->getRegion($where));
+    }
+
+    /**
+     * 用户性别
+     * @return mixed
+     */
+    public function getSex()
+    {
+        $where = $this->request->getMore([
+            ['channel_type', ''],
+            ['data', '', '', 'time']
+        ]);
+        $where['time'] = $this->getDay($where['time']);
+        return app('json')->success($this->services->getSex($where));
+    }
+
+    /**
+     * 用户统计导出
+     * @return mixed
+     */
+    public function getExcel()
+    {
+        $where = $this->request->getMore([
+            ['channel_type', ''],
+            ['data', '', '', 'time']
+        ]);
+        $where['time'] = $this->getDay($where['time']);
+        return app('json')->success($this->services->getTrend($where, true));
+    }
+
+    /**
+     * 格式化时间
+     * @param $time
+     * @return string
+     */
+    public function getDay($time)
+    {
+        if (strstr($time, '-') !== false) {
+            [$startTime, $endTime] = explode('-', $time);
+            if (!$startTime || !$endTime) {
+                return date("Y/m/d 00:00:00", strtotime("-30 days", time())) . '-' . date("Y/m/d 23:59:59", time());
+            } else {
+                return date('Y/m/d 00:00:00', strtotime($startTime)).'-'.date('Y/m/d 23:59:59', strtotime($endTime));
+            }
+        } else {
+            return date("Y/m/d 00:00:00", strtotime("-30 days", time())) . '-' . date("Y/m/d 23:59:59", time());
+        }
+    }
+}

+ 13 - 4
crmeb/app/adminapi/controller/v1/system/SystemClearData.php

@@ -100,11 +100,15 @@ class SystemClearData extends AuthController
      * 清除回收站商品
      * @return mixed
      */
-    public function recycleProduct()
+    public function recycleProduct($id = 0)
     {
         /** @var StoreProductServices $product */
         $product = app()->make(StoreProductServices::class);
-        $ids = $product->getColumn(['is_del' => 1], 'id');
+        if ($id) {
+            $ids = [$id];
+        } else {
+            $ids = $product->getColumn(['is_del' => 1], 'id');
+        }
         //清除规格表数据
         /** @var StoreProductAttrServices $ProductAttr */
         $productAttr = app()->make(StoreProductAttrServices::class);
@@ -145,8 +149,13 @@ class SystemClearData extends AuthController
 
         /** @var StoreProductServices $services */
         $services = app()->make(StoreProductServices::class);
-        $services->delete(1, 'is_del');
-        return app('json')->success(100046);
+        if ($id) {
+            $services->delete($id);
+            return true;
+        } else {
+            $services->delete(1, 'is_del');
+            return app('json')->success(100046);
+        }
     }
 
     /**

+ 88 - 0
crmeb/app/adminapi/controller/v1/system/SystemTicket.php

@@ -0,0 +1,88 @@
+<?php
+
+namespace app\adminapi\controller\v1\system;
+
+use app\adminapi\controller\AuthController;
+use app\services\system\SystemTicketServices;
+use think\facade\App;
+
+class SystemTicket extends AuthController
+{
+    public function __construct(App $app, SystemTicketServices $services)
+    {
+        parent::__construct($app);
+        $this->services = $services;
+    }
+
+    public function ticketList()
+    {
+        $where = $this->request->getMore([
+            ['type', 0],
+            ['keyword', ''],
+        ]);
+        return app('json')->success($this->services->ticketList($where));
+    }
+
+    public function ticketForm($id)
+    {
+        return app('json')->success($this->services->ticketForm($id));
+    }
+
+    public function ticketSave($id)
+    {
+        $data = $this->request->postMore([
+            ['print_name', ''],
+            ['type', 0],
+            ['yly_user_id', ''],
+            ['yly_app_id', ''],
+            ['yly_app_secret', ''],
+            ['yly_sn', ''],
+            ['fey_user', ''],
+            ['fey_ukey', ''],
+            ['fey_sn', ''],
+            ['times', 1],
+            ['print_type', 1],
+            ['status', 1],
+        ]);
+        $this->services->ticketSave($id, $data);
+        return app('json')->success('保存成功');
+    }
+
+    public function ticketSetStatus($id, $status)
+    {
+        $this->services->ticketSetStatus($id, $status);
+        return app('json')->success('修改成功');
+    }
+
+    public function ticketDel($id)
+    {
+        $this->services->ticketDel($id);
+        return app('json')->success('删除成功');
+    }
+
+    public function ticketContent($id)
+    {
+        return app('json')->success($this->services->ticketContent($id));
+    }
+
+    public function ticketContentSave($id)
+    {
+        $data = $this->request->postMore([
+            ['header', 0],
+            ['delivery', 0],
+            ['buyer_remarks', 0],
+            ['goods', []],
+            ['freight', 0],
+            ['preferential', 0],
+            ['pay', []],
+            ['custom', 0],
+            ['order', []],
+            ['code', 0],
+            ['code_url', ''],
+            ['show_notice', 0],
+            ['notice_content', '']
+        ]);
+        $this->services->ticketContentSave($id, $data);
+        return app('json')->success('保存成功');
+    }
+}

+ 50 - 4
crmeb/app/adminapi/controller/v1/user/User.php

@@ -10,8 +10,10 @@
 // +----------------------------------------------------------------------
 namespace app\adminapi\controller\v1\user;
 
+use app\services\system\config\SystemConfigServices;
 use app\services\user\UserServices;
 use app\adminapi\controller\AuthController;
+use crmeb\services\CacheService;
 use think\exception\ValidateException;
 use think\facade\App;
 
@@ -55,9 +57,15 @@ class User extends AuthController
             ['label_id', ''],
             ['now_money', 'normal'],
             ['field_key', ''],
-            ['isMember', '']
+            ['isMember', ''],
+            ['balance', []],
+            ['integral', []],
+            ['before_pay_time', ''],
+            ['pay_count_num', []],
+            ['pay_count_money', []],
+            ['recharge_count', []],
         ]);
-        $where['label_id'] = stringToIntArray($where['label_id']);
+        $where['label_id'] = toIntArray($where['label_id']);
         return app('json')->success($this->services->index($where));
     }
 
@@ -316,10 +324,10 @@ class User extends AuthController
      * @return mixed
      * @throws \FormBuilder\Exception\FormBuilderException
      */
-    public function edit_other($id)
+    public function edit_other($id, $type)
     {
         if (!$id) return app('json')->fail(100026);
-        return app('json')->success($this->services->editOther((int)$id));
+        return app('json')->success($this->services->editOther((int)$id, $type));
     }
 
     /**
@@ -450,4 +458,42 @@ class User extends AuthController
         return app('json')->success(400318);
     }
 
+    /**
+     * 新人礼
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/9/21
+     */
+    public function getNewGift()
+    {
+        $data = [
+            'reward_money' => intval(sys_config('reward_money')),
+            'reward_integral' => intval(sys_config('reward_integral')),
+            'reward_coupon' => sys_config('reward_coupon') == '' ? [] : sys_config('reward_coupon')
+        ];
+        return app('json')->success($data);
+    }
+
+    /**
+     * 保存新人礼
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/9/21
+     */
+    public function saveNewGift()
+    {
+        $data = $this->request->postMore([
+            ['reward_money', 0],
+            ['reward_integral', 0],
+            ['reward_coupon', '']
+        ]);
+        $configServices = app()->make(SystemConfigServices::class);
+        foreach ($data as $k => $v) {
+            $configServices->update($k, ['value' => json_encode($v)], 'menu_name');
+        }
+        CacheService::clear();
+        return app('json')->success('保存成功');
+    }
 }

+ 12 - 0
crmeb/app/adminapi/route/agent.php

@@ -79,6 +79,10 @@ Route::group('agent', function () {
         Route::get('get_level_form', 'v1.agent.AgentManage/getLevelForm')->name('getLevelForm')->option(['real_name' => '获取赠送分销等级表单']);
         //赠送分销等级
         Route::post('give_level', 'v1.agent.AgentManage/giveAgentLevel')->name('giveAgentLevel')->option(['real_name' => '赠送分销等级']);
+        //设置任务完成数量表单
+        Route::get('get_task_num_form/:id', 'v1.agent.AgentLevel/getTaskNumForm')->name('getTaskNumForm')->option(['real_name' => '获取任务完成数量表单']);
+        //设置完成任务数量
+        Route::post('set_task_num/:id', 'v1.agent.AgentLevel/setTaskNum')->name('setTaskNum')->option(['real_name' => '设置完成任务数量']);
     })->option(['parent' => 'agent', 'cate_name' => '分销等级']);
 
     /** 事业部 */
@@ -97,8 +101,16 @@ Route::group('agent', function () {
         Route::get('division/examine_apply/:id/:type', 'v1.agent.Division/examineApply')->name('examineApply')->option(['real_name' => '审核表单']);//审核表单
         Route::post('division/apply_agent/save', 'v1.agent.Division/applyAgentSave')->name('applyAgentSave')->option(['real_name' => '提交审核']);//提交审核
         Route::delete('division/del_apply/:id', 'v1.agent.Division/delApply')->name('delApply')->option(['real_name' => '删除审核']);//删除审核
+        Route::get('division/statistics', 'v1.agent.Division/divisionStatistics')->name('divisionStatistics')->option(['real_name' => '事业部统计']);//事业部统计
     })->option(['parent' => 'agent', 'cate_name' => '事业部']);
 
+    /** 分销员申请 */
+    Route::group(function () {
+        Route::get('spread/apply/list', 'v1.agent.SpreadApply/applyList')->name('applyList')->option(['real_name' => '分销员申请列表']);
+        Route::post('spread/apply/examine/:id/:uid/:status', 'v1.agent.SpreadApply/applyExamine')->name('applyExamine')->option(['real_name' => '分销员审核']);
+        Route::delete('spread/apply/del/:id', 'v1.agent.SpreadApply/applyDelete')->name('applyDelete')->option(['real_name' => '删除分销员申请']);
+    })->option(['parent' => 'agent', 'cate_name' => '分销员申请']);
+
 })->middleware([
     \app\http\middleware\AllowOriginMiddleware::class,
     \app\adminapi\middleware\AdminAuthTokenMiddleware::class,

+ 29 - 2
crmeb/app/adminapi/route/diy.php

@@ -12,7 +12,7 @@
 use think\facade\Route;
 
 /**
- * 分销管理 相关路由
+ * diy 相关路由
  */
 Route::group('diy', function () {
 
@@ -70,10 +70,37 @@ Route::group('diy', function () {
     //推荐商品
     Route::get('groom_list/:type', 'v1.diy.Diy/getGroomList')->option(['real_name' => '推荐商品']);
 
-
+    /** 系统链接管理 */
+    Route::get('link/category', 'v1.diy.PageLink/getLinkCategory')->option(['real_name' => '获取链接分类']);
+    Route::get('link/category/form/:cate_id/[:pid]', 'v1.diy.PageLink/getLinkCategoryForm')->option(['real_name' => '链接分类表单']);
+    Route::post('link/category/save/:cate_id', 'v1.diy.PageLink/getLinkCategorySave')->option(['real_name' => '链接分类保存']);
+    Route::delete('link/category/del/:cate_id', 'v1.diy.PageLink/getLinkCategoryDel')->option(['real_name' => '链接分类删除']);
+    Route::get('link/list/:cate_id', 'v1.diy.PageLink/getLinkList')->option(['real_name' => '链接列表']);
+    Route::post('link/save/:id', 'v1.diy.PageLink/getLinkSave')->option(['real_name' => '链接保存']);
+    Route::delete('link/del/:id', 'v1.diy.PageLink/getLinkDel')->option(['real_name' => '链接删除']);
 })->middleware([
     \app\http\middleware\AllowOriginMiddleware::class,
     \app\adminapi\middleware\AdminAuthTokenMiddleware::class,
     \app\adminapi\middleware\AdminCheckRoleMiddleware::class,
     \app\adminapi\middleware\AdminLogMiddleware::class
 ])->option(['mark' => 'diy', 'mark_name' => '页面装修']);
+
+
+/**
+ * diy_pro 相关路由
+ */
+Route::group('diy_pro', function () {
+
+    Route::get('get_list', 'v1.diy.DiyPro/getList')->option(['real_name' => 'DiyPro模板列表']);
+    Route::get('get_info/:id', 'v1.diy.DiyPro/getInfo')->option(['real_name' => 'DiyPro模板详情']);
+    Route::post('save/:id', 'v1.diy.DiyPro/saveInfo')->option(['real_name' => 'DiyPro模板保存']);
+    Route::get('get_product', 'v1.diy.DiyPro/getProduct')->option(['real_name' => '获取商品列表']);
+    Route::post('update/name/:id', 'v1.diy.DiyPro/updateName')->option(['real_name' => '修改名称']);
+    Route::get('export/data/:id', 'v1.diy.DiyPro/exportDIYData')->option(['real_name' => '导出DIY数据']);
+    Route::post('import/data', 'v1.diy.DiyPro/importDIYData')->option(['real_name' => '导入DIY数据']);
+})->middleware([
+    \app\http\middleware\AllowOriginMiddleware::class,
+    \app\adminapi\middleware\AdminAuthTokenMiddleware::class,
+    \app\adminapi\middleware\AdminCheckRoleMiddleware::class,
+    \app\adminapi\middleware\AdminLogMiddleware::class
+])->option(['mark' => 'diy_pro', 'mark_name' => '页面装修']);

+ 2 - 1
crmeb/app/adminapi/route/file.php

@@ -42,7 +42,8 @@ Route::group('file', function () {
     Route::get('upload_type', 'v1.file.SystemAttachment/uploadType')->option(['real_name' => '上传类型']);
     //分片上传本地视频
     Route::post('video_upload', 'v1.file.SystemAttachment/videoUpload')->option(['real_name' => '分片上传本地视频']);
-
+    //云存储视频保存数据
+    Route::post('video_data_save', 'v1.file.SystemAttachment/videoDataSave')->option(['real_name' => '云存储视频保存数据']);
     //获取扫码上传页面链接以及参数
     Route::get('scan_upload/qrcode', 'v1.file.SystemAttachment/scanUploadQrcode')->option(['real_name' => '扫码上传页面链接']);
     //删除扫码上传token

+ 15 - 3
crmeb/app/adminapi/route/marketing.php

@@ -111,6 +111,15 @@ Route::group('marketing', function () {
         Route::get('seckill/statistics/people/:id', 'v1.marketing.StoreSeckill/seckillPeople')->option(['real_name' => '秒杀参与人']);
         //秒杀订单
         Route::get('seckill/statistics/order/:id', 'v1.marketing.StoreSeckill/seckillOrder')->option(['real_name' => '秒杀参与人']);
+
+        Route::get('seckill_activity/list', 'v1.marketing.StoreSeckill/seckillActivityList')->option(['real_name' => '秒杀活动列表']);
+        Route::get('seckill_activity/info/:id', 'v1.marketing.StoreSeckill/seckillActivityInfo')->option(['real_name' => '秒杀活动详情']);
+        Route::post('seckill_activity/save/:id', 'v1.marketing.StoreSeckill/seckillActivitySave')->option(['real_name' => '新增或修改秒杀活动']);
+        Route::delete('seckill_activity/del/:id', 'v1.marketing.StoreSeckill/seckillActivityDel')->option(['real_name' => '删除秒杀活动']);
+        Route::put('seckill_activity/status/:id/:status', 'v1.marketing.StoreSeckill/seckillActivityStatus')->option(['real_name' => '修改秒杀活动状态']);
+
+
+
     })->option(['parent' => 'marketing', 'cate_name' => '秒杀活动']);
 
     /** 积分活动 */
@@ -182,8 +191,6 @@ Route::group('marketing', function () {
         Route::get('lottery/list', 'v1.marketing.lottery.LuckLottery/index')->option(['real_name' => '抽奖活动列表']);
         //抽奖活动详情
         Route::get('lottery/detail/:id', 'v1.marketing.lottery.LuckLottery/detail')->option(['real_name' => '抽奖活动详情']);
-        //抽奖活动详情
-        Route::get('lottery/factor_info/:factor', 'v1.marketing.lottery.LuckLottery/factorInfo')->option(['real_name' => '抽奖活动详情']);
         //添加抽奖活动
         Route::post('lottery/add', 'v1.marketing.lottery.LuckLottery/add')->option(['real_name' => '添加抽奖活动']);
         //修改抽奖活动数据
@@ -191,11 +198,16 @@ Route::group('marketing', function () {
         //删除抽奖活动
         Route::delete('lottery/del/:id', 'v1.marketing.lottery.LuckLottery/delete')->option(['real_name' => '删除抽奖活动']);
         //设置抽奖活动是否显示
-        Route::post('lottery/set_status/:id/:status', 'v1.marketing.lottery.LuckLottery/setStatus')->option(['real_name' => '设置抽奖活动是否显示']);
+        Route::put('lottery/set_status/:id/:status', 'v1.marketing.lottery.LuckLottery/setStatus')->option(['real_name' => '设置抽奖活动是否显示']);
         //抽奖记录列表
         Route::get('lottery/record/list', 'v1.marketing.lottery.LuckLotteryRecord/index')->option(['real_name' => '抽奖记录列表']);
         //抽奖中奖发货、备注处理
         Route::post('lottery/record/deliver', 'v1.marketing.lottery.LuckLotteryRecord/deliver')->option(['real_name' => '抽奖中奖发货、备注处理']);
+        //分类抽奖列表
+        Route::get('lottery/factor/list', 'v1.marketing.lottery.LuckLottery/factorList')->option(['real_name' => '分类抽奖列表']);
+        //保存抽奖配置
+        Route::post('lottery/factor/use', 'v1.marketing.lottery.LuckLottery/factorUse')->option(['real_name' => '保存抽奖使用状态']);
+
     })->option(['parent' => 'marketing', 'cate_name' => '抽奖活动']);
 
     /** 每日签到 */

+ 48 - 0
crmeb/app/adminapi/route/product.php

@@ -85,6 +85,18 @@ Route::group('product', function () {
         Route::post('generate_attr/:id/:type', 'v1.product.StoreProduct/is_format_attr')->option(['real_name' => '生成商品规格列表']);
         //商品批量操作
         Route::post('batch/setting', 'v1.product.StoreProduct/batchSetting')->option(['real_name' => '商品批量设置']);
+        //商品类型接口
+        Route::get('product_type_config', 'v1.product.StoreProduct/productTypeConfig')->option(['real_name' => '商品类型接口']);
+        //商品迁移导出
+        Route::get('product_export', 'v1.product.StoreProduct/productExport')->option(['real_name' => '商品迁移导出']);
+        //商品迁移导入
+        Route::post('product_import', 'v1.product.StoreProduct/productImport')->option(['real_name' => '商品迁移导出']);
+        //回收站商品彻底删除
+        Route::delete('full_del/:id', 'v1.product.StoreProduct/fullDel')->option(['real_name' => '回收站商品彻底删除']);
+
+        Route::get('other_info/:id/:type', 'v1.product.StoreProduct/otherInfo')->option(['real_name' => '商品其他信息']);
+        Route::post('other_save/:id/:type', 'v1.product.StoreProduct/otherSave')->option(['real_name' => '修改商品其他信息']);
+
     })->option(['parent' => 'product', 'cate_name' => '商品']);
 
     /** 商品评论 */
@@ -115,6 +127,42 @@ Route::group('product', function () {
         Route::post('crawl/save', 'v1.product.CopyTaobao/save_product')->option(['real_name' => '保存采集商品数据']);
     })->option(['parent' => 'product', 'cate_name' => '商品采集']);
 
+    /** 商品标签 */
+    Route::group(function () {
+        //商品标签分类
+        Route::get('label_cate/list', 'v1.product.StoreProductLabel/labelCateList')->option(['real_name' => '商品标签分类']);
+        Route::get('label_cate/form/:id', 'v1.product.StoreProductLabel/labelCateForm')->option(['real_name' => '商品标签分类添加表单']);
+        Route::post('label_cate/save/:id', 'v1.product.StoreProductLabel/labelCateSave')->option(['real_name' => '商品标签分类保存']);
+        Route::delete('label_cate/del/:id', 'v1.product.StoreProductLabel/labelCateDel')->option(['real_name' => '商品标签分类删除']);
+        Route::get('label/list', 'v1.product.StoreProductLabel/labelList')->option(['real_name' => '商品标签列表']);
+        Route::get('label/info/:id', 'v1.product.StoreProductLabel/labelInfo')->option(['real_name' => '商品标签详情']);
+        Route::post('label/save', 'v1.product.StoreProductLabel/labelSave')->option(['real_name' => '商品标签保存']);
+        Route::delete('label/del/:id', 'v1.product.StoreProductLabel/labelDel')->option(['real_name' => '商品标签删除']);
+        Route::put('label/status/:id/:status', 'v1.product.StoreProductLabel/labelStatus')->option(['real_name' => '修改商品标签状态']);
+        Route::put('label/is_show/:id/:is_show', 'v1.product.StoreProductLabel/labelIsShow')->option(['real_name' => '修改商品标签显示']);
+        Route::get('label/use_list', 'v1.product.StoreProductLabel/labelUseList')->option(['real_name' => '使用商品标签列表']);
+    })->option(['parent' => 'product', 'cate_name' => '商品标签']);
+
+    /** 商品参数 */
+    Route::group(function () {
+        Route::get('param/list', 'v1.product.StoreProductParam/getParamList')->option(['real_name' => '商品参数列表']);
+        Route::get('param/info/:id', 'v1.product.StoreProductParam/getParamInfo')->option(['real_name' => '商品参数详情']);
+        Route::get('param/value/:id', 'v1.product.StoreProductParam/getParamValue')->option(['real_name' => '商品参数值']);
+        Route::post('param/save/:id', 'v1.product.StoreProductParam/saveParamData')->option(['real_name' => '保存商品参数']);
+        Route::put('param/status/:id/:status', 'v1.product.StoreProductParam/setParamStatus')->option(['real_name' => '修改商品参数状态']);
+        Route::delete('param/del/:id', 'v1.product.StoreProductParam/delParamData')->option(['real_name' => '删除商品参数']);
+    })->option(['parent' => 'product', 'cate_name' => '商品参数']);
+
+    /** 商品保障 */
+    Route::group(function () {
+        Route::get('protection/list', 'v1.product.StoreProductProtection/protectionList')->option(['real_name' => '商品保障列表']);
+        Route::get('protection/info/:id', 'v1.product.StoreProductProtection/protectionInfo')->option(['real_name' => '商品保障详情']);
+        Route::get('protection/form/:id', 'v1.product.StoreProductProtection/protectionForm')->option(['real_name' => '商品保障表单']);
+        Route::post('protection/save/:id', 'v1.product.StoreProductProtection/protectionSave')->option(['real_name' => '保存商品保障']);
+        Route::put('protection/status/:id/:status', 'v1.product.StoreProductProtection/protectionStatus')->option(['real_name' => '修改商品保障状态']);
+        Route::delete('protection/del/:id', 'v1.product.StoreProductProtection/protectionDel')->option(['real_name' => '删除商品保障']);
+    })->option(['parent' => 'product', 'cate_name' => '商品参数']);
+
 })->middleware([
     \app\http\middleware\AllowOriginMiddleware::class,
     \app\adminapi\middleware\AdminAuthTokenMiddleware::class,

+ 6 - 6
crmeb/app/adminapi/route/route.php

@@ -19,6 +19,7 @@ use app\http\middleware\AllowOriginMiddleware;
 Route::group(function () {
     //升级程序
     Route::get('upgrade', 'UpgradeController/index');
+    Route::get('upgrade/run', 'UpgradeController/upgrade');
     //用户名密码登录
     Route::post('login', 'Login/login')->name('AdminLogin')->option(['real_name' => '下载表备份记录']);
     //后台登录页面数据
@@ -33,29 +34,28 @@ Route::group(function () {
     Route::get('get_workerman_url', 'PublicController/getWorkerManUrl')->option(['real_name' => '获取客服数据']);
     //测试
     Route::get('index', 'Test/index')->option(['real_name' => '测试地址']);
-
     //扫码上传图片
     Route::post('image/scan_upload', 'PublicController/scanUpload')->option(['real_name' => '扫码上传图片']);
-
+    Route::get('custom_admin_js', 'PublicController/customAdminJs')->option(['real_name' => '测试地址']);
 
 })->middleware(AllowOriginMiddleware::class)->option(['mark' => 'login', 'mark_name' => '登录相关']);
 
+
 /**
  * 需授权的接口
  */
 Route::group(function () {
-    //升级程序
-    Route::get('upgrade/run', 'UpgradeController/upgrade');
+    //服务器信息
+    Route::get('system/info', 'PublicController/getSystemInfo')->option(['real_name' => '服务器信息']);
     //路由导入
     Route::get('route/import_api', 'PublicController/import')->option(['real_name' => '路由导入']);
     //下载文件
     Route::get('download/[:key]', 'PublicController/download')->option(['real_name' => '下载文件']);
 })->middleware([
     AllowOriginMiddleware::class,
-    \app\adminapi\middleware\AdminAuthTokenMiddleware::class
+//    \app\adminapi\middleware\AdminAuthTokenMiddleware::class
 ])->option(['mark' => 'system', 'mark_name' => '系统相关']);
 
-
 /**
  * miss 路由
  */

+ 11 - 0
crmeb/app/adminapi/route/system.php

@@ -232,6 +232,17 @@ Route::group('system', function () {
         Route::post('crud', 'v1.setting.SystemCrud/save')->option(['real_name' => '保存生成CRUD']);
     })->option(['parent' => 'system', 'cate_name' => '代码生成']);
 
+    /** 小票打印 */
+    Route::group(function () {
+        Route::get('ticket/list', 'v1.system.SystemTicket/ticketList')->option(['real_name' => '小票打印列表']);
+        Route::get('ticket/form/:id', 'v1.system.SystemTicket/ticketForm')->option(['real_name' => '添加修改小票打印表单']);
+        Route::post('ticket/save/:id', 'v1.system.SystemTicket/ticketSave')->option(['real_name' => '添加修改小票打印']);
+        Route::post('ticket/set_status/:id/:status', 'v1.system.SystemTicket/ticketSetStatus')->option(['real_name' => '修改小票打印状态']);
+        Route::delete('ticket/del/:id', 'v1.system.SystemTicket/ticketDel')->option(['real_name' => '删除小票打印']);
+        Route::get('ticket/content/:id', 'v1.system.SystemTicket/ticketContent')->option(['real_name' => '获取小票打印详情']);
+        Route::post('ticket/save_content/:id', 'v1.system.SystemTicket/ticketContentSave')->option(['real_name' => '保存小票打印详情']);
+    })->option(['parent' => 'system', 'cate_name' => '小票打印']);
+
 })->middleware([
     \app\http\middleware\AllowOriginMiddleware::class,
     \app\adminapi\middleware\AdminAuthTokenMiddleware::class,

+ 7 - 1
crmeb/app/adminapi/route/user.php

@@ -46,7 +46,7 @@ Route::group('user', function () {
         //清除会员等级
         Route::delete('del_level/:id', 'v1.user.User/del_level')->option(['real_name' => '清除用户等级']);
         //编辑其他
-        Route::get('edit_other/:id', 'v1.user.User/edit_other')->option(['real_name' => '修改积分余额表单']);
+        Route::get('edit_other/:id/:type', 'v1.user.User/edit_other')->option(['real_name' => '修改积分余额表单']);
         //编辑其他
         Route::put('update_other/:id', 'v1.user.User/update_other')->option(['real_name' => '修改积分余额']);
         //修改用户状态
@@ -180,6 +180,12 @@ Route::group('user', function () {
         Route::get('cancel/refuse/:id', 'v1.user.UserCancel/refuseCancel')->option(['real_name' => '拒绝注销']);
     })->option(['parent' => 'user', 'cate_name' => '用户注销']);
 
+    /** 新人礼 */
+    Route::group(function () {
+        Route::get('new_gift', 'v1.user.User/getNewGift')->option(['real_name' => '获取新人礼']);
+        Route::post('new_gift/save', 'v1.user.User/saveNewGift')->option(['real_name' => '保存新人礼']);
+    })->option(['parent' => 'user', 'cate_name' => '新人礼']);
+
 })->middleware([
     \app\http\middleware\AllowOriginMiddleware::class,
     \app\adminapi\middleware\AdminAuthTokenMiddleware::class,

+ 1 - 10
crmeb/app/adminapi/validate/setting/SystemConfigValidata.php

@@ -32,7 +32,7 @@ class SystemConfigValidata extends Validate
         'site_url' => 'url',
         'store_brokerage_ratio' => 'float|egt:0|elt:100|regex:float_two',
         'store_brokerage_two' => 'float|egt:0|elt:100|regex:float_two',
-        'user_extract_min_price' => 'float|gt:0|checkMinPrice',
+        'user_extract_min_price' => 'float|gt:0',
         'extract_time' => 'number|between:0,180',
         'replenishment_num' => 'number',
         'store_stock' => 'number',
@@ -149,13 +149,4 @@ class SystemConfigValidata extends Validate
     protected $scene = [
 
     ];
-
-
-    protected function checkMinPrice($value, $rule, $data = [])
-    {
-        if ($data['brokerage_type'] == 1 && bccomp($value, '1', 2) < 0) {
-            return 410112;
-        }
-        return true;
-    }
 }

+ 1 - 1
crmeb/app/api/controller/v1/CrontabController.php

@@ -134,4 +134,4 @@ class CrontabController
         $attach = app()->make(SystemAttachmentServices::class);
         $attach->emptyYesterdayAttachment();
     }
-}
+}

+ 11 - 11
crmeb/app/api/controller/v1/LoginController.php

@@ -48,8 +48,8 @@ class LoginController
      */
     public function login(Request $request)
     {
-        [$account, $password, $spread] = $request->postMore([
-            'account', 'password', 'spread'
+        [$account, $password, $spread, $agent_id] = $request->postMore([
+            'account', 'password', 'spread', ['agent_id', 0]
         ], true);
         if (!$account || !$password) {
             return app('json')->fail(410000);
@@ -57,7 +57,7 @@ class LoginController
         if (strlen(trim($password)) < 6 || strlen(trim($password)) > 32) {
             return app('json')->fail(400762);
         }
-        return app('json')->success(410001, $this->services->login($account, $password, $spread));
+        return app('json')->success(410001, $this->services->login($account, $password, $spread, $agent_id));
     }
 
     /**
@@ -147,7 +147,7 @@ class LoginController
         $maxMinuteCountKey = 'sms.minute.' . $phone . date('YmdHi');
         $minuteCount = 0;
         if (CacheService::has($maxMinuteCountKey)) {
-            $minuteCount = CacheService::get($maxMinuteCountKey);
+            $minuteCount = CacheService::get($maxMinuteCountKey) ?? 0;
             $maxMinuteCount = Config::get('sms.maxMinuteCount', 5);
             if ($minuteCount > $maxMinuteCount) return app('json')->fail('同一手机号每分钟最多发送' . $maxMinuteCount . '条');
 
@@ -157,7 +157,7 @@ class LoginController
         $maxPhoneCountKey = 'sms.phone.' . $phone . '.' . date('Ymd');
         $phoneCount = 0;
         if (CacheService::has($maxPhoneCountKey)) {
-            $phoneCount = CacheService::get($maxPhoneCountKey);
+            $phoneCount = CacheService::get($maxPhoneCountKey) ?? 0;
             $maxPhoneCount = Config::get('sms.maxPhoneCount', 20);
             if ($phoneCount > $maxPhoneCount) return app('json')->fail('同一手机号每天最多发送' . $maxPhoneCount . '条');
 
@@ -167,7 +167,7 @@ class LoginController
         $maxIpCountKey = 'sms.ip.' . app()->request->ip() . '.' . date('Ymd');
         $ipCount = 0;
         if (CacheService::has($maxIpCountKey)) {
-            $ipCount = CacheService::get($maxPhoneCountKey);
+            $ipCount = CacheService::get($maxPhoneCountKey) ?? 0;
             $maxIpCount = Config::get('sms.maxIpCount', 50);
             if ($ipCount > $maxIpCount) return app('json')->fail('同一IP每天最多发送' . $maxIpCount . '条');
 
@@ -189,9 +189,9 @@ class LoginController
         $smsCode = $this->services->verify($services, $phone, $type, $time);
         if ($smsCode) {
             CacheService::set('code_' . $phone, $smsCode, $time * 60);
-            CacheService::set($maxMinuteCountKey, $minuteCount + 1, 61);
-            CacheService::set($maxPhoneCountKey, $phoneCount + 1, 86401);
-            CacheService::set($maxIpCountKey, $ipCount + 1, 86401);
+            CacheService::set($maxMinuteCountKey, (int)$minuteCount + 1, 61);
+            CacheService::set($maxPhoneCountKey, (int)$phoneCount + 1, 86401);
+            CacheService::set($maxIpCountKey, (int)$ipCount + 1, 86401);
             return app('json')->success(410007);
         } else {
             return app('json')->fail(410008);
@@ -275,7 +275,7 @@ class LoginController
      */
     public function mobile(Request $request)
     {
-        [$phone, $captcha, $spread] = $request->postMore([['phone', ''], ['captcha', ''], ['spread', 0]], true);
+        [$phone, $captcha, $spread, $agent_id] = $request->postMore([['phone', ''], ['captcha', ''], ['spread', 0], ['agent_id', 0]], true);
 
         //验证手机号
         try {
@@ -293,7 +293,7 @@ class LoginController
             return app('json')->fail(410010);
         }
         $user_type = $request->getFromType() ? $request->getFromType() : 'h5';
-        $token = $this->services->mobile($phone, $spread, $user_type);
+        $token = $this->services->mobile($phone, $spread, $user_type, $agent_id);
         if ($token) {
             CacheService::delete('code_' . $phone);
             return app('json')->success(410001, $token);

+ 5 - 0
crmeb/app/api/controller/v1/PayController.php

@@ -111,4 +111,9 @@ class PayController
 
         return app('json')->success($config);
     }
+
+    public function transferNotify()
+    {
+        return app()->make(Pay::class, ['v3_wechat_pay'])->handleTransferNotify()->getContent();
+    }
 }

+ 94 - 29
crmeb/app/api/controller/v1/PublicController.php

@@ -12,6 +12,7 @@ namespace app\api\controller\v1;
 
 
 use app\services\activity\combination\StorePinkServices;
+use app\services\activity\lottery\LuckLotteryRecordServices;
 use app\services\diy\DiyServices;
 use app\services\kefu\service\StoreServiceServices;
 use app\services\order\DeliveryServiceServices;
@@ -33,6 +34,7 @@ use app\services\system\lang\LangTypeServices;
 use app\services\system\store\SystemStoreServices;
 use app\services\system\store\SystemStoreStaffServices;
 use app\services\user\UserBillServices;
+use app\services\user\UserExtractServices;
 use app\services\user\UserInvoiceServices;
 use app\services\user\UserServices;
 use app\services\wechat\RoutineSchemeServices;
@@ -40,6 +42,7 @@ use app\services\wechat\WechatUserServices;
 use app\Request;
 use crmeb\services\CacheService;
 use app\services\other\UploadService;
+use crmeb\services\pay\Pay;
 use crmeb\services\workerman\ChannelService;
 
 /**
@@ -142,42 +145,47 @@ class PublicController
         if ($request->hasMacro('user')) $userInfo = $request->user();
         if ($request->hasMacro('uid')) $uid = $request->uid();
 
+        //用户等级开关
         $vipOpen = sys_config('member_func_status');
+        //分销功能开关
         $brokerageFuncStatus = sys_config('brokerage_func_status');
+        //余额功能开关
         $balanceFuncStatus = sys_config('balance_func_status');
-        $vipCard = sys_config('member_card_status', 0);
-        $svipOpen = (bool)sys_config('member_card_status');
-        $userService = $invoiceStatus = $deliveryUser = $isUserPromoter = $userVerifyStatus = $userOrder = true;
-
+        //付费会员开关
+        $svipOpen = sys_config('member_card_status');
+        $userService = $userOrder = $userVerifyStatus = $deliveryUser = $invoiceStatus = $isUserPromoter = false;
         if ($uid && $userInfo) {
             /** @var StoreServiceServices $storeService */
             $storeService = app()->make(StoreServiceServices::class);
+            //是否客服
             $userService = $storeService->checkoutIsService(['uid' => $uid, 'status' => 1]);
+            //是否订单管理
             $userOrder = $storeService->checkoutIsService(['uid' => $uid, 'status' => 1, 'customer' => 1]);
-            /** @var SystemStoreStaffServices $systemStoreStaff */
-            $systemStoreStaff = app()->make(SystemStoreStaffServices::class);
-            /** @var UserServices $user */
-            $user = app()->make(UserServices::class);
-            /** @var UserInvoiceServices $userInvoice */
-            $userInvoice = app()->make(UserInvoiceServices::class);
-            $invoiceStatus = $userInvoice->invoiceFuncStatus(false);
-            /** @var DeliveryServiceServices $deliveryService */
-            $deliveryService = app()->make(DeliveryServiceServices::class);
-            $deliveryUser = $deliveryService->checkoutIsService($uid);
-            $isUserPromoter = $user->checkUserPromoter($uid, $userInfo);
-            $userVerifyStatus = $systemStoreStaff->verifyStatus($uid);
+            //是否核销员
+            $userVerifyStatus = app()->make(SystemStoreStaffServices::class)->verifyStatus($uid);
+            //是否配送员
+            $deliveryUser = app()->make(DeliveryServiceServices::class)->checkoutIsService($uid);
+            //发票功能开关
+            $invoiceStatus = app()->make(UserInvoiceServices::class)->invoiceFuncStatus(false);
+            //是否分销员
+            $isUserPromoter = app()->make(UserServices::class)->checkUserPromoter($uid, $userInfo);
         }
         $auth = [];
-        $auth['/pages/users/user_vip/index'] = !$vipOpen;
-        $auth['/pages/users/user_spread_user/index'] = !$brokerageFuncStatus || !$isUserPromoter || $uid == 0;
-        $auth['/pages/users/user_money/index'] = !$balanceFuncStatus;
-        $auth['/pages/admin/order/index'] = !$userOrder || $uid == 0;
-        $auth['/pages/admin/order_cancellation/index'] = (!$userVerifyStatus && !$deliveryUser) || $uid == 0;
-        $auth['/pages/users/user_invoice_list/index'] = !$invoiceStatus;
-        $auth['/pages/annex/vip_paid/index'] = !$vipCard || !$svipOpen;
-        $auth['/kefu/mobile_list'] = !$userService || $uid == 0;
+        $auth['/pages/users/user_vip/index'] = $vipOpen;
+        $auth['/pages/users/user_spread_user/index'] = $brokerageFuncStatus && $isUserPromoter;
+        $auth['/pages/annex/settled/index'] = $brokerageFuncStatus && sys_config('store_brokerage_statu') == 1 && !$isUserPromoter;
+        $auth['/pages/users/user_money/index'] = $balanceFuncStatus;
+        $auth['/pages/admin/order/index'] = $userOrder;
+        $auth['/pages/admin/order_cancellation/index'] = $userVerifyStatus || $deliveryUser;
+        $auth['/pages/users/user_invoice_list/index'] = $invoiceStatus;
+        $auth['/pages/annex/vip_paid/index'] = $svipOpen;
+        $auth['/kefu/mobile_list'] = $userService;
         foreach ($menusInfo as $key => &$value) {
-            if (isset($auth[$value['url']]) && $auth[$value['url']]) {
+            if ($value['url'] == '/pages/users/user_spread_user/index' && $auth['/pages/annex/settled/index']) {
+                $value['name'] = '分销申请';
+                $value['url'] = '/pages/annex/settled/index';
+            }
+            if (isset($auth[$value['url']]) && !$auth[$value['url']]) {
                 unset($menusInfo[$key]);
                 continue;
             }
@@ -195,7 +203,7 @@ class PublicController
         $routine_contact_type = sys_config('routine_contact_type', 0);
         /** @var DiyServices $diyServices */
         $diyServices = app()->make(DiyServices::class);
-        $diy_data = $diyServices->get(['template_name' => 'member', 'type' => 1], ['value', 'order_status', 'my_banner_status']);
+        $diy_data = $diyServices->get(['template_name' => 'member', 'type' => 1], ['value', 'order_status', 'my_banner_status', 'my_menus_status', 'business_status']);
         $diy_data = $diy_data ? $diy_data->toArray() : [];
         return app('json')->success(['routine_my_menus' => array_merge($menusInfo), 'routine_my_banner' => $my_banner, 'routine_spread_banner' => $bannerInfo, 'routine_contact_type' => $routine_contact_type, 'diy_data' => $diy_data]);
     }
@@ -321,7 +329,10 @@ class PublicController
                 return str_replace(['https://', 'http://'], '', $item);
             }, $domainArr);
         }
-        if ($domainArr && (($imageUrl && !in_array($imageUrl, $domainArr)) || ($codeUrl && !in_array($codeUrl, $domainArr)))) {
+        $domainArr[] = 'mp.weixin.qq.com';
+        $imageUrlHost = $imageUrl ? (parse_url($imageUrl)['host'] ?? $imageUrl) : $imageUrl;
+        $codeUrlHost = $codeUrl ? (parse_url($codeUrl)['host'] ?? $codeUrl) : $codeUrl;
+        if ($domainArr && (($imageUrl && !in_array($imageUrlHost, $domainArr)) || ($codeUrl && !in_array($codeUrlHost, $domainArr)))) {
             return app('json')->success(['code' => false, 'image' => false]);
         }
         if ($imageUrl !== '' && !preg_match('/.*(\.png|\.jpg|\.jpeg|\.gif)$/', $imageUrl) && strpos(strtolower($imageUrl), "phar://") !== false) {
@@ -335,9 +346,10 @@ class PublicController
                 $codeTmp = $code = $codeUrl ? image_to_base64($codeUrl) : false;
                 if (!$codeTmp) {
                     $putCodeUrl = put_image($codeUrl);
+                    //TODO
                     $code = $putCodeUrl ? image_to_base64(app()->request->domain(true) . '/' . $putCodeUrl) : false;
                     if ($putCodeUrl) {
-                        unlink($_SERVER["DOCUMENT_ROOT"] . '/' . $putCodeUrl);
+                        unlink($_SERVER["DOCUMENT_ROOT"] . DS . $putCodeUrl);
                     }
                 }
                 return $code;
@@ -346,9 +358,10 @@ class PublicController
                 $imageTmp = $image = $imageUrl ? image_to_base64($imageUrl) : false;
                 if (!$imageTmp) {
                     $putImageUrl = put_image($imageUrl);
+                    //TODO
                     $image = $putImageUrl ? image_to_base64(app()->request->domain(true) . '/' . $putImageUrl) : false;
                     if ($putImageUrl) {
-                        unlink($_SERVER["DOCUMENT_ROOT"] . '/' . $putImageUrl);
+                        unlink($_SERVER["DOCUMENT_ROOT"] . DS . $putImageUrl);
                     }
                 }
                 return $image;
@@ -398,6 +411,11 @@ class PublicController
             $uids = array_rand($uids, count($uids) < 3 ? count($uids) : 3);
         }
         $data['avatars'] = $uids ? $user->getColumn(is_array($uids) ? [['uid', 'in', $uids]] : ['uid' => $uids], 'avatar') : [];
+        foreach ($data['avatars'] as &$avatar) {
+            if (strpos($avatar, '/statics/system_images/') !== false) {
+                $avatar = set_file_url($avatar);
+            }
+        }
         return app('json')->success($data);
     }
 
@@ -527,6 +545,11 @@ class PublicController
         return sys_config('statistic_script', '');
     }
 
+    public function customPcJs()
+    {
+        return sys_config('custom_pc_js', '');
+    }
+
     /**
      * 获取workerman请求域名
      * @return mixed
@@ -695,7 +718,9 @@ class PublicController
         $data['site_url'] = sys_config('site_url');//网站地址
         $data['wap_login_logo'] = sys_config('wap_login_logo');//移动端登录logo
         $data['record_No'] = sys_config('record_No');//备案号
+        $data['icp_url'] = sys_config('icp_url');//备案号链接
         $data['network_security'] = sys_config('network_security');//网安备案
+        $data['network_security_url'] = sys_config('network_security_url');//网安备案链接
         $data['store_self_mention'] = sys_config('store_self_mention');//是否开启到店自提
         $data['invoice_func_status'] = sys_config('invoice_func_status');//发票功能启用
         $data['special_invoice_status'] = sys_config('special_invoice_status');//专用发票启用
@@ -760,4 +785,44 @@ class PublicController
         $data['jump_url'] = sys_config('site_url') . '/pages/goods/order_pay_status/index?order_id=' . $out_trade_no . '&msg=支付成功&type=3&totalPrice=' . $data['pay_price'];
         return app('json')->header(['X-Frame-Options' => 'payapp.weixin.qq.com'])->success($data);
     }
+
+    public function getTransferInfo(Request $request, $order_id, $type)
+    {
+        $extractServices = app()->make(UserExtractServices::class);
+        $lotteryRecordServices = app()->make(LuckLotteryRecordServices::class);
+        $uid = (int)$request->uid();
+        if ($type == 1) {
+            $info = $extractServices->getExtractByOrderId($uid, $order_id);
+            $info['true_extract_price'] = bcsub($info['extract_price'], $info['extract_fee'], 2);
+        } else {
+            $info = $lotteryRecordServices->getRecordByOrderId($uid, $order_id);
+            $info['true_extract_price'] = $info['num'];
+        }
+        if ($info['state'] == 'WAIT_USER_CONFIRM') {
+            $pay = new Pay('v3_wechat_pay');
+            $res = $pay->queryTransferBills($order_id);
+            if (isset($res['fail_reason']) && $res['fail_reason'] != '') {
+                if ($type == 1) {
+                    $extractServices->refuse((int)$info['id'], '提现失败,原因:超时为领取');
+                    $extractServices->update($info['id'], ['state' => 'FAIL']);
+                } else {
+                    $lotteryRecordServices->update($info['id'], ['state' => 'FAIL']);
+                }
+                $info['state'] = 'FAIL';
+            }
+        }
+        switch ($info['channel_type']) {
+            case 'wechat':
+                $info['wechat_appid'] = sys_config('wechat_appid');
+                break;
+            case 'routine':
+                $info['wechat_appid'] = sys_config('routine_appid');
+                break;
+            case 'app':
+                $info['wechat_appid'] = sys_config('app_appid');
+                break;
+        }
+        $info['mchid'] = sys_config('pay_weixin_mchid');
+        return app('json')->success($info);
+    }
 }

+ 8 - 2
crmeb/app/api/controller/v1/activity/StoreSeckillController.php

@@ -122,7 +122,10 @@ class StoreSeckillController
      */
     public function detail(Request $request, $id)
     {
-        $data = $this->services->seckillDetail($request, $id);
+        [$time_id] = $request->getMore([
+            ['time_id', 0]
+        ], true);
+        $data = $this->services->seckillDetail($request, $id, $time_id);
         return app('json')->success($data);
     }
 
@@ -134,9 +137,12 @@ class StoreSeckillController
      */
     public function code(Request $request, $id)
     {
+        [$time_id] = $request->getMore([
+            ['time_id', 0]
+        ], true);
         /** @var QrcodeServices $qrcodeService */
         $qrcodeService = app()->make(QrcodeServices::class);
-        $url = $qrcodeService->getRoutineQrcodePath($id, $request->uid(), 2);
+        $url = $qrcodeService->getRoutineQrcodePath($id, $request->uid(), 2, ['time_id' => $time_id]);
         if ($url) {
             return app('json')->success(['code' => $url]);
         } else {

+ 61 - 12
crmeb/app/api/controller/v1/order/StoreOrderController.php

@@ -102,17 +102,18 @@ class StoreOrderController
         if (!$services->get(1, ['id'])) {
             return app('json')->fail(410207);
         }
-        [$cartId, $new, $addressId, $shipping_type] = $request->postMore([
+        [$cartId, $new, $addressId, $shipping_type, $is_gift] = $request->postMore([
             'cartId',
             'new',
             ['addressId', 0],
             ['shipping_type', 1],
+            ['is_gift', 0],
         ], true);
         if (!is_string($cartId) || !$cartId) {
             return app('json')->fail(410201);
         }
         $user = $request->user()->toArray();
-        return app('json')->success($this->services->getOrderConfirmData($user, $cartId, !!$new, $addressId, (int)$shipping_type));
+        return app('json')->success($this->services->getOrderConfirmData($user, $cartId, !!$new, $addressId, (int)$shipping_type, (int)$is_gift));
     }
 
     /**
@@ -128,9 +129,18 @@ class StoreOrderController
         $uid = $request->uid();
         if ($this->services->be(['order_id|unique' => $key, 'uid' => $uid, 'is_del' => 0]))
             return app('json')->status('extend_order', 410173, ['orderId' => $key, 'key' => $key]);
-        list($addressId, $couponId, $payType, $useIntegral, $mark, $combinationId, $pinkId, $seckill_id, $bargainId, $shipping_type) = $request->postMore([
-            'addressId', 'couponId', ['payType', ''], ['useIntegral', 0], 'mark', ['combinationId', 0], ['pinkId', 0], ['seckill_id', 0], ['bargainId', ''],
+        list($addressId, $couponId, $payType, $useIntegral, $mark, $combinationId, $pinkId, $seckill_id, $bargainId, $shipping_type, $is_gift) = $request->postMore([
+            'addressId',
+            'couponId',
+            ['payType', ''],
+            ['useIntegral', 0],
+            'mark',
+            ['combinationId', 0],
+            ['pinkId', 0],
+            ['seckill_id', 0],
+            ['bargainId', 0],
             ['shipping_type', 1],
+            ['is_gift', 0],
         ], true);
         $payType = strtolower($payType);
         $cartGroup = $this->services->getCacheOrderInfo($uid, $key);
@@ -140,7 +150,7 @@ class StoreOrderController
             'pinkId' => $pinkId,
             'seckill_id' => $seckill_id,
             'bargainId' => $bargainId,
-        ])->computedOrder($request->uid(), $request->user()->toArray(), $cartGroup, $addressId, $payType, !!$useIntegral, (int)$couponId, false, (int)$shipping_type);
+        ])->computedOrder($request->uid(), $request->user()->toArray(), $cartGroup, $addressId, $payType, !!$useIntegral, (int)$couponId, false, (int)$shipping_type, $is_gift);
         if ($priceGroup)
             return app('json')->status('NONE', 100010, $priceGroup);
         else
@@ -163,7 +173,7 @@ class StoreOrderController
         $userInfo = $request->user()->toArray();
         if ($checkOrder = $this->services->getOne(['order_id|unique' => $key, 'uid' => $userInfo['uid'], 'is_del' => 0]))
             return app('json')->status('extend_order', 410209, ['orderId' => $checkOrder['order_id'], 'key' => $key]);
-        [$addressId, $couponId, $payType, $useIntegral, $mark, $combinationId, $pinkId, $seckillId, $bargainId, $shipping_type, $real_name, $phone, $storeId, $news, $invoice_id, $advanceId, $customForm] = $request->postMore([
+        [$addressId, $couponId, $payType, $useIntegral, $mark, $combinationId, $pinkId, $seckillId, $bargainId, $shipping_type, $real_name, $phone, $storeId, $news, $invoice_id, $advanceId, $customForm, $is_gift, $gift_mark] = $request->postMore([
             [['addressId', 'd'], 0],
             [['couponId', 'd'], 0],
             ['payType', ''],
@@ -181,10 +191,12 @@ class StoreOrderController
             [['invoice_id', 'd'], 0],
             [['advanceId', 'd'], 0],
             ['custom_form', []],
+            ['is_gift', 0],
+            ['gift_mark', ''],
         ], true);
         $payType = strtolower($payType);
-        $order = CacheService::lock('orderCreate' . $key, function () use ($createServices, $userInfo, $key, $addressId, $payType, $useIntegral, $couponId, $mark, $combinationId, $pinkId, $seckillId, $bargainId, $shipping_type, $real_name, $phone, $storeId, $news, $advanceId, $customForm, $invoice_id) {
-            return $createServices->createOrder($userInfo['uid'], $key, $userInfo, $addressId, $payType, !!$useIntegral, $couponId, $mark, $combinationId, $pinkId, $seckillId, $bargainId, $shipping_type, $real_name, $phone, $storeId, !!$news, $advanceId, $customForm, $invoice_id);
+        $order = CacheService::lock('orderCreate' . $key, function () use ($createServices, $userInfo, $key, $addressId, $payType, $useIntegral, $couponId, $mark, $combinationId, $pinkId, $seckillId, $bargainId, $shipping_type, $real_name, $phone, $storeId, $news, $advanceId, $customForm, $invoice_id, $is_gift, $gift_mark) {
+            return $createServices->createOrder($userInfo['uid'], $key, $userInfo, $addressId, $payType, !!$useIntegral, $couponId, $mark, $combinationId, $pinkId, $seckillId, $bargainId, $shipping_type, $real_name, $phone, $storeId, !!$news, $advanceId, $customForm, $invoice_id, $is_gift, $gift_mark);
         });
         $orderId = $order['order_id'];
         return app('json')->status('success', 410203, compact('orderId', 'key'));
@@ -544,9 +556,10 @@ class StoreOrderController
         $user_info = $request->user();
         $group['nickname'] = $user_info['nickname'];
         $group['avatar'] = $user_info['avatar'];
-        if (!$cartInfo) return app('json')->fail(410294);
-        $orderUid = $this->services->value(['id' => $cartInfo['oid']], 'uid');
-        if ($uid != $orderUid) return app('json')->fail(410294);
+        if (!$cartInfo) return app('json')->fail('商品不存在');
+        $orderInfo = $this->services->get($cartInfo['oid']);
+        if (!$orderInfo) return app('json')->fail('订单不存在');
+        if ($uid != $orderInfo['uid'] && $uid != $orderInfo['gift_uid']) return app('json')->fail('不是您自己的订单,无法评价');
         if ($replyServices->be(['oid' => $cartInfo['oid'], 'unique' => $unique]))
             return app('json')->fail(410219);
         $group['comment'] = htmlspecialchars(trim($group['comment']));
@@ -566,6 +579,8 @@ class StoreOrderController
             'reply_type' => 'product',
             'suk' => $cartInfo['cart_info']['productInfo']['attrInfo']['suk']
         ]);
+        //评价是否需要审核
+        $group['status'] = sys_config('product_reply_examine') == 1 ? 0 : 1;
 
         $res = $replyServices->save($group);
         if (!$res) {
@@ -590,7 +605,7 @@ class StoreOrderController
         //缓存抽奖次数
         /** @var LuckLotteryServices $luckLotteryServices */
         $luckLotteryServices = app()->make(LuckLotteryServices::class);
-        $luckLotteryServices->setCacheLotteryNum((int)$orderUid, 'comment');
+        $luckLotteryServices->setCacheLotteryNum((int)$uid == $orderInfo['uid'] ? $orderInfo['uid'] : $orderInfo['gift_uid'], 'comment');
 
         /** @var SystemAdminServices $systemAdmin */
         $systemAdmin = app()->make(SystemAdminServices::class);
@@ -927,4 +942,38 @@ class StoreOrderController
         $decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
         return json_decode($decrypted, true);
     }
+
+    public function giftDetail($oid)
+    {
+        if (!$oid) {
+            return app('json')->fail('缺少参数');
+        }
+        return app('json')->success($this->services->giftDetail($oid));
+    }
+
+    public function receiveGift(Request $request, $oid)
+    {
+        [$gift_key, $shipping_type, $name, $phone, $address_id, $store_id] = $request->postMore([
+            ['gift_key', ''],
+            ['shipping_type', 1],
+            ['name', ''],
+            ['phone', ''],
+            ['address_id', 0],
+            ['store_id', 0],
+        ], true);
+        if (!$oid) {
+            return app('json')->fail('缺少参数');
+        }
+        if ($shipping_type == 1 && $address_id == 0) {
+            return app('json')->fail('请选择收货地址');
+        }
+        $uid = $request->uid();
+        $res = $this->services->receiveGift($uid, $oid, $gift_key, $shipping_type, $name, $phone, $address_id, $store_id);
+        if ($res) {
+            return app('json')->success('领取成功', ['status' => 1]);
+        } else {
+            return app('json')->success('该礼品已经被别人领取', ['status' => 0]);
+        }
+
+    }
 }

+ 34 - 0
crmeb/app/api/controller/v1/store/StoreProductController.php

@@ -60,6 +60,8 @@ class StoreProductController
             [['selectId', 'd'], 0],
             [['productId', 'd'], 0],
             [['coupon_category_id', 'd'], 0],
+            ['cate_id', ''],
+            ['store_label_id', ''],
         ]);
         if ($where['selectId'] && (!$where['sid'] || !$where['cid'])) {
             if ($services->value(['id' => $where['selectId']], 'pid')) {
@@ -78,6 +80,22 @@ class StoreProductController
         if (!$where['ids']) {
             unset($where['ids']);
         }
+        if ($where['cate_id'] !== '') {
+            $where['cate_id'] = explode(',', $where['cate_id']);
+            foreach ($where['cate_id'] as $keys => &$items) {
+                $where['cate_id'][$keys] = (int)$items;
+            }
+        } else {
+            $where['cate_id'] = [];
+        }
+        if ($where['store_label_id'] !== '') {
+            $where['store_label_id'] = explode(',', $where['store_label_id']);
+            foreach ($where['store_label_id'] as $keys => &$items) {
+                $where['store_label_id'][$keys] = (int)$items;
+            }
+        } else {
+            $where['store_label_id'] = [];
+        }
         $type = 'big';
         $field = ['image', 'recommend_image'];
         $list = $this->services->getGoodsList($where, (int)$request->uid());
@@ -209,4 +227,20 @@ class StoreProductController
         return app('json')->success($this->services->getAdvanceList($where));
     }
 
+    /**
+     * 获取商品实时价格
+     * @param Request $request
+     * @param $id
+     * @param $unique
+     * @return \think\Response
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2025/2/5
+     */
+    public function realPrice(Request $request, $id, $unique)
+    {
+        $uid = $request->uid() ?? 0;
+        if (!$id || !$unique) return app('json')->fail('缺少参数');
+        return app('json')->success($this->services->realPrice($uid, $id, $unique));
+    }
 }

+ 42 - 0
crmeb/app/api/controller/v1/user/SpreadApplyController.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace app\api\controller\v1\user;
+
+use app\Request;
+use app\services\agent\SpreadApplyServices;
+use crmeb\services\CacheService;
+
+class SpreadApplyController
+{
+    public function __construct(SpreadApplyServices $services)
+    {
+        $this->services = $services;
+    }
+
+    public function applyInfo(Request $request)
+    {
+        $uid = $request->uid();
+        $data = $this->services->applyInfo($uid);
+        return app('json')->success($data);
+    }
+
+    public function applyPromoter(Request $request, $id)
+    {
+        $data = $request->postMore([
+            ['uid', 0],
+            ['nickname', ''],
+            ['real_name', ''],
+            ['phone', ''],
+            ['content', ''],
+            ['code', 0]
+        ]);
+        $data['uid'] = $request->uid();
+        $userInfo = $request->user();
+        $verifyCode = CacheService::get('code_' . $data['phone']);
+        if (!$verifyCode) return app('json')->fail('请先获取验证码');
+        if ($verifyCode != $data['code']) return app('json')->fail('验证码错误');
+        unset($data['code']);
+        $id = $this->services->applyPromoter($data, $id, $userInfo);
+        return app('json')->success('申请成功', ['id' => $id]);
+    }
+}

+ 4 - 0
crmeb/app/api/controller/v1/user/UserAddressController.php

@@ -12,6 +12,7 @@ namespace app\api\controller\v1\user;
 
 use app\Request;
 use app\services\user\UserAddressServices;
+use app\services\wechat\WechatUserServices;
 
 /**
  * 用户地址类
@@ -70,6 +71,8 @@ class UserAddressController
         if (!$id || !is_numeric($id)) return app('json')->fail(100100);
         $uid = (int)$request->uid();
         $res = $this->services->setDefault($uid, (int)$id);
+        $province = $this->services->value(['id' => $id], 'province');
+        app()->make(WechatUserServices::class)->update(['uid' => $uid], ['province' => $province]);
         if (!$res)
             return app('json')->fail(410150);
         else
@@ -117,6 +120,7 @@ class UserAddressController
         $uid = (int)$request->uid();
         $res = $this->services->editAddress($uid, $addressInfo);
         if ($res) {
+            app()->make(WechatUserServices::class)->update(['uid' => $uid], ['province' => $addressInfo['address']['province']]);
             return app('json')->success($res['type'] == 'edit' ? 100001 : $res['data']);
         } else {
             return app('json')->fail(100007);

+ 4 - 3
crmeb/app/api/controller/v1/user/UserController.php

@@ -146,12 +146,13 @@ class UserController
      */
     public function spread(Request $request)
     {
-        [$spreadUid, $code] = $request->postMore([
+        [$spreadUid, $code, $agent_id] = $request->postMore([
             ['puid', 0],
-            ['code', 0]
+            ['code', 0],
+            ['agent_id', 0]
         ], true);
         $uid = (int)$request->uid();
-        $res = $this->services->spread($uid, (int)$spreadUid, $code);
+        $res = $this->services->spread($uid, (int)$spreadUid, $code, $agent_id);
         return app('json')->success($res);
     }
 

+ 8 - 3
crmeb/app/api/controller/v1/user/UserExtractController.php

@@ -54,12 +54,14 @@ class UserExtractController
             ['alipay_code', ''],
             ['extract_type', ''],
             ['money', 0],
+            ['user_name', ''],
             ['name', ''],
             ['bankname', ''],
             ['cardnum', ''],
             ['weixin', ''],
             ['qrcode_url', ''],
         ]);
+        $extractInfo['channel_type'] = $request->getFromType();
         $extractType = Config::get('pay.extractType', []);
         if (!in_array($extractInfo['extract_type'], $extractType))
             return app('json')->fail(410114);
@@ -67,9 +69,12 @@ class UserExtractController
         if (!$extractInfo['cardnum'] == '')
             if (!preg_match('/^([1-9]{1})(\d{15}|\d{16}|\d{18})$/', $extractInfo['cardnum']))
                 return app('json')->fail(410116);
-        if ($extractInfo['extract_type'] == 'alipay') {
-            if (trim($extractInfo['name']) == '') return app('json')->fail(410117);
-        } else if ($extractInfo['extract_type'] == 'bank') {
+        if ($extractInfo['extract_type'] == 'weixin') {
+            if (trim($extractInfo['user_name']) == '') return app('json')->fail('请填写真实姓名');
+        } elseif ($extractInfo['extract_type'] == 'alipay') {
+            if (trim($extractInfo['alipay_code']) == '') return app('json')->fail(410117);
+            if (trim($extractInfo['user_name']) == '') return app('json')->fail('请填写真实姓名');
+        } elseif ($extractInfo['extract_type'] == 'bank') {
             if (!$extractInfo['cardnum']) return app('json')->fail(410118);
             if (!$extractInfo['bankname']) return app('json')->fail(410119);
         }

+ 7 - 0
crmeb/app/api/controller/v2/PublicController.php

@@ -17,6 +17,7 @@ use app\services\diy\DiyServices;
 use app\services\product\product\StoreCategoryServices;
 use app\services\product\product\StoreProductServices;
 use app\services\user\UserServices;
+use app\services\user\UserSignServices;
 use app\services\wechat\WechatUserServices;
 
 class PublicController
@@ -135,4 +136,10 @@ class PublicController
         $is_diy = $services->value(['status' => 1, 'is_del' => 0], 'is_diy');
         return app('json')->success(compact('status', 'is_diy'));
     }
+
+    public function getDiySign(Request $request)
+    {
+        $uid = (int)$request->uid();
+        return app('json')->success(app()->make(UserSignServices::class)->signConfig($uid, 1));
+    }
 }

+ 11 - 5
crmeb/app/api/controller/v2/activity/LuckLotteryController.php

@@ -30,10 +30,14 @@ class LuckLotteryController
      * @throws \think\db\exception\DbException
      * @throws \think\db\exception\ModelNotFoundException
      */
-    public function LotteryInfo(Request $request, $factor)
+    public function LotteryInfo(Request $request, $factor, $lottery_id = 0)
     {
         if (!$factor) return app('json')->fail(100100);
-        $lottery = $this->services->getFactorLottery((int)$factor, '*', ['prize'], true);
+        if ($lottery_id) {
+            $lottery = $this->services->getLottery($lottery_id, '*', ['prize'], true);
+        } else {
+            $lottery = $this->services->getFactorLottery((int)$factor, '*', ['prize'], true);
+        }
         if (!$lottery) {
             return app('json')->fail(410318);
         }
@@ -74,6 +78,7 @@ class LuckLotteryController
         ], true);
 
         $uid = (int)$request->uid();
+        $channel_type = $request->getFromType();
         $key = 'lucklotter_limit_' . $uid;
         if (CacheService::get($key)) {
             return app('json')->fail('您求的频率太过频繁,请稍后请求!');
@@ -96,7 +101,7 @@ class LuckLotteryController
             return app('json')->fail(100100);
         }
 
-        return app('json')->success($this->services->luckLottery($uid, $id));
+        return app('json')->success($this->services->luckLottery($uid, $id, $channel_type));
     }
 
     /**
@@ -110,18 +115,19 @@ class LuckLotteryController
      */
     public function lotteryReceive(Request $request, LuckLotteryRecordServices $lotteryRecordServices)
     {
-        [$id, $name, $phone, $address, $mark] = $request->postMore([
+        [$id, $name, $phone, $address, $detail, $mark] = $request->postMore([
             ['id', 0],
             ['name', ''],
             ['phone', ''],
             ['address', ''],
+            ['detail', ''],
             ['mark', '']
         ], true);
         if (!$id) {
             return app('json')->fail(100100);
         }
         $uid = (int)$request->uid();
-        return app('json')->success($lotteryRecordServices->receivePrize($uid, $id, compact('name', 'phone', 'address', 'mark')) ? 410319 : 410320);
+        return app('json')->success($lotteryRecordServices->receivePrize($uid, $id, compact('name', 'phone', 'address', 'detail', 'mark')) ? 410319 : 410320);
     }
 
     /**

+ 2 - 2
crmeb/app/api/controller/v2/store/StoreCartController.php

@@ -74,7 +74,7 @@ class StoreCartController
         $cartService = app()->make(StoreCartServices::class);
         if (!$product_id || !is_numeric($product_id)) return app('json')->fail(100100);
         $res = $cartService->setCartNum($request->uid(), $product_id, $num, $unique, $type);
-        if ($res) return app('json')->success(100001);
-        return app('json')->fail(100007);
+        if ($res) return app('json')->success('加入购物车成功!');
+        return app('json')->fail('加入购物车失败!');
     }
 }

+ 1 - 1
crmeb/app/api/controller/v2/wechat/AuthController.php

@@ -121,7 +121,7 @@ class AuthController
             return app('json')->fail(410010);
         }
         CacheService::delete('code_' . $phone);
-        $data = $this->services->phoneLogin($key, $phone, $spread_code, $spread_spid, $code);
+        $data = $this->services->phoneLogin($key, $phone, $spread_code, 0, $spread_spid, $code);
         return app('json')->success($data);
     }
 

+ 2 - 2
crmeb/app/api/controller/v2/wechat/WechatController.php

@@ -43,9 +43,9 @@ class WechatController
      * @email: 442384644@qq.com
      * @date: 2023/8/12
      */
-    public function authLogin($spread = '')
+    public function authLogin($spread = '', $agent_id = '')
     {
-        $data = $this->services->authLogin($spread);
+        $data = $this->services->authLogin($spread, $agent_id);
         return app('json')->success($data);
     }
 

+ 17 - 5
crmeb/app/api/route/v1.php

@@ -18,8 +18,10 @@ Route::group(function () {
     Route::any('wechat/serve', 'v1.wechat.WechatController/serve')->option(['real_name' => '公众号服务']);//公众号服务
     Route::any('wechat/miniServe', 'v1.wechat.WechatController/miniServe')->option(['real_name' => '小程序服务']);//公众号服务
     Route::any('pay/notify/:type', 'v1.PayController/notify')->option(['real_name' => '支付回调']);//支付回调
+    Route::any('transfer/notify/:type', 'v1.PayController/transferNotify')->option(['real_name' => '商户转账回调']);//商户转账回调
     Route::any('order_call_back', 'v1.order.StoreOrderController/callBack')->option(['real_name' => '商家寄件回调']);//商家寄件回调
-    Route::get('get_script', 'v1.PublicController/getScript')->option(['real_name' => '获取统计代码']);//获取统计代码
+    Route::get('get_script', 'v1.PublicController/getScript')->option(['real_name' => '移动端自定义JS']);//移动端自定义JS
+    Route::get('custom_pc_js', 'v1.PublicController/customPcJs')->option(['real_name' => 'PC端自定义JS']);//PC端自定义JS
     Route::get('version', 'v1.PublicController/getVersion')->option(['real_name' => '获取代码版本号']);
     Route::get('service_pay_result', 'v1.PublicController/servicePayResult')->option(['real_name' => '服务商支付商家小票接口']);
 })->middleware(\app\http\middleware\AllowOriginMiddleware::class)->option(['mark' => 'serve', 'mark_name' => '服务接口']);
@@ -109,6 +111,9 @@ Route::group(function () {
         Route::post('switch_h5', 'v1.LoginController/switch_h5')->name('switch_h5')->option(['real_name' => '切换账号']);// 切换账号
         //公共类
         Route::post('upload/image', 'v1.PublicController/upload_image')->name('uploadImage')->option(['real_name' => '图片上传']);//图片上传
+        // 用户微信转账详情接口
+        Route::get('transfer/info', 'v1.PublicController/getTransferInfo')->name('getTransferInfo')->option(['real_name' => '用户微信转账详情接口']);// 用户微信转账详情接口
+
     })->option(['mark' => 'common', 'mark_name' => '公共接口']);
 
     Route::group(function () {
@@ -201,10 +206,10 @@ Route::group(function () {
         Route::post('order/product', 'v1.order.StoreOrderController/product')->name('orderProduct')->option(['real_name' => '订单商品信息']); //订单商品信息
         Route::post('order/comment', 'v1.order.StoreOrderController/comment')->name('orderComment')->option(['real_name' => '订单评价']); //订单评价
         Route::get('order/cashier/:orderId/[:type]', 'v1.order.StoreOrderController/cashier')->name('orderCashier')->option(['real_name' => '订单收银台']); //订单收银台
-        /** 好友代付 */
         Route::get('order/friend_detail', 'v1.order.StoreOrderController/friendDetail')->name('friendDetail')->option(['real_name' => '代付详情']);//代付详情
-        //首页获取未支付订单
-        Route::get('order/nopay', 'v1.order.StoreOrderController/get_noPay')->name('getNoPay')->option(['real_name' => '获取未支付订单']);//获取未支付订单
+        Route::post('order/receive_gift/:oid', 'v1.order.StoreOrderController/receiveGift')->name('receiveGift')->option(['real_name' => '领取礼物']);//领取礼物
+        Route::get('order/gift_detail/:oid', 'v1.order.StoreOrderController/giftDetail')->name('giftDetail')->option(['real_name' => '礼品详情']); //礼品详情
+
     })->option(['mark' => 'order', 'mark_name' => '订单']);
 
     Route::group(function () {
@@ -338,6 +343,12 @@ Route::group(function () {
         Route::delete('user/visit', 'v1.user.UserController/visitDelete')->name('visitDelete')->option(['real_name' => '商品浏览记录删除']);//商品浏览记录删除
     })->option(['mark' => 'user', 'mark_name' => '用户']);
 
+    Route::group(function () {
+        /** 分销员申请 */
+        Route::get('user/spread/apply/info', 'v1.user.SpreadApplyController/applyInfo')->name('申请信息');//申请信息
+        Route::post('user/spread/apply/:id', 'v1.user.SpreadApplyController/applyPromoter')->name('申请分销员');//申请分销员
+    })->option(['mark' => 'spread', 'mark_name' => '分销员申请']);
+
 })->middleware(\app\http\middleware\AllowOriginMiddleware::class)->middleware(\app\api\middleware\StationOpenMiddleware::class)->middleware(\app\api\middleware\AuthTokenMiddleware::class, true);
 //未授权接口
 Route::group(function () {
@@ -367,6 +378,7 @@ Route::group(function () {
         Route::get('reply/config/:id', 'v1.store.StoreProductController/reply_config')->name('replyConfig')->option(['real_name' => '商品评价数量和好评度']);//商品评价数量和好评度
         Route::get('advance/list', 'v1.store.StoreProductController/advanceList')->name('advanceList')->option(['real_name' => '预售商品列表']);//预售商品列表
         Route::get('product/code/:id', 'v1.store.StoreProductController/code')->name('productCode')->option(['real_name' => '商品分享二维码']);//商品分享二维码 推广员
+        Route::get('product/real_price/:id/:unique', 'v1.store.StoreProductController/realPrice')->name('realPrice')->option(['real_name' => '商品到手价']);//商品到手价
     })->option(['mark' => 'product', 'mark_name' => '商品']);
 
     Route::group(function () {
@@ -386,7 +398,7 @@ Route::group(function () {
             //活动---秒杀
             Route::get('seckill/index', 'v1.activity.StoreSeckillController/index')->name('seckillIndex')->option(['real_name' => '秒杀商品时间区间']);//秒杀商品时间区间
             Route::get('seckill/list/:time', 'v1.activity.StoreSeckillController/lst')->name('seckillList')->option(['real_name' => '秒杀商品列表']);//秒杀商品列表
-            Route::get('seckill/detail/:id/[:time]', 'v1.activity.StoreSeckillController/detail')->name('seckillDetail')->option(['real_name' => '秒杀商品详情']);//秒杀商品详情
+            Route::get('seckill/detail/:id', 'v1.activity.StoreSeckillController/detail')->name('seckillDetail')->option(['real_name' => '秒杀商品详情']);//秒杀商品详情
         })->option(['parent' => 'activity_nologin', 'cate_name' => '秒杀(未授权)']);
 
         Route::group(function () {

+ 2 - 7
crmeb/app/api/route/v2.php

@@ -37,11 +37,8 @@ Route::group('v2', function () {
         })->option(['mark' => 'wechat_auto', 'mark_name' => '微信授权']);
 
         Route::group(function () {
-            //获取门店自提开启状态
             Route::get('diy/get_store_status', 'v2.PublicController/getStoreStatus')->option(['real_name' => '获取门店自提开启状态']);
-            //一键换色
             Route::get('diy/color_change/:name', 'v2.PublicController/colorChange')->option(['real_name' => '一键换色']);
-            //DIY接口
             Route::get('diy/get_diy/[:name]', 'v2.PublicController/getDiy')->option(['real_name' => '获取DIY数据']);
             Route::get('diy/get_version/[:name]', 'v2.PublicController/getVersion')->option(['real_name' => '获取DIY版本号']);
         })->option(['mark' => 'diy', 'mark_name' => 'DIY']);
@@ -84,7 +81,7 @@ Route::group('v2', function () {
         Route::get('user/clean_search', 'v2.user.UserSearchController/cleanUserSearch')->name('cleanUserSearch')->option(['real_name' => '清除搜索记录']);
 
         //抽奖活动详情
-        Route::get('lottery/info/:factor', 'v2.activity.LuckLotteryController/lotteryInfo')->name('lotteryInfo')->option(['real_name' => '抽奖活动详情']);
+        Route::get('lottery/info/:factor/[:lottery_id]', 'v2.activity.LuckLotteryController/lotteryInfo')->name('lotteryInfo')->option(['real_name' => '抽奖活动详情']);
         //参与抽奖
         Route::post('lottery', 'v2.activity.LuckLotteryController/luckLottery')->name('luckLottery')->middleware(BlockerMiddleware::class)->option(['real_name' => '参与抽奖']);
         //领取奖品
@@ -101,14 +98,12 @@ Route::group('v2', function () {
 
     //授权不通过,不会抛出异常继续执行
     Route::group(function () {
-        //用户搜索记录
         Route::get('user/search_list', 'v2.user.UserSearchController/getUserSeachList')->name('userSearchList')->option(['real_name' => '用户搜索记录']);
         Route::get('get_today_coupon', 'v2.store.StoreCouponsController/getTodayCoupon')->option(['real_name' => '新优惠券弹窗接口']);//新优惠券弹窗接口
         Route::get('subscribe', 'v2.PublicController/subscribe')->name('WechatSubscribe')->option(['real_name' => '微信公众号用户是否关注']);// 微信公众号用户是否关注
-        //公共类
         Route::get('index', 'v2.PublicController/index')->name('index')->option(['real_name' => '首页']);//首页
-        //优惠券
         Route::get('coupons', 'v2.store.StoreCouponsController/lst')->name('couponsList')->option(['real_name' => '可领取优惠券列表']); //可领取优惠券列表
+        Route::get('diy/sign', 'v2.PublicController/getDiySign')->name('getDiySign')->option(['real_name' => '获取Diy签到']);
     })->middleware(\app\api\middleware\AuthTokenMiddleware::class, false)
         ->option(['mark' => 'common', 'mark_name' => '公共接口']);
 

+ 29 - 13
crmeb/app/common.php

@@ -626,14 +626,24 @@ if (!function_exists('filter_str')) {
      */
     function filter_str($str)
     {
-        $rules = preg_split('/\r\n|\r|\n/', base64_decode(sys_config('param_filter_data')));
-        if (filter_var($str, FILTER_VALIDATE_URL)) {
-            $url = parse_url($str);
-            if (!isset($url['scheme'])) return $str;
-            $host = $url['scheme'] . '://' . $url['host'];
-            $str = $host . preg_replace($rules, '', str_replace($host, '', $str));
-        } else {
-            $str = preg_replace($rules, '', $str);
+        $param_filter_type = sys_config('param_filter_type');
+        if ($param_filter_type != 0) {
+            $rules = preg_split('/\r\n|\r|\n/', base64_decode(sys_config('param_filter_data')));
+            if ($param_filter_type == 1) {
+                foreach ($rules as $item) {
+                    if (preg_match($item, $str)) {
+                        throw new \Exception('接口请求失败:非法操作!');
+                    }
+                }
+            }
+            if (filter_var($str, FILTER_VALIDATE_URL)) {
+                $url = parse_url($str);
+                if (!isset($url['scheme'])) return $str;
+                $host = $url['scheme'] . '://' . $url['host'];
+                $str = $host . preg_replace($rules, '', str_replace($host, '', $str));
+            } else {
+                $str = preg_replace($rules, '', $str);
+            }
         }
         return $str;
     }
@@ -655,7 +665,7 @@ if (!function_exists('is_brokerage_statu')) {
         if ($storeBrokerageStatus == 1) {
             return false;
         } else if ($storeBrokerageStatus == 2) {
-            return false;
+            return true;
         } else {
             $storeBrokeragePrice = sys_config('store_brokerage_price', 0);
             return $price >= $storeBrokeragePrice;
@@ -895,6 +905,7 @@ if (!function_exists('get_image_thumb')) {
         if (!$filePath || !is_string($filePath) || strpos($filePath, '?') !== false) return $filePath;
         try {
             $upload = UploadService::getOssInit($filePath, $is_remote_down);
+            //TODO
             $fileArr = explode('/', $filePath);
             $data = $upload->thumb($filePath, end($fileArr), $type);
             $image = $type == 'all' ? $data : $data[$type] ?? $filePath;
@@ -906,6 +917,7 @@ if (!function_exists('get_image_thumb')) {
             $image = sys_config('site_url') . $image;
         }
         //请求是https 图片是http 需要改变图片地址
+        //TODO 是否要读取后台配置url
         if (strpos(request()->domain(), 'https:') !== false && strpos($image, 'https:') === false) {
             $image = str_replace('http:', 'https:', $image);
         }
@@ -1146,16 +1158,20 @@ if (!function_exists('dump_sql')) {
     }
 }
 
-if (!function_exists('stringToIntArray')) {
+if (!function_exists('toIntArray')) {
 
     /**
      * 处理ids等并过滤参数
-     * @param string $string
+     * @param $data
      * @param string $separator
      * @return array
      */
-    function stringToIntArray(string $string, string $separator = ',')
+    function toIntArray($data, string $separator = ',')
     {
-        return !empty($string) ? array_unique(array_diff(array_map('intval', explode($separator, $string)), [0])) : [];
+        if (!is_string($data)) {
+            return array_unique(array_diff(array_map('intval', $data), [0]));
+        } else {
+            return !empty($data) ? array_unique(array_diff(array_map('intval', explode($separator, $data)), [0])) : [];
+        }
     }
 }

+ 52 - 0
crmeb/app/dao/activity/StoreActivityDao.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace app\dao\activity;
+
+use app\dao\BaseDao;
+use app\model\activity\StoreActivity;
+
+class StoreActivityDao extends BaseDao
+{
+    protected function setModel(): string
+    {
+        return StoreActivity::class;
+    }
+
+    public function conditionSearch($where)
+    {
+        return $this->getModel()
+            ->when(isset($where['title']) && $where['title'] !== '', function ($query) use ($where) {
+                $query->whereLike('title', '%' . $where['title'] . '%');
+            })->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) {
+                $query->where('is_del', $where['is_del']);
+            })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) {
+                $query->where('status', $where['status']);
+            })->when(isset($where['type']) && $where['type'] !== '', function ($query) use ($where) {
+                $query->where('type', $where['type']);
+            })->when(isset($where['time_ids']) && count($where['time_ids']) > 0, function ($query) use ($where) {
+                $query->where(function ($query) use ($where) {
+                    foreach ($where['time_ids'] as $value) {
+                        $query->whereOr('FIND_IN_SET(:value, time_ids)', ['value' => $value]);
+                    }
+                });
+            })->when(isset($where['time']) && $where['time'] !== '', function ($query) use ($where) {
+                $time = explode('-', $where['time']);
+                $query->where('start_day', '<=', strtotime($time[1]))->where('end_day', '>=', strtotime($time[0]));
+            });
+    }
+
+    public function activityList(array $where = [], string $field = '*', int $page = 0, int $limit = 0, $with = [])
+    {
+        return $this->conditionSearch($where)->field($field)
+            ->when($page && $limit, function ($query) use ($page, $limit) {
+                $query->page($page, $limit);
+            })->when(count($with), function ($query) use ($with) {
+                $query->with($with);
+            })->order('add_time DESC')->select()->toArray();
+    }
+
+    public function activityCount(array $where = [])
+    {
+        return $this->conditionSearch($where)->count();
+    }
+}

+ 8 - 0
crmeb/app/dao/activity/bargain/StoreBargainDao.php

@@ -60,6 +60,8 @@ class StoreBargainDao extends BaseDao
                 }
             })->when($page != 0 && $limit != 0, function ($query) use ($page, $limit) {
                 $query->page($page, $limit);
+            })->when(isset($where['product_id']) && $where['product_id'] != 0, function ($query) use ($where) {
+                $query->where('product_id', $where['product_id']);
             })->order('sort desc,id desc')->select()->toArray();
     }
 
@@ -243,4 +245,10 @@ class StoreBargainDao extends BaseDao
     {
         return $this->getModel()->where('id', $id)->inc($field, 1)->update();
     }
+
+    public function getProductExist($productIds)
+    {
+        return $this->getModel()->where('product_id', 'in', $productIds)->where('is_del', 0)
+            ->group('product_id')->column('COUNT(*) as count', 'product_id');
+    }
 }

+ 8 - 0
crmeb/app/dao/activity/combination/StoreCombinationDao.php

@@ -104,6 +104,8 @@ class StoreCombinationDao extends BaseDao
                 }
             })->when($page != 0 && $limit != 0, function ($query) use ($page, $limit) {
                 $query->page($page, $limit);
+            })->when(isset($where['product_id']) && $where['product_id'] != 0, function ($query) use ($where) {
+                $query->where('product_id', $where['product_id']);
             })->order('sort desc,id desc')->select()->toArray();
     }
 
@@ -240,4 +242,10 @@ class StoreCombinationDao extends BaseDao
         $where = ['is_del' => 0, 'is_host' => 1, 'is_show' => 1, 'pinkIngTime' => true];
         return $this->search($where)->order('id desc')->select()->toArray();
     }
+
+    public function getProductExist($productIds)
+    {
+        return $this->getModel()->where('product_id', 'in', $productIds)->where('is_del', 0)
+            ->group('product_id')->column('COUNT(*) as count', 'product_id');
+    }
 }

+ 37 - 0
crmeb/app/dao/activity/coupon/StoreCouponIssueDao.php

@@ -52,6 +52,14 @@ class StoreCouponIssueDao extends BaseDao
             }
         })->when(isset($where['receive_type']) && $where['receive_type'], function ($query) use ($where) {
             $query->where('receive_type', $where['receive_type']);
+        })->when(isset($where['receive_types']) && $where['receive_types'], function ($query) use ($where) {
+            $query->where(function ($query) use ($where) {
+                if ($where['receive_types'] == 1) {
+                    $query->where('receive_type', 1)->whereOr('receive_type', 4);
+                } else {
+                    $query->where('receive_type', 2)->whereOr('receive_type', 3);
+                }
+            });
         });
     }
 
@@ -359,4 +367,33 @@ class StoreCouponIssueDao extends BaseDao
     {
         return (bool)$this->getModel()->whereFindInSet('product_id', $product_id)->count();
     }
+
+    public function canReceiveCoupons($uid, $isMember)
+    {
+        return $this->getModel()->where('status', 1)
+            ->where('is_del', 0)
+            ->where('remain_count > 0 OR is_permanent = 1')
+            ->where(function ($query) use ($isMember) {
+                if ($isMember) {
+                    $query->where('receive_type', 1)->whereOr('receive_type', 4);
+                } else {
+                    $query->where('receive_type', 1);
+                }
+            })->where(function ($query) {
+                $query->where(function ($query) {
+                    $query->where('start_time', '<', time())->where('end_time', '>', time());
+                })->whereOr(function ($query) {
+                    $query->where('start_time', 0)->where('end_time', 0);
+                });
+            })->where(function ($query) {
+                $query->where(function ($query) {
+                    $query->where('start_use_time', '<', time())->where('end_use_time', '>', time());
+                })->whereOr(function ($query) {
+                    $query->where('start_use_time', 0)->where('end_use_time', 0);
+                });
+            })
+            ->with(['used' => function ($query) use ($uid) {
+                $query->where('uid', $uid);
+            }])->order('coupon_price desc')->select()->toArray();
+    }
 }

+ 6 - 1
crmeb/app/dao/activity/coupon/StoreCouponIssueUserDao.php

@@ -8,7 +8,7 @@
 // +----------------------------------------------------------------------
 // | Author: CRMEB Team <admin@crmeb.com>
 // +----------------------------------------------------------------------
-declare (strict_types = 1);
+declare (strict_types=1);
 
 namespace app\dao\activity\coupon;
 
@@ -56,4 +56,9 @@ class StoreCouponIssueUserDao extends BaseDao
     {
         return $this->getModel()->where($where)->delete();
     }
+
+    public function getIssueUserCount($uid, $coupon_id)
+    {
+        return $this->getModel()->where('uid', $uid)->where('issue_coupon_id', $coupon_id)->count();
+    }
 }

+ 35 - 8
crmeb/app/dao/activity/lottery/LuckLotteryDao.php

@@ -74,7 +74,7 @@ class LuckLotteryDao extends BaseDao
      * 抽奖活动列表
      * @param array $where
      * @param string $field
-     * @param array $with
+     * @param string $order
      * @param int $page
      * @param int $limit
      * @return array
@@ -82,13 +82,40 @@ class LuckLotteryDao extends BaseDao
      * @throws \think\db\exception\DbException
      * @throws \think\db\exception\ModelNotFoundException
      */
-    public function getList(array $where, string $field = '*', array $with = [], int $page = 0, int $limit = 0)
+    public function getList(array $where, string $field = '*', string $order = 'id desc', int $page = 0, int $limit = 0)
     {
-        return $this->search($where)->field($field)->when($with, function ($query) use ($with) {
-            $query->with($with);
-        })->when($page && $limit, function ($query) use ($page, $limit) {
+        $model = $this->getModel()->when($where['is_del'] !== '', function ($query) use ($where) {
+            $query->where('is_del', $where['is_del']);
+        })->when($where['factor'] !== '', function ($query) use ($where) {
+            $query->where('factor', $where['factor']);
+        })->when($where['start'] !== '', function ($query) use ($where) {
+            if ($where['start'] == 0) {
+                $query->where('start_time', '>', time());
+            } elseif ($where['start'] == 1) {
+                $query->where('start_time', '<', time())->where('end_time', '>', time());
+            } else {
+                $query->where('end_time', '<', time());
+            }
+        })->when($where['status'] !== '', function ($query) use ($where) {
+            $query->where('status', $where['status']);
+        })->when(count($where['time']) == 2, function ($query) use ($where) {
+            $query->where('start_time', '<=', $where['time'][0])->where('end_time', '>=', $where['time'][1]);
+        })->when($where['keyword'] !== '', function ($query) use ($where) {
+            $query->where('name|content', 'like', '%' . $where['keyword'] . '%');
+        });
+        $count = $model->count();
+        $list = $model->with(['records' => function ($query) {
+            $query->field([
+                'lottery_id',
+                'COUNT(DISTINCT uid) AS total_user',      // 总参与人数
+                'COUNT(DISTINCT CASE WHEN type != 1 THEN uid END) AS wins_user', // 中奖人数
+                'COUNT(*) AS total_num',                    // 总参与次数
+                'SUM(type != 1) AS wins_num',                  // 中奖次数
+            ])->group('lottery_id');
+        }])->field($field)->when($page && $limit, function ($query) use ($page, $limit) {
             $query->page($page, $limit);
-        })->order('add_time desc')->select()->toArray();
+        })->order($order)->select()->toArray();
+        return compact('count', 'list');
     }
 
     /**
@@ -125,10 +152,10 @@ class LuckLotteryDao extends BaseDao
      */
     public function getFactorLottery(int $factor = 1, string $field = '*', array $with = ['prize'], bool $is_doing = false)
     {
-        $where = ['factor' => $factor, 'is_del' => 0];
+        $where = ['factor' => $factor, 'is_del' => 0, 'is_use' => 1];
         if ($is_doing) $where['start'] = 1;
         return $this->search($where)->field($field)->when($with, function ($query) use ($with) {
             $query->with($with);
-        })->find();
+        })->order('id desc')->find();
     }
 }

+ 6 - 0
crmeb/app/dao/activity/lottery/LuckLotteryRecordDao.php

@@ -64,4 +64,10 @@ class LuckLotteryRecordDao extends BaseDao
             $query->group($group);
         })->count();
     }
+
+    public function getRecordByOrderId($uid, $order_id)
+    {
+        $info = $this->getModel()->where('uid', $uid)->where('wechat_order_id', $order_id)->find();
+        return $info ? $info->toArray() : [];
+    }
 }

+ 19 - 5
crmeb/app/dao/activity/seckill/StoreSeckillDao.php

@@ -58,8 +58,6 @@ class StoreSeckillDao extends BaseDao
             $query->where('product_id', 'IN', function ($query) {
                 $query->name('store_product')->where('is_show', 1)->where('is_del', 0)->field('id');
             });
-        })->when(isset($where['time_id']) && $where['time_id'], function ($query) use ($where) {
-            $query->where('time_id', $where['time_id']);
         });
     }
 
@@ -105,9 +103,15 @@ class StoreSeckillDao extends BaseDao
                 } else {
                     $query->whereIn('id', $where['ids'])->orderField('id', $where['ids'], 'asc');
                 }
+            })->when(isset($where['product_id']) && $where['product_id'] != 0, function ($query) use ($where) {
+                $query->where('product_id', $where['product_id']);
             })->when($page != 0 && $limit != 0, function ($query) use ($page, $limit) {
                 $query->page($page, $limit);
-            })->with(['product'])->order('sort desc,id desc')->select()->toArray();
+            })->when(isset($where['activity_name']) && $where['activity_name'] != '', function ($query) use ($where) {
+                $query->whereIn('activity_id', function ($query) use ($where) {
+                    $query->name('store_activity')->whereLike('title', '%' . $where['activity_name'] . '%')->field('id')->select();
+                });
+            })->with(['product', 'attrs'])->order('sort desc,id desc')->select()->toArray();
     }
 
     /**获取秒杀列表
@@ -148,6 +152,10 @@ class StoreSeckillDao extends BaseDao
                 } else {
                     $query->whereIn('id', $where['ids'])->orderField('id', $where['ids'], 'asc');
                 }
+            })->when(isset($where['activity_name']) && $where['activity_name'] != '', function ($query) use ($where) {
+                $query->whereIn('activity_id', function ($query) use ($where) {
+                    $query->name('store_activity')->whereLike('title', $where['activity_name'])->field('id')->select();
+                });
             })->with(['product'])->select()->toArray();
     }
 
@@ -179,10 +187,10 @@ class StoreSeckillDao extends BaseDao
      */
     public function getListByTime(int $time, int $page, int $limit)
     {
-        return $this->search(['is_del' => 0, 'status' => 1])
+        return $this->search(['is_del' => 0, 'status' => 1])->with(['product'])
             ->where('start_time', '<=', time())
             ->where('stop_time', '>=', time() - 86400)
-            ->where('time_id', $time)
+            ->whereFindInSet('time_id', $time)
             ->where('product_id', 'IN', function ($query) {
                 $query->name('store_product')->where('is_del', 0)->field('id');
             })->when($page != 0, function ($query) use ($page, $limit) {
@@ -222,4 +230,10 @@ class StoreSeckillDao extends BaseDao
             ->where('stop_time', '>', $time - 86400)
             ->field($field)->with(['product'])->find();
     }
+
+    public function getProductExist($productIds)
+    {
+        return $this->getModel()->where('product_id', 'in', $productIds)->where('is_show', 1)->where('is_del', 0)
+            ->group('product_id')->column('COUNT(*) as count', 'product_id');
+    }
 }

+ 36 - 0
crmeb/app/dao/agent/SpreadApplyDao.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace app\dao\agent;
+
+use app\dao\BaseDao;
+use app\model\agent\SpreadApply;
+
+class SpreadApplyDao extends BaseDao
+{
+    protected function setModel(): string
+    {
+        return SpreadApply::class;
+    }
+
+    public function getConditionModel($where)
+    {
+        return $this->getModel()->where('is_del', 0)
+            ->when($where['status'] !== '' && $where['status'] !== 'all', function ($query) use ($where) {
+                $query->where('status', $where['status']);
+            })->when($where['keyword'] !== '', function ($query) use ($where) {
+                $query->whereLike('uid|nickname|real_name|phone', $where['keyword']);
+            });
+    }
+
+    public function applyList($where, $page = 0, $limit = 0)
+    {
+        return $this->getConditionModel($where)->order('id desc')->when($page != 0, function ($query) use ($page, $limit) {
+            $query->page($page, $limit);
+        })->select()->toArray();
+    }
+
+    public function applyCount($where)
+    {
+        return $this->getConditionModel($where)->count();
+    }
+}

+ 6 - 3
crmeb/app/dao/diy/PageLinkDao.php

@@ -46,8 +46,11 @@ class PageLinkDao extends BaseDao
     public function getList(array $where, string $field = '*', int $page = 0, int $limit = 0)
     {
         $where['no_model'] = sys_config('model_checkbox', ['seckill', 'bargain', 'combination']);
-        return $this->search($where)->field($field)->when($page && $limit, function ($query) use ($page, $limit) {
-            $query->page();
-        })->order('sort desc,id asc')->select()->toArray();
+        return $this->search($where)->field($field)
+            ->when(isset($where['cate_ids']), function ($query) use ($where) {
+
+            })->when($page && $limit, function ($query) use ($page, $limit) {
+                $query->page($page, $limit);
+            })->order('sort desc,id asc')->select()->toArray();
     }
 }

+ 39 - 3
crmeb/app/dao/order/StoreOrderDao.php

@@ -59,7 +59,7 @@ class StoreOrderDao extends BaseDao
         })->when($status !== '', function ($query) use ($where, $status) {
             switch ((int)$status) {
                 case 0://未支付
-                    $query->where('paid', 0)->where('status', 0)->where('refund_status', 0)->where('is_del', 0);
+                    $query->where('paid', 0)->where('status', 0)->where('refund_status', 0)->where('is_del', 0)->where('is_cancel', 0);
                     break;
                 case 1://已支付 未发货
                     $query->where('paid', 1)->where('status', 0)->whereIn('refund_status', [0, 3])->when(isset($where['shipping_type']), function ($query) {
@@ -474,7 +474,7 @@ class StoreOrderDao extends BaseDao
     public function getUserOrderDetail(string $key, int $uid, $with = [])
     {
         $where = ['order_id|unique' => $key, 'is_del' => 0];
-        if ($uid > 0) $where = $where + ['uid' => $uid];
+        if ($uid > 0) $where = $where + ['uid|gift_uid' => $uid];
         return $this->getOne($where, '*', $with);
     }
 
@@ -569,7 +569,7 @@ class StoreOrderDao extends BaseDao
      */
     public function getOrderUnPaidList(array $field = ['*'])
     {
-        return $this->getModel()->where(['paid' => 0, 'is_del' => 0, 'status' => 0, 'refund_status' => 0])
+        return $this->getModel()->where(['paid' => 0, 'is_cancel' => 0, 'is_del' => 0, 'status' => 0, 'refund_status' => 0])
             ->where('pay_type', '<>', 'offline')->field($field)->select();
     }
 
@@ -1080,4 +1080,40 @@ class StoreOrderDao extends BaseDao
     {
         return $this->getModel()->where('pid', $pid)->where('status', 1)->where('id', '<>', $order_id)->count();
     }
+
+    /**
+     * 分销订单统计
+     * @param $field
+     * @param $time
+     * @param $page
+     * @param $limit
+     * @param $sort
+     * @param $order
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2025/4/8
+     */
+    public function divisionStatistics($field, $time, $page, $limit, $sort, $order)
+    {
+        $model = $this->getModel()
+            ->where('paid', 1)
+            ->where('pid', '>=', 0)
+            ->where('refund_status', 0)
+            ->where($field, '>', 0)->group($field)
+            ->when(!empty($time), function ($query) use ($time) {
+                $query->whereBetween('add_time', [strtotime($time[0]), strtotime($time[1] . ' 23:59:59')]);
+            });
+        $count = $model->count();
+        $orderStr = $sort == '' ? 'order_sum desc' : $sort . ' ' . $order;
+        $list = $model->field([
+            $field,
+            'COUNT(*) AS order_sum',
+            'SUM(pay_price) AS order_sum_price'
+        ])->order($orderStr)->page($page, $limit)->select()->toArray();
+        return compact('count', 'list');
+    }
 }

+ 5 - 0
crmeb/app/dao/order/StoreOrderRefundDao.php

@@ -191,4 +191,9 @@ class StoreOrderRefundDao extends BaseDao
             }
         })->field("FROM_UNIXTIME($field,'$timeType') as days,$str as num")->group('days')->select()->toArray();
     }
+
+    public function orderIsRefund($store_order_id)
+    {
+        return boolval($this->getModel()->where('store_order_id', $store_order_id)->whereIn('refund_type', [1, 2, 4, 5])->count());
+    }
 }

+ 23 - 5
crmeb/app/dao/product/product/StoreProductDao.php

@@ -46,11 +46,23 @@ class StoreProductDao extends BaseDao
         })->when(isset($where['cid']) && $where['cid'], function ($query) use ($where) {
             $query->whereIn('id', function ($query) use ($where) {
                 $query->name('store_product_cate')->whereIn('cate_id', function ($query) use ($where) {
-                    $query->name('store_category')->where('pid', is_array($where['cid']) ? 'in' : '=', $where['cid'])->field('id')->select();
+                    $query->name('store_category')->where('pid', is_array($where['cid']) ? 'in' : '=', $where['cid'])
+                        ->whereOr('id', is_array($where['cid']) ? 'in' : '=', $where['cid'])->field('id')->select();
                 })->field('product_id')->select();
             });
-        })->when(isset($where['ids']), function ($query) use ($where) {
-            $query->whereIn('id', $where['ids'])->orderField('id', $where['ids'], 'asc');
+        })->when(isset($where['coupon_category_id']) && $where['coupon_category_id'] != '', function ($query) use ($where) {
+            $where['coupon_category_id'] = toIntArray($where['coupon_category_id']);
+            $query->whereIn('id', function ($query) use ($where) {
+                $query->name('store_product_cate')->whereIn('cate_id', function ($query) use ($where) {
+                    $query->name('store_category')->whereIn('pid', $where['coupon_category_id'])->field('id')->select();
+                })->whereOr('cate_id', 'in', $where['coupon_category_id'])->field('product_id')->select();
+            });
+        })->when(isset($where['ids']) && $where['ids'], function ($query) use ($where) {
+            if ((isset($where['priceOrder']) && $where['priceOrder'] != '') || (isset($where['salesOrder']) && $where['salesOrder'] != '')) {
+                $query->whereIn('id', $where['ids']);
+            } else {
+                $query->whereIn('id', $where['ids'])->orderField('id', $where['ids'], 'asc');
+            }
         })->when(isset($where['is_live']) && $where['is_live'] == 1, function ($query) use ($where) {
             $query->whereNotIn('id', function ($query) {
                 $query->name('live_goods')->where('is_del', 0)->where('audit_status', '<>', 3)->field('product_id')->select();
@@ -110,7 +122,7 @@ class StoreProductDao extends BaseDao
      * @throws \think\db\exception\DbException
      * @throws \think\db\exception\ModelNotFoundException
      */
-    public function getSearchList(array $where, int $page = 0, int $limit = 0, array $field = ['*'], array $with = ['couponId', 'description'])
+    public function getSearchList(array $where, int $page = 0, int $limit = 0, array $field = ['*'], array $with = ['attrs', 'couponId', 'description'])
     {
         if (isset($where['star'])) $with[] = 'star';
         return $this->search($where, false)->with($with)->when($page != 0 && $limit != 0, function ($query) use ($page, $limit) {
@@ -127,7 +139,7 @@ class StoreProductDao extends BaseDao
                 })->field('product_id')->select();
             });
         })->when(isset($where['coupon_category_id']) && $where['coupon_category_id'] != '', function ($query) use ($where) {
-            $where['coupon_category_id'] = stringToIntArray($where['coupon_category_id']);
+            $where['coupon_category_id'] = toIntArray($where['coupon_category_id']);
             $query->whereIn('id', function ($query) use ($where) {
                 $query->name('store_product_cate')->whereIn('cate_id', function ($query) use ($where) {
                     $query->name('store_category')->whereIn('pid', $where['coupon_category_id'])->field('id')->select();
@@ -169,6 +181,12 @@ class StoreProductDao extends BaseDao
             }
         })->when(!$page && $limit, function ($query) use ($limit) {
             $query->limit($limit);
+        })->when(isset($where['store_label_id']), function ($query) use ($where) {
+            $query->where(function ($query) use ($where) {
+                foreach ($where['store_label_id'] as $value) {
+                    $query->whereOr('FIND_IN_SET(:value, label_list)', ['value' => $value]);
+                }
+            });
         })->order('sort desc')->field($field)->select()->toArray();
     }
 

+ 42 - 0
crmeb/app/dao/product/product/StoreProductLabelCateDao.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace app\dao\product\product;
+
+use app\dao\BaseDao;
+use app\model\product\product\StoreProductLabelCate;
+
+class StoreProductLabelCateDao extends BaseDao
+{
+    protected function setModel(): string
+    {
+        return StoreProductLabelCate::class;
+    }
+
+    public function conditionSearch($where)
+    {
+        return $this->getModel()
+            ->when(isset($where['name']) && $where['name'] !== '', function ($query) use ($where) {
+                $query->whereLike('name', '%' . $where['name'] . '%');
+            })->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) {
+                $query->where('is_del', $where['is_del']);
+            });
+    }
+
+    public function getLabelCateList(array $where = [], string $field = '*', int $page = 0, int $limit = 0)
+    {
+        return $this->conditionSearch($where)->field($field)
+            ->when($page && $limit, function ($query) use ($page, $limit) {
+                $query->page($page, $limit);
+            })->order('sort DESC')->select()->toArray();
+    }
+
+    public function getLabelCateCount(array $where = [])
+    {
+        return $this->conditionSearch($where)->count();
+    }
+
+    public function labelCateArr()
+    {
+        return $this->getModel()->where('is_del', 0)->column('name', 'id');
+    }
+}

+ 58 - 0
crmeb/app/dao/product/product/StoreProductLabelDao.php

@@ -0,0 +1,58 @@
+<?php
+
+namespace app\dao\product\product;
+
+use app\dao\BaseDao;
+use app\model\product\product\StoreProductLabel;
+
+class StoreProductLabelDao extends BaseDao
+{
+    protected function setModel(): string
+    {
+        return StoreProductLabel::class;
+    }
+
+    public function conditionSearch($where)
+    {
+        return $this->getModel()
+            ->when(isset($where['name']) && $where['name'] !== '', function ($query) use ($where) {
+                $query->whereLike('name', '%' . $where['name'] . '%');
+            })->when(isset($where['cate_id']) && $where['cate_id'] !== '', function ($query) use ($where) {
+                $query->where('cate_id', $where['cate_id']);
+            })->when(isset($where['is_show']) && $where['is_show'] !== '', function ($query) use ($where) {
+                $query->where('is_show', $where['is_show']);
+            })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) {
+                $query->where('status', $where['status']);
+            })->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) {
+                $query->where('is_del', $where['is_del']);
+            });
+    }
+
+    public function getLabelList(array $where = [], string $field = '*', int $page = 0, int $limit = 0)
+    {
+        return $this->conditionSearch($where)->field($field)
+            ->when($page && $limit, function ($query) use ($page, $limit) {
+                $query->page($page, $limit);
+            })->order('sort DESC')->select()->toArray();
+    }
+
+    public function getLabelCount(array $where = [])
+    {
+        return $this->conditionSearch($where)->count();
+    }
+
+    public function labelUseList()
+    {
+        $list = $this->getModel()->where('is_show', 1)->where('status', 1)->where('is_del', 0)->select()->toArray();
+        $arr = [];
+        foreach ($list as $item) {
+            $arr[$item['cate_id']][] = $item;
+        }
+        return $arr;
+    }
+
+    public function labelListByIds($ids)
+    {
+        return $this->getModel()->whereIn('id', $ids)->where('status', 1)->where('is_show', 1)->select()->toArray();
+    }
+}

+ 16 - 0
crmeb/app/dao/product/product/StoreProductLogDao.php

@@ -90,4 +90,20 @@ class StoreProductLogDao extends BaseDao
                 $query->group($group);
             })->order('add_time desc')->select()->toArray();
     }
+
+    /**
+     * 获取用户访问商品数量
+     * @param $uid
+     * @return int
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2025/2/17
+     */
+    public function getCountByUser($uid)
+    {
+        return $this->getModel()->where('uid', $uid)
+            ->where('type', 'visit')
+            ->group('product_id')
+            ->count();
+    }
 }

+ 79 - 0
crmeb/app/dao/product/product/StoreProductParamDao.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace app\dao\product\product;
+
+use app\dao\BaseDao;
+use app\model\product\product\StoreProductParam;
+
+/**
+ * 商品参数
+ * @author wuhaotian
+ * @email 442384644@qq.com
+ * @date 2024/12/17
+ */
+class StoreProductParamDao extends BaseDao
+{
+    /**
+     * 设置模型
+     * @return string
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    protected function setModel(): string
+    {
+        return StoreProductParam::class;
+    }
+
+    /**
+     * 条件搜索
+     * @param $where
+     * @return \crmeb\basic\BaseModel
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    public function conditionSearch($where)
+    {
+        return $this->getModel()
+            ->when(isset($where['name']) && $where['name'] !== '', function ($query) use ($where) {
+                $query->whereLike('name', '%' . $where['name'] . '%');
+            })->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) {
+                $query->where('is_del', $where['is_del']);
+            })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) {
+                $query->where('status', $where['status']);
+            });
+    }
+
+    /**
+     * 获取参数列表
+     * @param array $where
+     * @param string $field
+     * @param int $page
+     * @param int $limit
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    public function getParamList(array $where = [], string $field = '*', int $page = 0, int $limit = 0)
+    {
+        return $this->conditionSearch($where)->field($field)->order('sort DESC')->page($page, $limit)->select()->toArray();
+    }
+
+    /**
+     * 获取参数列表数量
+     * @param array $where
+     * @return int
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2024/12/17
+     */
+    public function getParamCount(array $where = [])
+    {
+        return $this->conditionSearch($where)->count();
+    }
+}

+ 44 - 0
crmeb/app/dao/product/product/StoreProductProtectionDao.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace app\dao\product\product;
+
+use app\dao\BaseDao;
+use app\model\product\product\StoreProductProtection;
+
+class StoreProductProtectionDao extends BaseDao
+{
+    protected function setModel(): string
+    {
+        return StoreProductProtection::class;
+    }
+
+    public function conditionSearch($where)
+    {
+        return $this->getModel()
+            ->when(isset($where['title']) && $where['title'] !== '', function ($query) use ($where) {
+                $query->whereLike('title', '%' . $where['title'] . '%');
+            })->when(isset($where['is_del']) && $where['is_del'] !== '', function ($query) use ($where) {
+                $query->where('is_del', $where['is_del']);
+            })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) {
+                $query->where('status', $where['status']);
+            });
+    }
+
+    public function protectionList(array $where = [], string $field = '*', int $page = 0, int $limit = 0)
+    {
+        return $this->conditionSearch($where)->field($field)
+            ->when($page && $limit, function ($query) use ($page, $limit) {
+                $query->page($page, $limit);
+            })->order('sort DESC')->select()->toArray();
+    }
+
+    public function protectionCount(array $where = [])
+    {
+        return $this->conditionSearch($where)->count();
+    }
+
+    public function protectionListByIds($ids)
+    {
+        return $this->getModel()->whereIn('id', $ids)->select()->toArray();
+    }
+}

+ 27 - 0
crmeb/app/dao/system/SystemPemDao.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace app\dao\system;
+
+use app\dao\BaseDao;
+use app\model\system\SystemPem;
+
+class SystemPemDao extends BaseDao
+{
+    protected function setModel(): string
+    {
+        return SystemPem::class;
+    }
+
+    public function savePem($data)
+    {
+        $info = $this->getModel()->where('name', $data['name'])->find();
+        if ($info) {
+            $info = $info->toArray();
+            $this->getModel()->where('id', $info['id'])->update($data);
+        } else {
+            $data['add_time'] = time();
+            $this->getModel()->save($data);
+        }
+        return true;
+    }
+}

+ 40 - 0
crmeb/app/dao/system/SystemTicketDao.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace app\dao\system;
+
+use app\dao\BaseDao;
+use app\model\system\SystemTicket;
+
+class SystemTicketDao extends BaseDao
+{
+    protected function setModel(): string
+    {
+        return SystemTicket::class;
+    }
+
+    public function getConditionModel($where)
+    {
+        return $this->getModel()->where('is_del', 0)
+            ->when(isset($where['keyword']) && $where['keyword'] !== '', function ($query) use ($where) {
+                $query->where('print_name', 'like', '%' . $where['keyword'] . '%');
+            })->when(isset($where['type']) && $where['type'] != 0, function ($query) use ($where) {
+                $query->where('type', $where['type']);
+            })->when(isset($where['status']) && $where['status'] !== '', function ($query) use ($where) {
+                $query->where('status', $where['status']);
+            })->when(isset($where['print_type']) && $where['print_type'] != 0, function ($query) use ($where) {
+                $query->where('print_type', $where['print_type']);
+            });
+    }
+
+    public function ticketList($where, $page = 0, $limit = 0)
+    {
+        return $this->getConditionModel($where)->order('id desc')->when($page != 0, function ($query) use ($page, $limit) {
+            $query->page($page, $limit);
+        })->select()->toArray();
+    }
+
+    public function ticketCount($where)
+    {
+        return $this->getConditionModel($where)->count();
+    }
+}

+ 1 - 1
crmeb/app/dao/system/admin/SystemAdminDao.php

@@ -102,6 +102,6 @@ class SystemAdminDao extends BaseDao
      */
     public function checkRoleUse(int $id): bool
     {
-        return (bool)$this->getModel()->where('is_del', 0)->whereFindInSet('roles', $id)->count();
+        return (bool)$this->getModel()->where('level', '<>', 0)->where('is_del', 0)->whereFindInSet('roles', $id)->count();
     }
 }

+ 6 - 0
crmeb/app/dao/user/UserExtractDao.php

@@ -126,4 +126,10 @@ class UserExtractDao extends BaseDao
     {
         return $this->search($where)->sum($field);
     }
+
+    public function getExtractByOrderId($uid, $order_id)
+    {
+        $info = $this->getModel()->where('uid', $uid)->where('wechat_order_id', $order_id)->find();
+        return $info ? $info->toArray() : [];
+    }
 }

+ 31 - 0
crmeb/app/dao/user/UserWechatUserDao.php

@@ -152,6 +152,37 @@ class UserWechatUserDao extends BaseDao
                 $model = $model->where($userAlias . 'pay_count', '>', $where['pay_count']);
             }
         }
+        if (isset($where['pay_count_num']) && count($where['pay_count_num']) == 2) {
+            if ($where['pay_count_num'][0] != '' && $where['pay_count_num'][1] != '') {
+                $model = $model->whereBetween($userAlias . 'pay_count', $where['pay_count_num']);
+            } elseif ($where['pay_count_num'][0] != '' && $where['pay_count_num'][1] == '') {
+                $model = $model->where($userAlias . 'pay_count', '>', $where['pay_count_num'][0]);
+            } elseif ($where['pay_count_num'][0] == '' && $where['pay_count_num'][1] != '') {
+                $model = $model->where($userAlias . 'pay_count', '<', $where['pay_count_num'][1]);
+            }
+        }
+
+        //储值余额
+        if (isset($where['balance']) && count($where['balance']) == 2) {
+            if ($where['balance'][0] != '' && $where['balance'][1] != '') {
+                $model = $model->whereBetween($userAlias . 'now_money', $where['balance']);
+            } elseif ($where['balance'][0] != '' && $where['balance'][1] == '') {
+                $model = $model->where($userAlias . 'now_money', '>', $where['balance'][0]);
+            } elseif ($where['balance'][0] == '' && $where['balance'][1] != '') {
+                $model = $model->where($userAlias . 'now_money', '<', $where['balance'][1]);
+            }
+        }
+
+        //积分剩余
+        if (isset($where['integral']) && count($where['integral']) == 2) {
+            if ($where['integral'][0] != '' && $where['integral'][1] != '') {
+                $model = $model->whereBetween($userAlias . 'integral', $where['integral']);
+            } elseif ($where['integral'][0] != '' && $where['integral'][1] == '') {
+                $model = $model->where($userAlias . 'integral', '>', $where['integral'][0]);
+            } elseif ($where['integral'][0] == '' && $where['integral'][1] != ''){
+                $model = $model->where($userAlias . 'integral', '<', $where['integral'][1]);
+            }
+        }
 
         //用户等级
         if (isset($where['level']) && $where['level']) {

+ 1 - 3
crmeb/app/event.php

@@ -18,9 +18,7 @@
 */ 
 
 return [
-    'bind' => [
-
-    ],
+    'bind' => [],
 
     'listen' => [
         'AppInit' => [],

+ 1 - 1
crmeb/app/jobs/MiniOrderJob.php

@@ -19,10 +19,10 @@ class MiniOrderJob extends BaseJobs
     {
         try {
             MiniOrderService::shippingByTradeNo($out_trade_no, $logistics_type, $shipping_list, $payer_openid, $path, $delivery_mode, $is_all_delivered);
+            return true;
         } catch (HttpException $e) {
             // 订单异常处理
             throw new HttpException($e);
         }
-        return true;
     }
 }

+ 3 - 0
crmeb/app/jobs/PinkJob.php

@@ -17,6 +17,9 @@ use app\services\order\StoreOrderRefundServices;
 use app\services\order\StoreOrderServices;
 use crmeb\basic\BaseJobs;
 use crmeb\traits\QueueTrait;
+use think\db\exception\DataNotFoundException;
+use think\db\exception\DbException;
+use think\db\exception\ModelNotFoundException;
 
 class PinkJob extends BaseJobs
 {

+ 1 - 1
crmeb/app/jobs/UnpaidOrderCancelJob.php

@@ -62,7 +62,7 @@ class UnpaidOrderCancelJob extends BaseJobs
                 return true;
             });
             if ($res) {
-                $orderInfo->is_del = 1;
+                $orderInfo->is_cancel = 1;
                 $orderInfo->mark = '订单未支付已超过系统预设时间';
                 $orderInfo->save();
             }

+ 2 - 2
crmeb/app/jobs/notice/PrintJob.php

@@ -30,12 +30,12 @@ class PrintJob extends BaseJobs
      * @param $id
      * @return bool|void
      */
-    public function doJob($id)
+    public function doJob($id, $print_type)
     {
         try {
             /** @var StoreOrderServices $orderServices */
             $orderServices = app()->make(StoreOrderServices::class);
-            $orderServices->orderPrintTicket((int)$id);
+            $orderServices->orderPrintTicket((int)$id, $print_type);
             return true;
         } catch (\Throwable $e) {
             Log::error('小票打印失败失败,失败原因:' . $e->getMessage());

+ 0 - 1
crmeb/app/listener/admin/AdminLoginListener.php

@@ -31,7 +31,6 @@ class AdminLoginListener
             $content = file_get_contents($path);
             $res = $key === $content;
             if (sys_config('queue_open', 0) == 0) $res = true;
-            unlink($path);
         } catch (\Throwable $e) {
         }
 

+ 1 - 1
crmeb/app/listener/http/HttpEndListener.php

@@ -21,7 +21,7 @@ use think\Response;
  */
 class HttpEndListener
 {
-    public function handle(Response $response):void
+    public function handle(Response $response): void
     {
         if (!is_array($response->getData())) return;
         //业务成功和失败分开存储

+ 35 - 2
crmeb/app/listener/notice/NoticeListener.php

@@ -68,6 +68,8 @@ class NoticeListener implements ListenerInterface
         'send_admin_confirm_take_over' => 'handleSendAdminConfirmTakeOver',
         'send_order_apply_refund' => 'handleSendOrderApplyRefund',
         'kefu_send_extract_application' => 'handleKefuSendExtractApplication',
+        'sign_remind' => 'handleSignRemind',
+        'revenue_received' => 'handleRevenueReceived',
         // add more event-method mappings here...
     ];
 
@@ -166,8 +168,6 @@ class NoticeListener implements ListenerInterface
         $this->getNoticeService('Wechat')->sendOrderPaySuccess($data['uid'], $data);
         //模板消息小程序订阅消息
         $this->getNoticeService('Routine')->sendOrderSuccess($data['uid'], $data['pay_price'], $data['order_id']);
-        //小票打印
-        if (isset($data['cart_id']) && $data['cart_id']) PrintJob::dispatch([$data['id']]);
         return true;
     }
 
@@ -672,4 +672,37 @@ class NoticeListener implements ListenerInterface
         $this->getNoticeService('WeWork')->weComSend($data);
         return true;
     }
+
+    /**
+     * 签到提醒
+     * @param $data
+     * @return bool
+     * @author wuhaotian
+     * @email 442384644@qq.com
+     * @date 2023/9/30
+     */
+    public function handleSignRemind($data)
+    {
+        //站内信
+        $this->getNoticeService('SysMsg')->sendMsg($data['uid'], ['site_name' => sys_config('site_name')]);
+        //短信
+        if ($data['phone']) {
+            $this->getNoticeService('Sms')->sendSms($data['phone'], ['site_name' => sys_config('site_name')]);
+        }
+        return true;
+    }
+
+    protected function handleRevenueReceived($data)
+    {
+        $extractNumber = $data['extractNumber'];
+        $uid = $data['uid'];
+        $order_id = $data['order_id'];
+        $type = $data['type'];
+
+        //模板消息公众号模版消息
+        $this->getNoticeService('Wechat')->sendRevenueReceived($uid, $extractNumber, $order_id, $type);
+        //模板消息小程序订阅消息
+        $this->getNoticeService('Routine')->sendRevenueReceived($uid, $extractNumber, $order_id, $type);
+        return true;
+    }
 }

+ 0 - 0
crmeb/app/listener/order/OrderCreateAfterListener.php


部分文件因文件數量過多而無法顯示