moonsflyer 2 ay önce
ebeveyn
işleme
f3005c6de9
100 değiştirilmiş dosya ile 15507 ekleme ve 0 silme
  1. 131 0
      app/admin/controller/Express.php
  2. 67 0
      app/admin/controller/Footprint.php
  3. 65 0
      app/admin/controller/Freight.php
  4. 105 0
      app/admin/controller/Recharge.php
  5. 172 0
      app/admin/controller/Seckill.php
  6. 24 0
      app/admin/controller/account_log/AccountLog.php
  7. 109 0
      app/admin/controller/activity_area/Area.php
  8. 125 0
      app/admin/controller/activity_area/Goods.php
  9. 230 0
      app/admin/controller/bargain/Bargain.php
  10. 40 0
      app/admin/controller/coupon/ShopCoupon.php
  11. 58 0
      app/admin/controller/distribution/Apply.php
  12. 89 0
      app/admin/controller/distribution/Center.php
  13. 47 0
      app/admin/controller/distribution/DistributionGoods.php
  14. 84 0
      app/admin/controller/distribution/DistributionLevel.php
  15. 112 0
      app/admin/controller/distribution/DistributionMember.php
  16. 25 0
      app/admin/controller/distribution/DistributionOrder.php
  17. 49 0
      app/admin/controller/distribution/DistributionSetting.php
  18. 154 0
      app/admin/controller/distribution/Member.php
  19. 22 0
      app/admin/controller/distribution/Record.php
  20. 36 0
      app/admin/controller/distribution/Setting.php
  21. 39 0
      app/admin/controller/finance/Finance.php
  22. 65 0
      app/admin/controller/finance/Integral.php
  23. 270 0
      app/admin/controller/finance/Shop.php
  24. 476 0
      app/admin/controller/finance/User.php
  25. 118 0
      app/admin/controller/integral/IntegralGoods.php
  26. 161 0
      app/admin/controller/integral/IntegralOrder.php
  27. 159 0
      app/admin/controller/kefu/Kefu.php
  28. 110 0
      app/admin/controller/kefu/KefuLang.php
  29. 118 0
      app/admin/controller/live/LiveGoods.php
  30. 123 0
      app/admin/controller/live/LiveRoom.php
  31. 89 0
      app/admin/controller/order/Invoice.php
  32. 130 0
      app/admin/controller/order/Order.php
  33. 82 0
      app/admin/controller/seckill/SeckillGoods.php
  34. 75 0
      app/admin/controller/seckill/SeckillTime.php
  35. 133 0
      app/admin/controller/sign_daily/SignDaily.php
  36. 113 0
      app/admin/controller/team/Activity.php
  37. 72 0
      app/admin/controller/team/Found.php
  38. 39 0
      app/admin/controller/team/Setting.php
  39. 89 0
      app/admin/controller/user/Level.php
  40. 72 0
      app/admin/controller/user/Tag.php
  41. 171 0
      app/admin/controller/user/User.php
  42. 77 0
      app/admin/logic/FootprintLogic.php
  43. 139 0
      app/admin/logic/RechargeLogic.php
  44. 110 0
      app/admin/logic/account_log/AccountLogLogic.php
  45. 142 0
      app/admin/logic/activity_area/AreaLogic.php
  46. 193 0
      app/admin/logic/activity_area/GoodsLogic.php
  47. 433 0
      app/admin/logic/bargain/BargainLogic.php
  48. 191 0
      app/admin/logic/coupon/ShopCouponLogic.php
  49. 143 0
      app/admin/logic/distribution/ApplyLogic.php
  50. 143 0
      app/admin/logic/distribution/CenterLogic.php
  51. 169 0
      app/admin/logic/distribution/DistributionGoodsLogic.php
  52. 514 0
      app/admin/logic/distribution/DistributionLevelLogic.php
  53. 231 0
      app/admin/logic/distribution/DistributionMemberLogic.php
  54. 110 0
      app/admin/logic/distribution/DistributionOrderLogic.php
  55. 95 0
      app/admin/logic/distribution/DistributionSettingLogic.php
  56. 414 0
      app/admin/logic/distribution/MemberLogic.php
  57. 84 0
      app/admin/logic/distribution/RecordLogic.php
  58. 232 0
      app/admin/logic/finance/FinanceLogic.php
  59. 123 0
      app/admin/logic/finance/IntegralLogic.php
  60. 233 0
      app/admin/logic/finance/ShopSettlementLogic.php
  61. 446 0
      app/admin/logic/finance/ShopWithdrawalLogic.php
  62. 929 0
      app/admin/logic/finance/WithdrawLogic.php
  63. 199 0
      app/admin/logic/integral/IntegralGoodsLogic.php
  64. 362 0
      app/admin/logic/integral/IntegralOrderLogic.php
  65. 102 0
      app/admin/logic/kefu/KefuLangLogic.php
  66. 231 0
      app/admin/logic/kefu/KefuLogic.php
  67. 219 0
      app/admin/logic/live/LiveGoodsLogic.php
  68. 240 0
      app/admin/logic/live/LiveRoomLogic.php
  69. 172 0
      app/admin/logic/order/InvoiceLogic.php
  70. 539 0
      app/admin/logic/order/OrderLogic.php
  71. 266 0
      app/admin/logic/seckill/SeckillGoodsLogic.php
  72. 73 0
      app/admin/logic/seckill/SeckillTimeLogic.php
  73. 219 0
      app/admin/logic/sign_daily/SignDailyLogic.php
  74. 297 0
      app/admin/logic/team/ActivityLogic.php
  75. 154 0
      app/admin/logic/team/FoundLogic.php
  76. 210 0
      app/admin/logic/user/LevelLogic.php
  77. 108 0
      app/admin/logic/user/TagLogic.php
  78. 549 0
      app/admin/logic/user/UserLogic.php
  79. 99 0
      app/admin/validate/BargainValidate.php
  80. 19 0
      app/admin/validate/ExpressValidate.php
  81. 85 0
      app/admin/validate/FreightValidate.php
  82. 35 0
      app/admin/validate/RechargeTemplateValidate.php
  83. 40 0
      app/admin/validate/activity_area/ActivityGoods.php
  84. 55 0
      app/admin/validate/activity_area/AreaValidate.php
  85. 151 0
      app/admin/validate/distribution/DistributionLevelValidate.php
  86. 101 0
      app/admin/validate/distribution/MemberValidate.php
  87. 137 0
      app/admin/validate/integral/IntegralGoodsValidate.php
  88. 144 0
      app/admin/validate/integral/IntegralOrderValidate.php
  89. 68 0
      app/admin/validate/kefu/KefuLangValidate.php
  90. 98 0
      app/admin/validate/kefu/KefuValidate.php
  91. 30 0
      app/admin/validate/kefu/LoginValidate.php
  92. 86 0
      app/admin/validate/live/LiveGoodsValidate.php
  93. 83 0
      app/admin/validate/live/LiveRoomValidate.php
  94. 50 0
      app/admin/validate/order/OrderValidate.php
  95. 42 0
      app/admin/validate/seckill/SeckillTimeValidate.php
  96. 121 0
      app/admin/validate/sign_daily/SignDailyValidate.php
  97. 35 0
      app/admin/validate/user/LevelValidate.php
  98. 30 0
      app/admin/validate/user/TagValidate.php
  99. 242 0
      app/admin/validate/user/UserValidate.php
  100. 217 0
      app/admin/view/account_log/account_log/growth_lists.html

+ 131 - 0
app/admin/controller/Express.php

@@ -0,0 +1,131 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\controller;
+
+use app\admin\validate\ExpressValidate;
+use app\common\basics\AdminBase;
+use app\common\server\ConfigServer;
+use app\common\logic\ExpressLogic;
+use app\common\server\JsonServer;
+use think\db;
+use think\exception\ValidateException;
+
+class Express extends AdminBase
+{
+    /**
+     * lists
+     * @return mixed
+     * @throws \think\exception\DbException
+     * @throws db\exception\DataNotFoundException
+     * @throws db\exception\ModelNotFoundException
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            return JsonServer::error('', ExpressLogic::lists($get));
+        }
+    }
+
+    /**
+     * 添加
+     * @return mixed
+     */
+    public function add()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['del'] = 0;
+            try {
+                validate(ExpressValidate::class)->scene('add')->check($post);
+                $result = ExpressLogic::addExpress($post);
+                if ($result) {
+                    return JsonServer::success('添加成功');
+                }
+                return JsonServer::error($result);
+            } catch (ValidateException $e) {
+                return JsonServer::error($e->getMessage());
+            }
+        }
+        return view();
+    }
+
+    /**
+     * 编辑
+     * @param $id
+     * @return mixed
+     */
+    public function edit($id)
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['del'] = 0;
+            try {
+                validate(ExpressValidate::class)->scene('edit')->check($post);
+                $result = ExpressLogic::editExpress($post);
+                if ($result) {
+                    return JsonServer::success('修改成功');
+                }
+                return JsonServer::error($result);
+            } catch (ValidateException $e) {
+                return JsonServer::error($e->getMessage());
+            }
+        }
+        return view('', [
+            'info' => ExpressLogic::info($id)
+        ]);
+    }
+
+
+    /**
+     * 删除
+     * @param $delData
+     * @throws \think\Exception
+     * @throws \think\exception\PDOException
+     */
+    public function del($delData)
+    {
+        if ($this->request->isAjax()) {
+            $result = ExpressLogic::delExpress($delData);
+            if ($result) {
+                return JsonServer::success('删除成功');
+            }
+            return JsonServer::error('删除失败');
+        }
+    }
+
+    //查询配置
+    public function setExpress()
+    {
+        $post = $this->request->post();
+        if ($post) {
+            ConfigServer::set('express', 'way', $post['way']);
+
+            ConfigServer::set('kd100', 'appkey', $post['kd100_appkey']);
+            ConfigServer::set('kd100', 'appsecret', $post['kd100_customer']);
+
+            ConfigServer::set('kdniao', 'appkey', $post['kdniao_appkey']);
+            ConfigServer::set('kdniao', 'appsecret', $post['kdniao_ebussinessid']);
+            ConfigServer::set('kdniao', 'type', $post['kdniao_type']);
+        }
+        return JsonServer::success('操作成功');
+    }
+}

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

@@ -0,0 +1,67 @@
+<?php
+
+
+namespace app\admin\controller;
+
+
+use app\admin\logic\FootprintLogic;
+use app\common\basics\AdminBase;
+use app\common\server\ConfigServer;
+use app\common\server\JsonServer;
+use think\facade\View;
+
+class Footprint extends AdminBase
+{
+    /**
+     * @Notes: 足迹气泡配置页
+     * @Author: 张无忌
+     * @return \think\response\View
+     */
+    public function index()
+    {
+        $config['footprint_status']   = ConfigServer::get('footprint','footprint_status',0);
+        $config['footprint_duration'] = ConfigServer::get('footprint','footprint_duration',60);
+        View::assign('config', $config);
+        View::assign('footprint', FootprintLogic::lists());
+        return view();
+    }
+
+    /**
+     * @Notes: 编辑足迹气泡
+     * @Author: 张无忌
+     */
+    public function edit()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $result = FootprintLogic::edit($post);
+            if ($result === false) {
+                $message = FootprintLogic::getError() ?: '编辑失败';
+                return JsonServer::error($message);
+            }
+            return JsonServer::success('编辑成功');
+        }
+
+        $id = $this->request->get('id');
+        View::assign('detail', FootprintLogic::detail($id));
+        return view();
+    }
+
+    /**
+     * @Notes: 设置足迹
+     * @Author: 张无忌
+     */
+    public function set()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $result = FootprintLogic::set($post);
+            if ($result === false) {
+                $message = FootprintLogic::getError() ?: '设置失败';
+                return JsonServer::error($message);
+            }
+            return JsonServer::success('设置成功');
+        }
+        return JsonServer::error('请求异常');
+    }
+}

+ 65 - 0
app/admin/controller/Freight.php

@@ -0,0 +1,65 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller;
+
+use app\common\logic\ExpressLogic;
+use app\common\basics\AdminBase;
+use app\common\server\ConfigServer;
+use app\common\logic\FreightLogic;
+use app\common\model\Freight as FreightModel;
+use app\common\server\JsonServer;
+
+class Freight extends AdminBase
+{
+    /**
+     * User: 意象信息科技 mjf
+     * Desc: 设置快递方式
+     */
+    public function set()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['type'] = isset($post['type']) && $post['type'] == 'on' ? 1 : 0;
+            ConfigServer::set('express', 'is_express', $post['type']);
+            return JsonServer::success('操作成功');
+        }
+        $type = ConfigServer::get('express', 'is_express');
+        return view('', [
+            'type' => $type
+        ]);
+    }
+
+    /**
+     * User: 意象信息科技 mjf
+     * Desc: 运费模板列表
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            return JsonServer::success('获取成功', FreightLogic::lists($get));//运费模板页
+        }
+        return view('index', [
+            'charge_way_lists' => FreightModel::getChargeWay(true),
+            'config'=>ExpressLogic::getExpress()
+        ]);
+    }
+
+}

+ 105 - 0
app/admin/controller/Recharge.php

@@ -0,0 +1,105 @@
+<?php
+namespace app\admin\controller;
+
+use app\common\basics\AdminBase;
+use app\admin\logic\RechargeLogic;
+use app\common\server\JsonServer;
+use app\admin\validate\RechargeTemplateValidate;
+use think\exception\ValidateException;
+
+class Recharge extends AdminBase
+{
+    public function lists(){
+        if($this->request->isAjax()){
+            $get = $this->request->get();
+            if($get['type'] == 1){ // 充值方案
+                $list = RechargeLogic::templatelists($get['type']);
+            }else{ // 充值配置
+                $list = RechargeLogic::getRechargeConfig();
+            }
+            return JsonServer::success('', $list);
+
+        }
+        return view();
+    }
+
+    public function add(){
+
+        if ($this->request->isAjax()){
+            $post = $this->request->post();
+            try{
+                validate(RechargeTemplateValidate::class)->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = RechargeLogic::add($post);
+            if ($result === true){
+                return JsonServer::success('新增成功');
+            }
+            return JsonServer::error(RechargeLogic::getError());
+
+        }
+        return view();
+    }
+
+    public function changeFields(){
+        $table = 'recharge_template';
+
+        $pk_name = 'id';
+        $pk_value = $this->request->get('id');
+
+        $field = $this->request->get('field');
+        $field_value = $this->request->get('value');
+        $result = RechargeLogic::changeTableValue($table,$pk_name,$pk_value,$field,$field_value);
+        if($result){
+            return JsonServer::success('修改成功');
+        }
+        return JsonServer::error('修改失败');
+    }
+
+    public function edit($id){
+        if ($this->request->isAjax()){
+            $post = $this->request->post();
+            try{
+                validate(RechargeTemplateValidate::class)->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = RechargeLogic::edit($post);
+            if ($result === true){
+                return JsonServer::success('编辑成功');
+            }
+            return JsonServer::error('编辑失败');
+        }
+
+        $info = RechargeLogic::getRechargeTemplate($id);
+        return view('', [
+            'info' => $info
+        ]);
+    }
+
+    public function del($id)
+    {
+        if ($this->request->isAjax()) {
+            $result = RechargeLogic::del($id);
+            if ($result) {
+                return JsonServer::success('删除成功');
+            }
+            return JsonServer::error('删除失败');
+        }
+    }
+
+    public function setRecharge(){
+        if($this->request->isAjax()){
+            $post = $this->request->post();
+            if($post['give_growth'] < 0) {
+                return JsonServer::error('赠送成长值不能小于0');
+            }
+            if($post['min_money'] < 0) {
+                return JsonServer::error('最低充值金额不能小于0');
+            }
+            RechargeLogic::setRecharge($post);
+            return JsonServer::success('设置成功');
+        }
+    }
+}

+ 172 - 0
app/admin/controller/Seckill.php

@@ -0,0 +1,172 @@
+<?php
+declare (strict_types = 1);
+
+namespace app\admin\controller;
+
+use app\admin\logic\SeckillLogic;
+use app\common\server\JsonServer;
+use think\Request;
+use think\Controller;
+use app\common\basics\AdminBase;
+
+class Seckill extends AdminBase
+{
+    public function lists(){
+        $seckill_time = SeckillLogic::getTimeAll();
+        return view('', [
+            'seckill' => $seckill_time
+        ]);
+    }
+    /**
+     * note 秒杀商品
+     * create_time 2020/11/13 16:01
+     */
+    public function goodsLists(){
+        if($this->request->isAjax()){
+            $get = $this->request->get();
+            $list = SeckillLogic::goodsList($get);
+            return JsonServer::success('',$list,0);
+        }
+    }
+
+    /**
+     * note 秒杀时间
+     * create_time 2020/11/13 16:01
+     */
+    public function timeLists(){
+        if($this->request->isAjax()){
+            $get= $this->request->get();
+            $list = SeckillLogic::timeList($get);
+            return JsonServer::success('',$list,0);
+        }
+    }
+    /**
+     * note 添加秒杀时间段
+     * create_time 2020/11/13 16:01
+     */
+    public function addTime(){
+        if($this->request->isAjax()){
+            $post = $this->request->post();
+            $result = $this->validate($post, 'app\admin\validate\SeckillTime');
+            if($result === true){
+                SeckillLogic::addTime($post);
+                $this->_success('新增成功','');
+            }
+            $this->_error($result,'');
+
+
+        }
+        return $this->fetch();
+    }
+
+    /**
+     * note 编辑秒杀时间段
+     * create_time 2020/11/13 16:02
+     */
+    public function editTime($id){
+        if($this->request->isAjax()){
+            $post = $this->request->post();
+            $result = $this->validate($post, 'app\admin\validate\SeckillTime');
+            if($result === true){
+                SeckillLogic::editTime($post);
+                $this->_success('编辑成功','');
+            }
+            $this->_error($result,'');
+        }
+        $this->assign('detail',SeckillLogic::getTime($id));
+        return $this->fetch();
+    }
+
+    /**
+     * note 删除秒杀时间段
+     * create_time 2020/11/13 16:02
+     */
+    public function delTime(){
+        if($this->request->isAjax()){
+            $id = $this->request->post('id');
+            $result = SeckillLogic::delTime($id);
+
+            if($result == true){
+                $this->_success('删除成功','');
+            }
+            return $this->_error('删除失败','');
+
+
+        }
+    }
+    /**
+     * note 添加秒杀商品
+     * create_time 2020/11/13 16:02
+     */
+    public function addGoods(){
+        if($this->request->isAjax()){
+            $post = $this->request->post();
+            $post['item'] = form_to_linear($post);
+            $result = $this->validate($post,'app\admin\validate\SeckillGoods.add');
+            if($result === true){
+                $result = SeckillLogic::addGoods($post);
+                if($result){
+                    $this->_success('新增成功','');
+                }
+                $result = '新增失败';
+            }
+            $this->_error($result);
+
+        }
+        $seckill_time = SeckillLogic::getTimeAll();
+        foreach ($seckill_time as $k=>$v){
+//            $seckill_time[$k]["time"]
+        }
+        return view('', [
+            'seckill' =>$seckill_time
+        ]);
+//        $this->assign('seckill',$seckill_time);
+//        return $this->fetch();
+    }
+    /**
+     * note 编辑秒杀商品
+     * create_time 2020/11/13 16:02
+     */
+    public function editGoods(){
+        if($this->request->isAjax()){
+            $post = $this->request->post();
+            $post['item'] = form_to_linear($post);
+            $result = $this->validate($post,'app\admin\validate\SeckillGoods.edit');
+            if($result === true){
+                $result = SeckillLogic::editGoods($post);
+                if($result){
+                    $this->_success('编辑成功','');
+                }
+                $result = '编辑失败';
+            }
+            $this->_error($result);
+
+
+        }
+        $id = $this->request->get('id');
+        $seckill_id = $this->request->get('seckill_id');
+
+        $detail = SeckillLogic::getSeckillGoods($id,$seckill_id);
+        $seckill_time = SeckillLogic::getTimeAll();
+        $this->assign('seckill',$seckill_time);
+        $this->assign('detail',$detail);
+        return $this->fetch();
+    }
+
+    /**
+     * note 删除秒杀商品
+     * create_time 2020/11/13 16:05
+     */
+    public function delGoods(){
+        if($this->request->isAjax()){
+            $id = $this->request->post('id');
+            $seckill_id = $this->request->post('seckill_id');
+            $result = SeckillLogic::delGoods($id,$seckill_id);
+
+            if($result == true){
+                $this->_success('删除成功','');
+            }
+            return $this->_error('删除失败','');
+        }
+    }
+}

+ 24 - 0
app/admin/controller/account_log/AccountLog.php

@@ -0,0 +1,24 @@
+<?php
+namespace app\admin\controller\account_log;
+
+use app\common\basics\AdminBase;
+use app\admin\logic\account_log\AccountLogLogic;
+use app\common\model\AccountLog as AccountLogModel;
+use app\common\server\JsonServer;
+
+class AccountLog extends AdminBase
+{
+    public function growthLists()
+    {
+        if($this->request->isAjax()) {
+            $get = $this->request->get();
+            $data = AccountLogLogic::growthLists($get);
+            return JsonServer::success('', $data);
+        }
+
+        return view('', [
+            'typeDescArr' => AccountLogLogic::getTypeDesc(AccountLogModel::growth_change),
+            'time' => AccountLogLogic::getTime()
+        ]);
+    }
+}

+ 109 - 0
app/admin/controller/activity_area/Area.php

@@ -0,0 +1,109 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+namespace app\admin\controller\activity_area;
+
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use think\facade\View;
+use app\admin\validate\activity_area\AreaValidate;
+use app\admin\logic\activity_area\AreaLogic;
+use app\admin\logic\activity_area\GoodsLogic;
+
+/**
+ * Class Area
+ * @package app\admin\controller\activity_area
+ */
+class Area extends AdminBase
+{
+    /**
+     * @notes 活动专区列表
+     * @return \think\response\Json|\think\response\View
+     * @author suny
+     * @date 2021/7/13 6:57 下午
+     */
+    public function lists()
+    {
+
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = AreaLogic::lists($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+        return View();
+    }
+
+    /**
+     * @notes 新增活动专区
+     * @return \think\response\Json|\think\response\View
+     * @author suny
+     * @date 2021/7/13 6:57 下午
+     */
+    public function add()
+    {
+
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['del'] = 0;
+            (new AreaValidate())->goCheck('add', $post);
+            AreaLogic::add($post);
+            return JsonServer::success('添加成功');
+        }
+        return View();
+    }
+
+    /**
+     * @notes 编辑活动专区
+     * @return \think\response\Json|\think\response\View
+     * @author suny
+     * @date 2021/7/13 6:57 下午
+     */
+    public function edit()
+    {
+
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['del'] = 0;
+            $post['status'] = isset($post['status']) ? 1 : 0;
+            (new AreaValidate())->goCheck('edit', $post);
+            AreaLogic::edit($post);
+            return JsonServer::success('修改成功');
+        }
+        $id = $this->request->get('id');
+        $detail = AreaLogic::getActivityArea($id);
+        View::assign('detail', $detail);
+        return View();
+    }
+
+
+    /**
+     * @notes 删除活动专区
+     * @return \think\response\Json
+     * @author suny
+     * @date 2021/7/13 6:57 下午
+     */
+    public function del()
+    {
+
+        $id = $this->request->post('id');
+        (new AreaValidate())->goCheck('del', ['id' => $id]);
+
+        return JsonServer::success('删除成功', [AreaLogic::del($id)]);
+    }
+
+}

+ 125 - 0
app/admin/controller/activity_area/Goods.php

@@ -0,0 +1,125 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\activity_area;
+
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use think\facade\View;
+use app\admin\logic\activity_area\AreaLogic;
+use app\admin\logic\activity_area\GoodsLogic;
+use app\admin\validate\activity_area\ActivityGoods;
+
+/**
+ * Class Goods
+ * @package app\admin\controller\activity_area
+ */
+class Goods extends AdminBase
+{
+
+    /**
+     * @notes 活动专区商品列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/13 6:58 下午
+     */
+    public function lists()
+    {
+
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $list = GoodsLogic::lists($get);
+            return JsonServer::success('获取成功', $list);
+        }
+        $activity_area = AreaLogic::getActivityAreaAll();
+        $num = GoodsLogic::getNum();
+        View::assign('num', $num);
+        View::assign('activity_area', $activity_area);
+        return View();
+    }
+
+    /**
+     * @notes 活动专区商品审核
+     * @return \think\response\Json|\think\response\View
+     * @author suny
+     * @date 2021/7/13 6:58 下午
+     */
+    public function audit()
+    {
+
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            (new ActivityGoods())->goCheck('audit', $post);
+            $result = GoodsLogic::audit($post);
+            if ($result) {
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error('操作失败');
+        }
+        $id = $this->request->get('id');
+        $detail = GoodsLogic::getActivityAreaGoods($id);
+        View::assign('detail', $detail);
+        View::assign('id', $id);
+        return View();
+    }
+
+    /**
+     * @notes 违规操作
+     * @return \think\response\Json|\think\response\View
+     * @author suny
+     * @date 2021/7/13 6:58 下午
+     */
+    public function violation()
+    {
+
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $id = $post['id'];
+            (new ActivityGoods())->goCheck('violation', $post);
+            $result = GoodsLogic::violation($post);
+            if ($result) {
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error('操作失败');
+        }
+        $id = $this->request->get('id');
+        $detail = GoodsLogic::getActivityAreaGoods($id);
+        View::assign('detail', $detail);
+        View::assign('id', $id);
+        return View();
+    }
+
+    /**
+     * @notes 活动商品详情
+     * @return \think\response\View
+     * @author suny
+     * @date 2021/7/13 6:58 下午
+     */
+    public function detail()
+    {
+
+        $get = $this->request->get();
+        $detail = GoodsLogic::detail($get);
+        View::assign('detail', $detail);
+        return View();
+    }
+}

+ 230 - 0
app/admin/controller/bargain/Bargain.php

@@ -0,0 +1,230 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\controller\bargain;
+
+use app\admin\logic\bargain\BargainLogic;
+use app\common\server\ConfigServer;
+use app\common\server\JsonServer;
+use app\common\basics\AdminBase;
+use app\admin\validate\BargainValidate;
+use think\facade\View;
+
+/**
+ * Class Bargain
+ * @package app\admin\controller\bargain
+ */
+class Bargain extends AdminBase
+{
+
+    /**
+     * @notes 砍价活动商品列表
+     * @return string|\think\response\Json
+     * @author suny
+     * @date 2021/7/13 6:59 下午
+     */
+    public function activity()
+    {
+
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = BargainLogic::activity($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+        $num = BargainLogic::getNum();
+        View::assign('num', $num);
+        return View::fetch('bargain/activity');
+    }
+
+    /**
+     * @notes 砍价活动商品审核
+     * @return \think\response\Json|\think\response\View
+     * @author suny
+     * @date 2021/7/13 6:59 下午
+     */
+    public function audit()
+    {
+
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            (new BargainValidate())->goCheck('audit', $post);
+            $result = BargainLogic::audit($post);
+            if ($result) {
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error('操作失败');
+        }
+        $id = $this->request->get('id');
+        View::assign('id', $id);
+        return View('bargain/audit');
+    }
+
+
+    /**
+     * @notes 违规操作
+     * @return \think\response\Json|\think\response\View
+     * @author suny
+     * @date 2021/7/13 6:59 下午
+     */
+    public function violation()
+    {
+
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $id = $post['id'];
+            (new BargainValidate())->goCheck('violation', $post);
+            $result = BargainLogic::violation($post);
+            if ($result) {
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error('操作失败');
+        }
+        $id = $this->request->get('id');
+        View::assign('id', $id);
+        return View('bargain/violation');
+    }
+
+    /**
+     * @notes 砍价商品详情
+     * @return \think\response\View
+     * @author suny
+     * @date 2021/7/13 6:59 下午
+     */
+    public function bargain_detail()
+    {
+
+        $get = $this->request->get();
+        $detail = BargainLogic::detail($get);
+        View::assign('detail', $detail);
+        return View('bargain/bargain_detail');
+    }
+
+    /**
+     * @notes 切换状态
+     * @return \think\response\Json
+     * @author suny
+     * @date 2021/7/13 7:00 下午
+     */
+    public function switchStatus()
+    {
+
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            if (BargainLogic::switchStatus($post)) {
+                return JsonServer::success('更新成功');
+            } else {
+                $error = BargainLogic::getError() ?? '更新失败';
+                return JsonServer::error($error);
+            }
+        }
+    }
+
+    /**
+     * @notes 砍价记录列表
+     * @return string|\think\response\Json
+     * @author suny
+     * @date 2021/7/13 7:00 下午
+     */
+    public function launch()
+    {
+
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = BargainLogic::getLaunch($get);
+            if (false === $lists) {
+                return JsonServer::error('结束时间必须大于开始时间!');
+            } else {
+                return JsonServer::success('OK', $lists);
+            }
+        }
+
+        $bargain_id = $this->request->get('bargain_id', 0);
+        View::assign('bargain_id', $bargain_id);
+        return View::fetch('bargain/launch');
+    }
+
+    /**
+     * @notes 砍价记录详情
+     * @return string
+     * @author suny
+     * @date 2021/7/13 7:00 下午
+     */
+    public function detail()
+    {
+
+        $id = $this->request->get('id');
+        $detail = BargainLogic::getLaunchDetail($id);
+        View::assign('detail', $detail);
+        return View::fetch('bargain/detail');
+    }
+
+    /**
+     * @notes 砍价订单记录
+     * @return \think\response\Json
+     * @author suny
+     * @date 2021/7/13 7:00 下午
+     */
+    public function knifeOrderRecord()
+    {
+
+        $launch_id = $this->request->get('launch_id');
+        $get = $this->request->get();
+        $lists = BargainLogic::getKnifeOrderRecord($launch_id, $get);
+        return JsonServer::success('获取成功', $lists);
+    }
+
+    /**
+     * @notes 砍价助力记录
+     * @return \think\response\Json
+     * @author suny
+     * @date 2021/7/13 7:00 下午
+     */
+    public function knifeRecord()
+    {
+
+        $launch_id = $this->request->get('launch_id');
+        $get = $this->request->get();
+        $lists = BargainLogic::getKnifeRecord($launch_id, $get);
+        return JsonServer::success('获取成功', $lists);
+    }
+
+    /**
+     * @notes 砍价设置
+     * @return string|\think\response\Json
+     * @author suny
+     * @date 2021/7/13 7:00 下午
+     */
+    public function set()
+    {
+
+        if ($this->request->isAjax()) {
+            $payment_limit_time = $this->request->post('payment_limit_time', 0);
+            try {
+                ConfigServer::set('bargain', 'payment_limit_time', $payment_limit_time);
+            } catch (\Exception $e) {
+                return JsonServer::error('设置失败');
+            }
+            return JsonServer::success('设置成功');
+        }
+        $payment_limit_time = ConfigServer::get('bargain', 'payment_limit_time', 0);
+        View::assign('payment_limit_time', $payment_limit_time);
+        return View::fetch('bargain/set');
+    }
+}

+ 40 - 0
app/admin/controller/coupon/ShopCoupon.php

@@ -0,0 +1,40 @@
+<?php
+namespace app\admin\controller\coupon;
+
+use app\common\basics\AdminBase;
+use app\admin\logic\coupon\ShopCouponLogic;
+use app\common\server\JsonServer;
+
+class ShopCoupon extends AdminBase
+{
+    public function lists(){
+        if($this->request->isAjax()){
+            $get = $this->request->get();
+            $data = ShopCouponLogic::lists($get);
+            return JsonServer::success('', $data);
+        }
+        return view();
+    }
+
+    public function detail(){
+        $id = $this->request->get('id');
+        $detail = ShopCouponLogic::getCoupon($id,true);
+        return view('', [
+            'detail' => json_encode($detail,JSON_UNESCAPED_UNICODE)
+        ]);
+    }
+
+    public function record()
+    {
+        if($this->request->isAjax()){
+            $get = $this->request->get();
+            $data = ShopCouponLogic::record($get);
+            return JsonServer::success('', $data);
+        }
+
+        $id = $this->request->get('id');
+        return view('', [
+            'id' => $id
+        ]);
+    }
+}

+ 58 - 0
app/admin/controller/distribution/Apply.php

@@ -0,0 +1,58 @@
+<?php
+
+
+namespace app\admin\controller\distribution;
+
+
+use app\admin\logic\distribution\ApplyLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use think\facade\View;
+
+class Apply extends AdminBase
+{
+    /**
+     * @Notes: 分销申请列表
+     * @Author: 张无忌
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = ApplyLogic::lists($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+
+        return view();
+    }
+
+    /**
+     * @Notes: 分销申请详细
+     * @Author: 张无忌
+     */
+    public function detail()
+    {
+        $id = $this->request->get('id');
+        View::assign('detail', ApplyLogic::detail($id));
+        return view();
+    }
+
+    /**
+     * @Notes: 审核分销申请
+     * @Author: 张无忌
+     */
+    public function audit()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $res = ApplyLogic::audit($post);
+            if ($res === false) {
+                $message = ApplyLogic::getError() ?: '审核失败';
+                return JsonServer::error($message);
+            }
+            return JsonServer::success('审核成功');
+        }
+
+        return view();
+    }
+}

+ 89 - 0
app/admin/controller/distribution/Center.php

@@ -0,0 +1,89 @@
+<?php
+namespace app\admin\controller\distribution;
+
+use app\admin\logic\distribution\CenterLogic;
+use app\common\basics\AdminBase;
+use app\common\model\distribution\Distribution;
+use app\common\model\distribution\DistributionLevel;
+use app\common\model\user\User;
+use app\common\server\JsonServer;
+use app\common\model\distribution\DistributionOrderGoods;
+
+class Center extends AdminBase
+{
+    public function data()
+    {
+        // 已结算: 已结算
+        $settled = DistributionOrderGoods::where(['status'=>2])->sum('money');
+        // 预估: 待返佣 + 已结算
+        $estimate = DistributionOrderGoods::where('status', 'in', [1, 2])->sum('money');
+        return view('', [
+            'settled' => $settled,
+            'estimate' => $estimate
+        ]);
+    }
+
+    /**
+     * @notes 数据概览
+     * @return \think\response\Json
+     * @author Tab
+     * @date 2021/9/6 14:35
+     */
+    public function center()
+    {
+        $data = CenterLogic::center();
+        return view('', ['data' => $data]);
+    }
+
+    /**
+     * @notes 分销初始化数据
+     * @return \think\response\Json
+     * @author Tab
+     * @date 2021/9/6 14:26
+     */
+    public function updateTable()
+    {
+        try {
+            $defaultLevel = DistributionLevel::where('is_default', 1)->findOrEmpty()->toArray();
+            if (empty($defaultLevel)) {
+                // 没有默认等级,初始化
+                DistributionLevel::create([
+                    'name' => '默认等级',
+                    'weights' => '1',
+                    'is_default' => '1',
+                    'remark' => '默认等级',
+                    'update_relation' => '1'
+                ]);
+            }
+            // 默认分销会员等级
+            $defaultLevelId = DistributionLevel::where('is_default', 1)->value('id');
+            // 生成分销基础信息表
+            $users = User::field('id,is_distribution')
+                ->where(['del' => 0])
+                ->select()
+                ->toArray();
+            $distribution = Distribution::column('user_id');
+            $addData = [];
+            foreach($users as $item) {
+                if (in_array($item['id'], $distribution)) {
+                    // 已有基础分销记录,跳过
+                    continue;
+                }
+                $data = [
+                    'user_id' => $item['id'],
+                    'level_id' => $defaultLevelId,
+                    'is_distribution' => $item['is_distribution'],
+                    'is_freeze' => 0,
+                    'remark' => '',
+                ];
+                $addData[] = $data;
+            }
+            $distributionModel = new Distribution();
+            $distributionModel->saveAll($addData);
+
+            return JsonServer::success('初始化数据完成');
+        } catch(\Exception $e) {
+            return JsonServer::error($e->getMessage());
+        }
+    }
+}

+ 47 - 0
app/admin/controller/distribution/DistributionGoods.php

@@ -0,0 +1,47 @@
+<?php
+namespace app\admin\controller\distribution;
+
+use app\admin\logic\distribution\DistributionGoodsLogic;
+use app\common\basics\AdminBase;
+use app\admin\logic\goods\CategoryLogic as MallCategoryLogic;
+use app\common\server\JsonServer;
+use app\shop\logic\goods\CategoryLogic as ShopCategoryLogic;
+
+/**
+ * 分销商品
+ * Class DistributionGoodsLogic
+ * @package app\admin\controller\distribution
+ */
+class DistributionGoods extends AdminBase
+{
+    /**
+     * @notes 分销商品列表页
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/2 17:30
+     */
+    public function index()
+    {
+        if ($this->request->isPost()) {
+            $params = $this->request->post();
+            $lists = DistributionGoodsLogic::lists($params);
+            return JsonServer::success('', $lists);
+        }
+        // 显示分销商品列表页
+        $cate_list = MallCategoryLogic::categoryTreeeTree();
+        return view('', ['cate_list' => $cate_list]);
+    }
+
+    /**
+     * @notes 查看商品佣金比例
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/2 17:57
+     */
+    public function detail()
+    {
+        $params = $this->request->get();
+        $detail = DistributionGoodsLogic::detail($params);
+        return view('', ['detail' => $detail]);
+    }
+}

+ 84 - 0
app/admin/controller/distribution/DistributionLevel.php

@@ -0,0 +1,84 @@
+<?php
+namespace app\admin\controller\distribution;
+
+use app\admin\logic\distribution\DistributionLevelLogic;
+use app\admin\validate\distribution\DistributionLevelValidate;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+
+class DistributionLevel extends AdminBase
+{
+    /**
+     * @notes 分销等级列表
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/1 11:01
+     */
+    public function index()
+    {
+        if ($this->request->isPost()) {
+            $result = DistributionLevelLogic::index();
+            return JsonServer::success('', $result);
+        }
+        return view();
+    }
+
+    /**
+     * @notes 添加分销等级
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/1 12:02
+     */
+    public function add()
+    {
+        if ($this->request->isPost()) {
+            $params = (new DistributionLevelValidate())->goCheck('add');
+            $result = DistributionLevelLogic::add($params);
+            if($result) {
+                return JsonServer::success('添加成功');
+            }
+            return JsonServer::error(DistributionLevelLogic::getError());
+        }
+        // 显示添加页面
+        return view();
+    }
+
+    /**
+     * @notes 编辑分销等级
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/1 15:39
+     */
+    public function edit()
+    {
+        if ($this->request->isPost()) {
+            $params = (new DistributionLevelValidate())->goCheck('edit');
+            $result = DistributionLevelLogic::edit($params);
+            if($result) {
+                return JsonServer::success('编辑成功');
+            }
+            return JsonServer::error(DistributionLevelLogic::getError());
+        }
+
+        $params = $this->request->get();
+        $detail = DistributionLevelLogic::detail($params);
+        $template = $detail['is_default'] ? 'edit_default' : 'edit';
+        return view($template, ['detail' => $detail]);
+    }
+
+    /**
+     * @notes 删除分销等级
+     * @return \think\response\Json
+     * @author Tab
+     * @date 2021/9/1 16:18
+     */
+    public function delete()
+    {
+        $params = $this->request->post();
+        $result = DistributionLevelLogic::delete($params);
+        if($result) {
+            return JsonServer::success('删除成功');
+        }
+        return JsonServer::error(DistributionLevelLogic::getError());
+    }
+}

+ 112 - 0
app/admin/controller/distribution/DistributionMember.php

@@ -0,0 +1,112 @@
+<?php
+namespace app\admin\controller\distribution;
+
+use app\admin\logic\distribution\DistributionLevelLogic;
+use app\admin\logic\distribution\DistributionMemberLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+
+/**
+ * 分销会员
+ * Class DistributionMember
+ * @package app\admin\controller\distribution
+ */
+class DistributionMember extends AdminBase
+{
+    /**
+     * @notes 分销会员列表
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/2 18:26
+     */
+    public function index()
+    {
+        if ($this->request->isPost()) {
+            $params = $this->request->post();
+            $result = DistributionMemberLogic::lists($params);
+            return JsonServer::success('', $result);
+        }
+        $levels = DistributionLevelLogic::getLevels();
+        return view('', ['levels' => $levels]);
+    }
+
+    /**
+     * @notes 开通分销会员
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/2 19:32
+     */
+    public function open()
+    {
+        if($this->request->isPost()) {
+            $params = $this->request->post();
+            $result = DistributionMemberLogic::open($params);
+            if($result) {
+                return JsonServer::success('开通成功');
+            }
+            return JsonServer::error(DistributionMemberLogic::getError());
+        }
+        $levels = DistributionLevelLogic::getLevels();
+        return view('', ['levels' => $levels]);
+    }
+
+    /**
+     * @notes 用户列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author Tab
+     * @date 2021/9/3 11:50
+     */
+    public function userLists()
+    {
+        if ($this->request->isPost()) {
+            $params = $this->request->post();
+            $lists = DistributionMemberLogic::getUserLists($params);
+            return JsonServer::success('', $lists);
+        }
+        return view();
+    }
+
+    /**
+     * @notes 分销会员等级调整
+     * @return \think\response\Json|\think\response\View
+     * @author Tab
+     * @date 2021/9/3 14:10
+     */
+    public function adjust()
+    {
+        if($this->request->isPost()) {
+            $params = $this->request->post();
+            $result = DistributionMemberLogic::adjust($params);
+            if($result) {
+                return JsonServer::success('调整成功');
+            }
+            return JsonServer::error(DistributionMemberLogic::getError());
+        }
+        $params = $this->request->get();
+        $user = DistributionMemberLogic::getUser($params);
+        $levels = DistributionLevelLogic::getLevels();
+        return view('', [
+            'user' => $user,
+            'levels' => $levels
+        ]);
+    }
+
+    /**
+     * @notes 冻结资格/恢复资格
+     * @return \think\response\Json
+     * @author Tab
+     * @date 2021/9/3 14:20
+     */
+    public function isFreeze()
+    {
+        $params = $this->request->post();
+        $result = DistributionMemberLogic::isFreeze($params);
+        if($result) {
+            return JsonServer::success('操作成功');
+        }
+        return JsonServer::error(DistributionMemberLogic::getError());
+    }
+}

+ 25 - 0
app/admin/controller/distribution/DistributionOrder.php

@@ -0,0 +1,25 @@
+<?php
+namespace app\admin\controller\distribution;
+
+use app\admin\logic\distribution\DistributionOrderLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+
+class DistributionOrder extends AdminBase
+{
+    /**
+     * @notes 分销订单列表
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/3 16:53
+     */
+    public function index()
+    {
+        if($this->request->isPost()) {
+            $params = $this->request->post();
+            $result = DistributionOrderLogic::lists($params);
+            return JsonServer::success('', $result);
+        }
+        return view();
+    }
+}

+ 49 - 0
app/admin/controller/distribution/DistributionSetting.php

@@ -0,0 +1,49 @@
+<?php
+namespace app\admin\controller\distribution;
+
+use app\admin\logic\distribution\DistributionSettingLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+
+class DistributionSetting extends AdminBase
+{
+    /**
+     * @notes 基础设置
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/1 9:14
+     */
+    public function index()
+    {
+        $config = DistributionSettingLogic::getConfig();
+        return view('', ['config' => $config]);
+    }
+
+    /**
+     * @notes 分销设置
+     * @return \think\response\Json
+     * @author Tab
+     * @date 2021/9/1 9:15
+     */
+    public function set()
+    {
+        $params = $this->request->post();
+        $result = DistributionSettingLogic::set($params);
+        if ($result) {
+            return JsonServer::success('设置成功');
+        }
+        return JsonServer::error(DistributionSettingLogic::getError());
+    }
+
+    /**
+     * @notes 结算设置
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/1 9:17
+     */
+    public function settlement()
+    {
+        $config = DistributionSettingLogic::getConfig();
+        return view('', ['config' => $config]);
+    }
+}

+ 154 - 0
app/admin/controller/distribution/Member.php

@@ -0,0 +1,154 @@
+<?php
+namespace app\admin\controller\distribution;
+
+use app\common\basics\AdminBase;
+use app\common\model\distribution\DistributionMemberApply;
+use app\common\server\JsonServer;
+use app\admin\logic\distribution\MemberLogic;
+use app\admin\validate\distribution\MemberValidate;
+use think\exception\ValidateException;
+
+class Member extends AdminBase
+{
+    public function index()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $type = $get['type'] ?? 'member';
+            if ($type == 'member') {
+                return JsonServer::success('获取成功', MemberLogic::memberLists($get));
+            }
+            return JsonServer::success('获取成功', MemberLogic::auditLists($get));
+        }
+
+        return view('index', ['status' => DistributionMemberApply::getApplyStatus(true)]);
+    }
+
+    public function addMember()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            try{
+                validate(MemberValidate::class)->scene('add')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+
+            $result = MemberLogic::addMember($post);
+            if($result === true) {
+               return JsonServer::success('添加成功');
+            }
+            return JsonServer::error($result);
+        }
+        return view();
+    }
+
+    public function info()
+    {
+        $get = $this->request->get();
+        $info = MemberLogic::getMemberInfo($get);
+        return view('info', ['detail'=>$info]);
+    }
+
+    public function fans()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            return JsonServer::success('', MemberLogic::getFansLists($get));
+        }
+
+        $user_id = $this->request->get('id');
+        return view('', ['user_id'=>$user_id]);
+    }
+
+    public function earningsDetail()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            return JsonServer::success('', MemberLogic::getEarningsDetail($get));
+        }
+
+        $user_id = $this->request->get('id');
+        return view('', ['user_id'=>$user_id]);
+    }
+
+    public function updateLeader()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            try{
+                validate(MemberValidate::class)->scene('updateLeader')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = MemberLogic::updateRelation($post);
+            if ($result === true){
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error($result);
+        }
+
+        $user_id = $this->request->get('id');
+        return view('',[
+            'first_leader' => MemberLogic::getLeaderInfo($user_id),
+            'user_id' => $user_id
+        ]);
+    }
+
+    public function freeze()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            try{
+                validate(MemberValidate::class)->scene('freeze')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = MemberLogic::freeze($post);
+            if($result === true) {
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error('操作失败');
+        }
+    }
+
+    // 删除分销资格
+    public function del()
+    {
+        if($this->request->isPost()) {
+            $post = $this->request->post();
+            $result = MemberLogic::del($post);
+            if($result === true) {
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error('操作失败');
+        }
+    }
+
+
+    /**
+     * 审核分销会员
+     */
+    public function audit()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            try{
+                validate(MemberValidate::class)->scene('audit')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            if ($post['type'] == 'pass') {
+                $res = MemberLogic::auditPass($post);
+            } else {
+                $res = MemberLogic::auditRefuse($post);
+            }
+
+            if ($res !== true) {
+                return JsonServer::error('操作失败');
+            }
+            return JsonServer::success('操作成功');
+        }
+    }
+
+}

+ 22 - 0
app/admin/controller/distribution/Record.php

@@ -0,0 +1,22 @@
+<?php
+namespace app\admin\controller\distribution;
+
+use app\admin\logic\distribution\RecordLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use app\common\utils\Time;
+
+class Record extends AdminBase
+{
+    public function lists()
+    {
+        if($this->request->isAjax()) {
+            $get = $this->request->get();
+            $data = RecordLogic::lists($get);
+            return JsonServer::success('', $data);
+        }
+        return view('', [
+            'time' => Time::getTime()
+        ]);
+    }
+}

+ 36 - 0
app/admin/controller/distribution/Setting.php

@@ -0,0 +1,36 @@
+<?php
+namespace app\admin\controller\distribution;
+
+use app\common\basics\AdminBase;
+use app\common\server\ConfigServer;
+use app\common\server\JsonServer;
+
+class Setting extends AdminBase
+{
+    /**
+     * 分销设置
+     */
+    public function setting()
+    {
+        if($this->request->isPost()) {
+            $post = $this->request->post();
+            ConfigServer::set('distribution', 'is_open', $post['is_open']);
+            ConfigServer::set('distribution', 'member_apply', $post['member_apply']);
+            if(isset($post['image'])) {
+                // 图片链接去除域名再入库
+                $domain = $this->request->domain();
+                $post['image'] = str_replace($domain, '', $post['image']);
+                ConfigServer::set('distribution', 'image', $post['image']);
+            }else{
+                ConfigServer::set('distribution', 'image', '');
+            }
+            return JsonServer::success('设置成功');
+        }
+        $config = [
+            'is_open' => ConfigServer::get('distribution', 'is_open', 1),
+            'member_apply' => ConfigServer::get('distribution', 'member_apply', 1),
+            'image' => ConfigServer::get('distribution', 'image', ''),
+        ];
+        return view('', ['config' => $config]);
+    }
+}

+ 39 - 0
app/admin/controller/finance/Finance.php

@@ -0,0 +1,39 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\finance;
+
+use app\common\basics\AdminBase;
+use app\admin\logic\finance\FinanceLogic;
+use think\facade\View;
+
+/**
+ * 财务中心
+ * Class Finance
+ * @package app\admin\controller\finance
+ */
+class Finance extends AdminBase
+{
+    public function center()
+    {
+
+        View::assign('shop', FinanceLogic::shop());
+        return view();
+    }
+}

+ 65 - 0
app/admin/controller/finance/Integral.php

@@ -0,0 +1,65 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\finance;
+
+
+use app\admin\logic\finance\IntegralLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+
+class Integral extends AdminBase
+{
+    /**
+     * @notes 积分明细
+     * @return \think\response\Json|\think\response\View
+     * @author ljj
+     * @date 2022/2/22 6:00 下午
+     */
+    public function integral()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $data = IntegralLogic::integral($get);
+            return JsonServer::success('', $data, 1);
+        }
+
+        return view();
+    }
+
+
+    /**
+     * @notes 导出积分明细Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function export()
+    {
+        $params = $this->request->get();
+        $result = IntegralLogic::integral($params, true);
+        if(false === $result) {
+            return JsonServer::error(IntegralLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+}

+ 270 - 0
app/admin/controller/finance/Shop.php

@@ -0,0 +1,270 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\finance;
+
+use app\admin\logic\finance\ShopSettlementLogic;
+use app\admin\logic\finance\ShopWithdrawalLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+
+use think\facade\View;
+
+/**
+ * 财务-商家相关
+ * Class Shop
+ * @package app\admin\controller\finance
+ */
+class Shop extends AdminBase
+{
+    /**
+     * @Notes: 商家提现列表
+     * @Author: 张无忌
+     */
+    public function withdrawal()
+    {
+        if($this->request->isAjax()){
+            $get= $this->request->get();
+            $lists = ShopWithdrawalLogic::lists($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+
+        View::assign('summary', ShopWithdrawalLogic::summary());
+        View::assign('statistics', ShopWithdrawalLogic::statistics());
+        return view();
+    }
+
+    /**
+     * @Notes: 商家提现详细
+     * @Author: 张无忌
+     * @return \think\response\View
+     */
+    public function withdrawalDetail()
+    {
+        $id = $this->request->get('id');
+        View::assign('detail', ShopWithdrawalLogic::detail($id));
+        return view();
+    }
+
+    /**
+     * @Notes: 商家提现统计
+     * @Author: 张无忌
+     */
+    public function withdrawalStatistics()
+    {
+        if ($this->request->isAjax()) {
+            $statistics = ShopWithdrawalLogic::statistics();
+            return JsonServer::success('获取成功', $statistics);
+        }
+
+        return JsonServer::error('请求异常');
+    }
+
+    /**
+     * @Notes: 审核商家提现
+     * @Author: 张无忌
+     */
+    public function withdrawalExamine()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $res = ShopWithdrawalLogic::examine($post);
+            if ($res === false) {
+                $error = ShopWithdrawalLogic::getError() ?: '审核失败';
+                return JsonServer::error($error);
+            }
+
+            return JsonServer::success('审核成功');
+        }
+
+        return view();
+    }
+
+    /**
+     * @Notes: 商家提现转账
+     * @Author: 张无忌
+     */
+    public function withdrawalTransfer()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $res = ShopWithdrawalLogic::transfer($post);
+            if ($res === false) {
+                $error = ShopWithdrawalLogic::getError() ?: '审核失败';
+                return JsonServer::error($error);
+            }
+
+            return JsonServer::success('审核成功');
+        }
+
+        $id = $this->request->get('id');
+        View::assign('detail', ShopWithdrawalLogic::detail($id));
+        return view();
+    }
+    
+    /**
+     * @notes 在线转账
+     * @return \think\response\Json|void
+     * @author lbzy
+     * @datetime 2023-06-07 09:48:22
+     */
+    function WithdrawalTransferOnline()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $res = ShopWithdrawalLogic::transfer_online($post);
+            if ($res === false) {
+                $error = ShopWithdrawalLogic::getError() ? : '在线转账失败';
+                return JsonServer::error($error);
+            }
+            
+            return JsonServer::success(ShopWithdrawalLogic::getError() ? : '在线转账成功');
+        }
+    }
+
+
+    /**
+     * @Notes: 商家结算列表
+     * @Author: 张无忌
+     */
+    public function settlement()
+    {
+        if($this->request->isAjax()){
+            $get= $this->request->get();
+            $lists = ShopSettlementLogic::lists($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+
+        $statistics = ShopSettlementLogic::statistics();
+        View::assign('statistics', $statistics);
+        return view();
+    }
+
+    /**
+     * @Notes: 商家结算记录
+     * @Author: 张无忌
+     */
+    public function settlementRecord()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = ShopSettlementLogic::record($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+
+        $shop_id = $this->request->get('shop_id');
+        $statistics = ShopSettlementLogic::statistics($shop_id);
+        View::assign('shop_id', $shop_id);
+        View::assign('statistics', $statistics);
+        return view();
+    }
+
+    /**
+     * @Notes: 商家结算详细记录
+     * @Author: 张无忌
+     */
+    public function settlementDetail()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = ShopSettlementLogic::detail($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+
+        $settle_id = $this->request->get('settle_id');
+        View::assign('settle_id', $settle_id);
+        return view();
+    }
+
+
+    /**
+     * @Notes: 账户明细列表
+     * @Author: 张无忌
+     */
+    public function account()
+    {
+        if($this->request->isAjax()){
+            $get= $this->request->get();
+            $lists = ShopWithdrawalLogic::account($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+
+        return view();
+    }
+
+
+    /**
+     * @notes 导出商家提现Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function withdrawalExport()
+    {
+        $params = $this->request->get();
+        $result = ShopWithdrawalLogic::lists($params, true);
+        if(false === $result) {
+            return JsonServer::error(ShopWithdrawalLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+
+    /**
+     * @notes 导出商家结算Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function settlementExport()
+    {
+        $params = $this->request->get();
+        $result = ShopSettlementLogic::lists($params, true);
+        if(false === $result) {
+            return JsonServer::error(ShopSettlementLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+
+
+    /**
+     * @notes 导出商家账户明细Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function accountExport()
+    {
+        $params = $this->request->get();
+        $result = ShopWithdrawalLogic::account($params, true);
+        if(false === $result) {
+            return JsonServer::error(ShopWithdrawalLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+
+}

+ 476 - 0
app/admin/controller/finance/User.php

@@ -0,0 +1,476 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\finance;
+
+use app\common\basics\AdminBase;
+use app\common\model\AccountLog;
+use app\common\server\JsonServer;
+use app\admin\logic\finance\WithdrawLogic;
+use app\common\model\order\Order as OrderModel;
+use app\common\model\Client_;
+use app\common\enum\PayEnum;
+
+/**
+ * 财务-会员相关
+ * Class User
+ * @package app\admin\controller\finance
+ */
+class User extends AdminBase
+{
+    /**
+     * @notes 会员佣金提现列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/13 7:01 下午
+     */
+    public function withdrawal()
+    {
+
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $data = WithdrawLogic::lists($get);
+            return JsonServer::success('', $data, 1);
+        }
+        $today = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", time()))),
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", time())) + 86399)
+        ];
+
+        $yesterday = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-1 day")))),
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-1 day"))) + 86399)
+        ];
+
+
+        $days_ago7 = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-7 day")))),
+            date('Y-m-d 23:59:59', time())
+        ];
+
+        $days_ago30 = [
+            date('Y-m-d 00:00:00', strtotime("-30 day")),
+            date('Y-m-d 23:59:59', time())
+        ];
+        $summary = WithdrawLogic::summary();
+        return view('', [
+            'today' => $today,
+            'yesterday' => $yesterday,
+            'days_ago7' => $days_ago7,
+            'days_ago30' => $days_ago30,
+            'summary' => $summary
+        ]);
+    }
+
+    /**
+     * @notes 会员佣金明细列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/13 7:01 下午
+     */
+    public function commission()
+    {
+
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $data = WithdrawLogic::commission($get);
+            return JsonServer::success('', $data, 1);
+        }
+        $today = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", time()))),
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", time())) + 86399)
+        ];
+
+        $yesterday = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-1 day")))),
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-1 day"))) + 86399)
+        ];
+
+
+        $days_ago7 = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-7 day")))),
+            date('Y-m-d 23:59:59', time())
+        ];
+
+        $days_ago30 = [
+            date('Y-m-d 00:00:00', strtotime("-30 day")),
+            date('Y-m-d 23:59:59', time())
+        ];
+        return view('', [
+            'today' => $today,
+            'yesterday' => $yesterday,
+            'days_ago7' => $days_ago7,
+            'days_ago30' => $days_ago30,
+            'source_type' => AccountLog::getEarningsChange()
+        ]);
+    }
+
+    /**
+     * @notes 充值明细列表
+     * @return \think\response\Json|\think\response\View
+     * @author suny
+     * @date 2021/7/13 7:01 下午
+     */
+    public function recharge()
+    {
+
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $data = WithdrawLogic::recharge($get);
+            return JsonServer::success('', $data, 1);
+        }
+        // 订单状态
+        $order_status = OrderModel::getOrderStatus(true);
+        // 订单类型
+        $order_type = OrderModel::getOrderType(true);
+        // 订单来源
+        $order_source = Client_::getClient(true);
+        unset($order_source[2]);
+        // 支付方式
+        $pay_way = PayEnum::getPayWay(true);
+        unset($pay_way[3], $pay_way[4]);
+        // 配送方式
+        $today = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", time()))),
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", time())) + 86399)
+        ];
+
+        $yesterday = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-1 day")))),
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-1 day"))) + 86399)
+        ];
+
+
+        $days_ago7 = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-7 day")))),
+            date('Y-m-d 23:59:59', time())
+        ];
+
+        $days_ago30 = [
+            date('Y-m-d 00:00:00', strtotime("-30 day")),
+            date('Y-m-d 23:59:59', time())
+        ];
+        return view('', [
+            'order_status' => $order_status,
+            'order_type' => $order_type,
+            'order_source' => $order_source,
+            'pay_way' => $pay_way,
+            'today' => $today,
+            'yesterday' => $yesterday,
+            'days_ago7' => $days_ago7,
+            'days_ago30' => $days_ago30,
+        ]);
+    }
+
+
+    /**
+     * @notes 账户明细列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/13 7:02 下午
+     */
+    public function account()
+    {
+
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $data = WithdrawLogic::account($get);
+            return JsonServer::success('', $data, 1);
+        }
+        $today = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", time()))),
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", time())) + 86399)
+        ];
+
+        $yesterday = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-1 day")))),
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-1 day"))) + 86399)
+        ];
+
+
+        $days_ago7 = [
+            date('Y-m-d H:i:s', strtotime(date("Y-m-d", strtotime("-7 day")))),
+            date('Y-m-d 23:59:59', time())
+        ];
+
+        $days_ago30 = [
+            date('Y-m-d 00:00:00', strtotime("-30 day")),
+            date('Y-m-d 23:59:59', time())
+        ];
+        return view('', [
+            'today' => $today,
+            'yesterday' => $yesterday,
+            'days_ago7' => $days_ago7,
+            'days_ago30' => $days_ago30,
+        ]);
+    }
+
+    /**
+     * @notes 会员佣金提现详情
+     * @return \think\response\View
+     * @author suny
+     * @date 2021/7/13 7:02 下午
+     */
+    public function withdraw_detail()
+    {
+
+        $id = $this->request->get('id', '', 'intval');
+        $detail = WithdrawLogic::detail($id);
+        return view('detail', [
+            'detail' => $detail
+        ]);
+    }
+
+    /**
+     * @notes 显示提现审核界面
+     * @return \think\response\View
+     * @author suny
+     * @date 2021/7/13 7:02 下午
+     */
+    public function withdraw_review()
+    {
+
+        $id = $this->request->get('id', '', 'intval');
+        return view('review', [
+            'id' => $id
+        ]);
+    }
+
+    /**
+     * @notes 审核通过
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @author suny
+     * @date 2021/7/13 7:02 下午
+     */
+    public function confirm()
+    {
+
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $result = WithdrawLogic::confirm($post);
+            if ($result['code']) {
+                return JsonServer::success($result['msg']);
+            } else {
+                return JsonServer::error($result['msg']);
+            }
+        }
+    }
+
+    /**
+     * @notes 审核拒绝
+     * @return \think\response\Json
+     * @throws \think\exception\PDOException
+     * @author suny
+     * @date 2021/7/13 7:02 下午
+     */
+    public function refuse()
+    {
+
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            WithdrawLogic::refuse($post);
+            return JsonServer::success('已拒绝提现');
+        }
+    }
+
+    /**
+     * @notes 显示提现转账界面
+     * @return \think\response\View
+     * @author suny
+     * @date 2021/7/13 7:02 下午
+     */
+    public function transfer()
+    {
+
+        $id = $this->request->get('id', '', 'intval');
+        return view('', [
+            'id' => $id
+        ]);
+    }
+
+    /**
+     * @notes 转账失败
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @author suny
+     * @date 2021/7/13 7:02 下午
+     */
+    public function transferFail()
+    {
+
+        $post = $this->request->post();
+        $result = WithdrawLogic::transferFail($post);
+        if ($result['code']) {
+            return JsonServer::success($result['msg']);
+        } else {
+            return JsonServer::error($result['msg']);
+        }
+    }
+
+    /**
+     * @notes 转账成功
+     * @return \think\response\Json
+     * @author suny
+     * @date 2021/7/13 7:02 下午
+     */
+    public function transferSuccess()
+    {
+
+        $post = $this->request->post();
+        $result = WithdrawLogic::transferSuccess($post);
+        if ($result['code']) {
+            return JsonServer::success($result['msg']);
+        } else {
+            return JsonServer::error($result['msg']);
+        }
+    }
+
+    /**
+     * @notes 提现结果查询
+     * @return \think\response\Json
+     * @author suny
+     * @date 2021/7/13 7:02 下午
+     */
+    public function search()
+    {
+
+        $id = $this->request->post('id', '', 'intval');
+        $result = WithdrawLogic::search($id);
+        if ($result['code']) {
+            return JsonServer::success($result['msg']);
+        } else {
+            return JsonServer::error($result['msg']);
+        }
+    }
+
+    /**
+     * @notes 提现失败
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @author suny
+     * @date 2021/7/13 7:03 下午
+     */
+    public function withdrawFailed()
+    {
+
+        $id = $this->request->post('id', '', 'intval');
+        WithdrawLogic::withdrawFailed($id);
+        return JsonServer::success('提现失败已回退佣金');
+    }
+
+
+    /**
+     * @notes 导出充值明细Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function rechargeExport()
+    {
+        $params = $this->request->get();
+        $result = WithdrawLogic::recharge($params, true);
+        if(false === $result) {
+            return JsonServer::error(WithdrawLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+
+
+    /**
+     * @notes 导出账户明细Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function accountExport()
+    {
+        $params = $this->request->get();
+        $result = WithdrawLogic::account($params, true);
+        if(false === $result) {
+            return JsonServer::error(WithdrawLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+
+
+    /**
+     * @notes 导出佣金明细Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function commissionExport()
+    {
+        $params = $this->request->get();
+        $result = WithdrawLogic::commission($params, true);
+        if(false === $result) {
+            return JsonServer::error(WithdrawLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+
+
+
+    /**
+     * @notes 导出佣金提现Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function withdrawalExport()
+    {
+        $params = $this->request->get();
+        $result = WithdrawLogic::lists($params, true);
+        if(false === $result) {
+            return JsonServer::error(WithdrawLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+}

+ 118 - 0
app/admin/controller/integral/IntegralGoods.php

@@ -0,0 +1,118 @@
+<?php
+
+namespace app\admin\controller\integral;
+
+use app\admin\logic\integral\IntegralGoodsLogic;
+use app\admin\validate\integral\IntegralGoodsValidate;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+
+/**
+ * 积分商城-积分商品
+ * Class IntegralGoods
+ * @package app\admin\controller\integral
+ */
+class IntegralGoods extends AdminBase
+{
+
+    /**
+     * @notes 商品列表
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2022/2/25 18:28
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = IntegralGoodsLogic::getLists($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+        return view();
+    }
+
+
+    /**
+     * @notes 添加商品
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2022/2/25 18:27
+     */
+    public function add()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['status'] = isset($post['status']) && $post['status'] == 'on' ? 1 : 0;
+            (new IntegralGoodsValidate())->goCheck('add', $post);
+            $res = IntegralGoodsLogic::add($post);
+            if (false === $res) {
+                $error = IntegralGoodsLogic::getError() ?: '操作失败';
+                return JsonServer::error($error);
+            }
+            return JsonServer::success('操作成功');
+        }
+        return view();
+    }
+
+
+    /**
+     * @notes 编辑积分商品
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2022/3/1 15:40
+     */
+    public function edit()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['status'] = isset($post['status']) && $post['status'] == 'on' ? 1 : 0;
+            (new IntegralGoodsValidate())->goCheck('edit', $post);
+            $res = IntegralGoodsLogic::edit($post);
+            if (false === $res) {
+                $error = IntegralGoodsLogic::getError() ?: '操作失败';
+                return JsonServer::error($error);
+            }
+            return JsonServer::success('操作成功');
+        }
+        $id = $this->request->get('id');
+        return view('', [
+            'detail'   => IntegralGoodsLogic::detail($id),
+        ]);
+    }
+
+
+    /**
+     * @notes 删除商品
+     * @return \think\response\Json|void
+     * @author 段誉
+     * @date 2022/2/25 18:26
+     */
+    public function del()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            (new IntegralGoodsValidate())->goCheck('del');
+            IntegralGoodsLogic::del($post);
+            return JsonServer::success('操作成功');
+        }
+        return JsonServer::error('操作失败');
+    }
+
+
+    /**
+     * @notes 切换状态
+     * @return \think\response\Json|void
+     * @author 段誉
+     * @date 2022/2/25 18:26
+     */
+    public function switchStatus()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            IntegralGoodsLogic::switchStatus($post);
+            return JsonServer::success('操作成功');
+        }
+        return JsonServer::error('操作失败');
+    }
+
+}

+ 161 - 0
app/admin/controller/integral/IntegralOrder.php

@@ -0,0 +1,161 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\integral;
+
+
+use app\admin\logic\integral\IntegralOrderLogic;
+use app\admin\validate\integral\IntegralOrderValidate;
+use app\common\basics\AdminBase;
+use app\common\enum\IntegralGoodsEnum;
+use app\common\enum\IntegralOrderEnum;
+use app\common\server\JsonServer;
+
+class IntegralOrder extends AdminBase
+{
+    /**
+     * @notes 兑换订单列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author ljj
+     * @date 2022/3/3 10:38 上午
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            return JsonServer::success('', IntegralOrderLogic::lists($get));
+        }
+
+        // 订单状态
+        $order_status = IntegralOrderEnum::getOrderStatus(true);
+        // 兑换类型
+        $type = IntegralGoodsEnum::getTypeDesc(true);
+
+        return view('', [
+            'order_status' => $order_status,
+            'type' => $type,
+        ]);
+    }
+
+    /**
+     * @notes 兑换订单详情
+     * @return \think\response\View
+     * @author ljj
+     * @date 2022/3/3 11:10 上午
+     */
+    public function detail()
+    {
+        $id = $this->request->get('id');
+        $detail = IntegralOrderLogic::detail($id);
+        return view('', [
+            'detail' => $detail,
+        ]);
+    }
+
+    /**
+     * @notes 发货详情
+     * @return \think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author ljj
+     * @date 2022/3/3 11:48 上午
+     */
+    public function delivery()
+    {
+        $id = $this->request->get('id');
+        $detail = IntegralOrderLogic::deliveryDetail($id);
+        $express = IntegralOrderLogic::express();
+        return view('', [
+            'detail' => $detail,
+            'express' => $express
+        ]);
+    }
+
+    /**
+     * @notes 发货操作
+     * @return \think\response\Json|void
+     * @author ljj
+     * @date 2022/3/3 2:53 下午
+     */
+    public function deliveryHandle()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            (new IntegralOrderValidate())->goCheck('deliveryHandle', $post);
+            $result = IntegralOrderLogic::deliveryHandle($post,$this->adminId);
+            if (true !== $result) {
+                return JsonServer::error($result);
+            }
+            return JsonServer::success('发货成功');
+        }
+    }
+
+    /**
+     * @notes 物流信息
+     * @return \think\response\View
+     * @author ljj
+     * @date 2022/3/3 3:32 下午
+     */
+    public function express()
+    {
+        $id = $this->request->get('id');
+        $detail = IntegralOrderLogic::detail($id);
+        $detail['shipping'] = IntegralOrderLogic::shippingInfo($detail['id']);
+        return view('', [
+            'detail' => $detail
+        ]);
+    }
+
+    /**
+     * @notes 确认收货
+     * @return \think\response\Json|void
+     * @author ljj
+     * @date 2022/3/3 3:39 下午
+     */
+    public function confirm()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            (new IntegralOrderValidate())->goCheck('confirm', $post);
+            IntegralOrderLogic::confirm($post['id'],$this->adminId);
+            return JsonServer::success('确认成功');
+        }
+    }
+
+    /**
+     * @notes 取消订单
+     * @return \think\response\Json|void
+     * @author 段誉
+     * @date 2022/3/3 18:00
+     */
+    public function cancel()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            (new IntegralOrderValidate())->goCheck('cancel', $post);
+            IntegralOrderLogic::cancel($post['id']);
+            return JsonServer::success('取消成功');
+        }
+    }
+
+}

+ 159 - 0
app/admin/controller/kefu/Kefu.php

@@ -0,0 +1,159 @@
+<?php
+
+namespace app\admin\controller\kefu;
+
+use app\admin\logic\kefu\KefuLogic;
+use app\admin\validate\kefu\KefuValidate;
+use app\admin\validate\kefu\LoginValidate;
+use app\common\basics\AdminBase;
+use app\common\model\Role;
+use app\common\server\JsonServer;
+use think\facade\Request;
+
+/**
+ * 客服管理控制器
+ * Class Kefu
+ * @package app\admin\controller\kefu
+ */
+class Kefu extends AdminBase
+{
+
+    /**
+     * @notes 客服列表
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2021/11/26 18:40
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = KefuLogic::getLists($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+        return view();
+    }
+
+    /**
+     * @notes 添加客服
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2021/11/26 18:04
+     */
+    public function add()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['disable'] = isset($post['disable']) && $post['disable'] == 'on' ? 0 : 1;
+            (new KefuValidate())->goCheck('add', $post);
+            $res = KefuLogic::add($post);
+            if (false === $res) {
+                $error = KefuLogic::getError() ?: '操作失败';
+                return JsonServer::error($error);
+            }
+            return JsonServer::success('操作成功');
+        }
+        return view();
+    }
+
+
+    /**
+     * @notes 编辑客服
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2021/11/27 10:45
+     */
+    public function edit()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['disable'] = isset($post['disable']) && $post['disable'] == 'on' ? 0 : 1;
+            (new KefuValidate())->goCheck('edit', $post);
+            $res = KefuLogic::edit($post);
+            if (false === $res) {
+                $error = KefuLogic::getError() ?: '操作失败';
+                return JsonServer::error($error);
+            }
+            return JsonServer::success('操作成功');
+        }
+
+        $id = $this->request->get('id');
+        return view('', [
+            'detail'   => KefuLogic::detail($id),
+        ]);
+    }
+
+
+
+    /**
+     * @notes 删除客服
+     * @return \think\response\Json|void
+     * @author 段誉
+     * @date 2021/11/26 18:53
+     */
+    public function del()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            (new KefuValidate())->goCheck('del');
+            KefuLogic::del($post);
+            return JsonServer::success('操作成功');
+        }
+    }
+
+
+    /**
+     * @notes 管理员列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2021/11/26 18:01
+     */
+    public function adminLists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            return JsonServer::success('', KefuLogic::getAdminLists($get));
+        }
+        return view('', ['role_lists' => (new Role())->getRoleLists()]);
+    }
+
+
+    /**
+     * @notes 设置状态
+     * @return \think\response\Json|void
+     * @author 段誉
+     * @date 2021/11/26 18:40
+     */
+    public function status()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            KefuLogic::setStatus($post);
+            return JsonServer::success('操作成功');
+        }
+    }
+
+
+    /**
+     * @notes 登录工作台
+     * @return \think\response\Json
+     * @author 段誉
+     * @date 2021/12/15 19:57
+     */
+    public function login()
+    {
+        if ($this->request->isAjax()) {
+            $id = $this->request->post('id/d');
+            (new LoginValidate())->goCheck();
+            $res = KefuLogic::login($id);
+            if (false === $res) {
+                return JsonServer::error(KefuLogic::getError() ?: '系统错误');
+            }
+            return JsonServer::success('', ['url' => $res]);
+        }
+    }
+
+}

+ 110 - 0
app/admin/controller/kefu/KefuLang.php

@@ -0,0 +1,110 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop100%开源免费商用商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | 商业版本务必购买商业授权,以免引起法律纠纷
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshopTeam
+// +----------------------------------------------------------------------
+namespace app\admin\controller\kefu;
+use app\admin\logic\kefu\KefuLangLogic;
+use app\admin\logic\kefu\KefuLogic;
+use app\admin\validate\kefu\KefuLangValidate;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+
+/**
+ * 客服术语
+ * Class KefuLang
+ * @package app\admin\controller\kefu
+ */
+class KefuLang extends AdminBase
+{
+    /**
+     * @notes 列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DbException
+     * @author cjhao
+     * @date 2021/11/29 15:20
+     */
+    public function lists()
+    {
+        if($this->request->isAjax()){
+            $page = $this->request->get('page', 1);
+            $limit = $this->request->get('limit', 10);
+            $lists = KefuLangLogic::lists($limit,$page);
+            return JsonServer::success('获取成功', $lists);
+        }
+        return view();
+    }
+
+
+    /**
+     * @notes 添加话术
+     * @return \think\response\Json|\think\response\View
+     * @author cjhao
+     * @date 2021/11/29 15:59
+     */
+    public function add()
+    {
+        if($this->request->isAjax()){
+            $post= (new KefuLangValidate())->goCheck('add');
+            $result = KefuLangLogic::add($post);
+            if($result){
+                return JsonServer::success('新增成功', []);
+            }
+            return JsonServer::error('新增失败');
+        }
+        return view();
+
+    }
+
+    /**
+     * @notes 编辑话术
+     * @return \think\response\Json|\think\response\View
+     * @author cjhao
+     * @date 2021/11/29 15:59
+     */
+    public function edit()
+    {
+        if($this->request->isAjax()){
+            $post= (new KefuLangValidate())->goCheck();
+            $result = KefuLangLogic::edit($post);
+            if($result){
+                return JsonServer::success('修改成功', []);
+            }
+            return JsonServer::error('修改失败');
+        }
+        $id = $this->request->get('id');
+        return view('', [
+            'detail'   => KefuLangLogic::detail($id),
+        ]);
+
+    }
+
+    /**
+     * @notes 删除话术
+     * @return \think\response\Json
+     * @author cjhao
+     * @date 2021/11/29 16:35
+     */
+    public function del()
+    {
+        $post= (new KefuLangValidate())->goCheck('del');
+        $result = KefuLangLogic::del($post['id']);
+        if($result){
+            return JsonServer::success('删除成功', []);
+        }
+        return JsonServer::error('删除失败');
+    }
+}

+ 118 - 0
app/admin/controller/live/LiveGoods.php

@@ -0,0 +1,118 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop100%开源免费商用商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | 商业版本务必购买商业授权,以免引起法律纠纷
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshopTeam
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\live;
+
+
+use app\admin\logic\live\LiveRoomLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use app\admin\logic\live\LiveGoodsLogic;
+use app\admin\validate\live\LiveGoodsValidate;
+
+
+/**
+ * 直播商品
+ * Class LiveGoods
+ * @package app\admin\controller\live
+ */
+class LiveGoods extends AdminBase
+{
+
+    /**
+     * @notes 直播间列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2023/2/16 10:38
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = LiveGoodsLogic::lists($get);
+            return JsonServer::success('', $lists);
+        }
+        return view('', [
+            'shop' => LiveRoomLogic::shopLists()
+        ]);
+    }
+
+
+    /**
+     * @notes 添加直播商品
+     * @return \think\response\Json|\think\response\View
+     * @throws \GuzzleHttp\Exception\GuzzleException
+     * @author 段誉
+     * @date 2023/2/16 10:38
+     */
+    public function audit()
+    {
+        if ($this->request->isAjax()) {
+            $params = (new LiveGoodsValidate())->goCheck('audit');
+            $result = LiveGoodsLogic::audit($params);
+            if ($result !== true) {
+                return JsonServer::error(LiveGoodsLogic::getError());
+            }
+            return JsonServer::success('操作成功');
+        }
+        $id = $this->request->get('id');
+        return view('', [
+            'detail' => LiveGoodsLogic::detail($id),
+        ]);
+    }
+
+
+
+    /**
+     * @notes 直播商品详情
+     * @return \think\response\View
+     * @author 段誉
+     * @date 2023/2/16 16:40
+     */
+    public function detail()
+    {
+        $params = (new LiveGoodsValidate())->goCheck('detail');
+        return view('', [
+            'detail' => LiveGoodsLogic::detail($params),
+        ]);
+    }
+
+
+    /**
+     * @notes 删除直播商品
+     * @return \think\response\Json|void
+     * @author 段誉
+     * @date 2023/2/17 10:20
+     */
+    public function del()
+    {
+        if ($this->request->isAjax()) {
+            $params = (new LiveGoodsValidate())->goCheck('del');
+            $result = LiveGoodsLogic::del($params);
+            if ($result !== true) {
+                return JsonServer::error(LiveGoodsLogic::getError());
+            }
+            return JsonServer::success('操作成功');
+        }
+    }
+
+}

+ 123 - 0
app/admin/controller/live/LiveRoom.php

@@ -0,0 +1,123 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop100%开源免费商用商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | 商业版本务必购买商业授权,以免引起法律纠纷
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshopTeam
+// +----------------------------------------------------------------------
+
+namespace app\admin\controller\live;
+
+
+use app\common\basics\AdminBase;
+use app\common\enum\LiveRoomEnum;
+use app\common\server\JsonServer;
+use app\admin\logic\live\LiveRoomLogic;
+use app\admin\validate\live\LiveRoomValidate;
+
+
+/**
+ * 直播间
+ * Class LiveRoom
+ * @package app\admin\controller\live
+ */
+class LiveRoom extends AdminBase
+{
+
+    /**
+     * @notes 直播间列表
+     * @return \think\response\Json|\think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2023/2/16 10:38
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = LiveRoomLogic::lists($get);
+            return JsonServer::success('', $lists);
+        }
+        return view('', [
+            'live_status' => LiveRoomEnum::getLiveStatusDesc(),
+            'shop' => LiveRoomLogic::shopLists(),
+        ]);
+    }
+
+
+    /**
+     * @notes 编辑直播间
+     * @return \think\response\Json|\think\response\View
+     * @throws \GuzzleHttp\Exception\GuzzleException
+     * @author 段誉
+     * @date 2023/2/16 10:38
+     */
+    public function audit()
+    {
+        if ($this->request->isAjax()) {
+            $params = (new LiveRoomValidate())->goCheck('audit');
+            $result = LiveRoomLogic::audit($params);
+            if ($result !== true) {
+                return JsonServer::error(LiveRoomLogic::getError());
+            }
+            return JsonServer::success('操作成功');
+        }
+        $id = $this->request->get('id');
+        return view('', [
+            'detail' => LiveRoomLogic::detail($id),
+        ]);
+    }
+
+
+    /**
+     * @notes 直播间详情
+     * @return \think\response\View
+     * @author 段誉
+     * @date 2023/2/16 16:40
+     */
+    public function detail()
+    {
+        $id = $this->request->get('id');
+        return view('', [
+            'detail' => LiveRoomLogic::detail($id),
+        ]);
+    }
+
+
+    /**
+     * @notes 推荐值设置
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2023/2/16 16:56
+     */
+    public function recommend()
+    {
+        if ($this->request->isAjax()) {
+            $params = (new LiveRoomValidate())->goCheck('recommend');
+            $result = LiveRoomLogic::recommend($params);
+            if ($result) {
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error(LiveRoomLogic::getError());
+        }
+        $id = $this->request->get('id');
+        return view('', [
+            'detail' => LiveRoomLogic::detail($id),
+        ]);
+    }
+
+
+}

+ 89 - 0
app/admin/controller/order/Invoice.php

@@ -0,0 +1,89 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\controller\order;
+
+use app\common\basics\AdminBase;
+use app\common\model\order\Order;
+use app\common\server\JsonServer;
+use app\admin\logic\order\InvoiceLogic;
+
+
+/**
+ * 发票管理
+ * Class Invoice
+ * @package app\shop\controller\order
+ */
+class Invoice extends AdminBase
+{
+
+    /**
+     * @notes 发票列表
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2022/4/12 17:34
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            return JsonServer::success('', InvoiceLogic::getInvoiceLists($get));
+        }
+        return view('', [
+            'order_status' => order::getOrderStatus(true)
+        ]);
+    }
+
+
+    /**
+     * @notes 开票
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2022/4/12 19:00
+     */
+    public function detail()
+    {
+        $id = $this->request->get('id/d');
+        return view('detail', [
+            'detail' => InvoiceLogic::detail($id)
+        ]);
+    }
+
+
+    /**
+     * @notes 导出Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function export()
+    {
+        $params = $this->request->get();
+        $result = InvoiceLogic::getInvoiceLists($params, true);
+        if(false === $result) {
+            return JsonServer::error(InvoiceLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+
+}

+ 130 - 0
app/admin/controller/order/Order.php

@@ -0,0 +1,130 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\controller\order;
+
+use app\common\basics\AdminBase;
+use app\common\model\order\order as OrderModel;
+use app\common\server\JsonServer;
+use app\admin\logic\order\OrderLogic;
+use app\common\model\Client_;
+use app\common\enum\PayEnum;
+use app\common\model\order\OrderLog;
+
+
+/**
+ * Class order
+ * @package app\admin\controller\order
+ */
+class Order extends AdminBase
+{
+
+    /**
+     * @notes 订单列表
+     * @return \think\response\Json|\think\response\View
+     * @author suny
+     * @date 2021/7/13 7:07 下午
+     */
+    public function lists()
+    {
+        $data = OrderLogic::statistics(input());
+        
+        // 订单状态
+        $order_status = OrderModel::getOrderStatus();
+        // 拼装数量统计
+        $order_status   = OrderLogic::getStat($order_status);
+        $all            = OrderLogic::getAll();
+        
+        if ($this->request->isAjax()) {
+            $data['statistics'] = [
+                'all'           => $all,
+                'order_status'  => $order_status,
+            ];
+            return JsonServer::success('', $data);
+        }
+        
+        return view('', [
+            'all'           => $all,
+            'statistics'    => $data,
+            'order_status'  => $order_status,
+            'order_type'    => OrderModel::getOrderType(true),
+            'order_source'  => Client_::getClient(),
+            'pay_way'       => PayEnum::getPayWay(),
+            'delivery_type' => OrderModel::getDeliveryType(true),
+        ]);
+    }
+
+    /**
+     * @notes 订单详情
+     * @return \think\response\View
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @author suny
+     * @date 2021/7/13 7:07 下午
+     */
+    public function detail()
+    {
+
+        $id = $this->request->get('id');
+        $detail = OrderLogic::getDetail($id);
+        $order_log = OrderLog::getOrderLog($id);
+        return view('', [
+            'detail' => $detail,
+            'logs' => $order_log
+        ]);
+    }
+
+    /**
+     * @notes 物流信息
+     * @return \think\response\View
+     * @author suny
+     * @date 2021/7/13 7:07 下午
+     */
+    public function express()
+    {
+        $id = $this->request->get('id');
+        $detail = OrderLogic::getDetail($id);
+        $detail['shipping'] = OrderLogic::shippingInfo($detail['id']);
+        return view('', [
+            'detail' => $detail
+        ]);
+    }
+
+
+    /**
+     * @notes 导出Excel
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/4/24 10:20
+     */
+    public function export()
+    {
+        $params = $this->request->get();
+        $result = OrderLogic::statistics($params, true);
+        if(false === $result) {
+            return JsonServer::error(OrderLogic::getError() ?: '导出失败');
+        }
+        return JsonServer::success('', $result);
+    }
+}

+ 82 - 0
app/admin/controller/seckill/SeckillGoods.php

@@ -0,0 +1,82 @@
+<?php
+namespace app\admin\controller\seckill;
+
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use app\admin\logic\seckill\SeckillGoodsLogic;
+
+class SeckillGoods extends AdminBase
+{
+    public function lists()
+    {
+        $statistics = SeckillGoodsLogic::statistics();
+        $seckill_time = SeckillGoodsLogic::getTimeAll();
+        return view('', [
+            'statistics' => $statistics,
+            'seckill_time' => $seckill_time
+        ]);
+    }
+
+
+    public function goodsLists(){
+        if($this->request->isAjax()){
+            $get = $this->request->get();
+            $list = SeckillGoodsLogic::goodsList($get);
+            return JsonServer::success('', $list);
+        }
+    }
+
+    public function editGoods(){
+        $id = $this->request->get('id');
+        $seckill_id = $this->request->get('seckill_id');
+        $start_date = $this->request->get('start_date');
+        $end_date = $this->request->get('end_date');
+
+        $detail = SeckillGoodsLogic::getSeckillGoods($id,$seckill_id,$start_date,$end_date);
+        $seckill_time = SeckillGoodsLogic::getTimeAll();
+
+        return view('', [
+            'seckill' => $seckill_time,
+            'detail' => $detail
+        ]);
+    }
+
+    /**
+     * 违规重审
+     */
+    public function reAudit()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $result = SeckillGoodsLogic::reAudit($post);
+            if ($result === true) {
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error(SeckillGoodsLogic::getError());
+        }
+
+        $get = $this->request->get();
+        return view('re_audit', [
+            'get' => $get
+        ]);
+    }
+
+    /**
+     * 审核
+     */
+    public function audit()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $result = SeckillGoodsLogic::audit($post);
+            if ($result) {
+                return JsonServer::success('操作成功');
+            }
+            return JsonServer::error(SeckillGoodsLogic::getError());
+        }
+        $get = $this->request->get();
+        return view('audit', [
+            'get' => $get
+        ]);
+    }
+}

+ 75 - 0
app/admin/controller/seckill/SeckillTime.php

@@ -0,0 +1,75 @@
+<?php
+namespace app\admin\controller\seckill;
+
+use app\admin\logic\seckill\SeckillTimeLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use think\exception\ValidateException;
+use app\admin\validate\seckill\SeckillTimeValidate;
+
+class SeckillTime extends AdminBase
+{
+    public function lists()
+    {
+        return view();
+    }
+
+    public function addTime()
+    {
+        if($this->request->isAjax()) {
+            $post = $this->request->post();
+            try{
+                validate(SeckillTimeValidate::class)->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = SeckillTimeLogic::addTime($post);
+            if($result === true) {
+                return JsonServer::success('新增成功');
+            }
+            return JsonServer::error(SeckillTimeLogic::getError());
+        }
+        return view();
+    }
+
+    public function timeLists(){
+        if($this->request->isAjax()){
+            $get= $this->request->get();
+            $list = SeckillTimeLogic::timeList($get);
+            return JsonServer::success('', $list);
+        }
+    }
+
+    public function editTime(){
+        if($this->request->isAjax()){
+            $post = $this->request->post();
+            try{
+                validate(SeckillTimeValidate::class)->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = SeckillTimeLogic::editTime($post);
+            if($result === true) {
+                return JsonServer::success('编辑成功');
+            }
+            return JsonServer::error(SeckillTimeLogic::getError());
+        }
+
+        $id = $this->request->get('id', '', 'intval');
+        return view('', [
+            'detail' => SeckillTimeLogic::getTime($id)
+        ]);
+    }
+
+    public function delTime(){
+        if($this->request->isAjax()){
+            $id = $this->request->post('id');
+            $result = SeckillTimeLogic::delTime($id);
+
+            if($result === true) {
+                return JsonServer::success('删除成功');
+            }
+            return JsonServer::error(SeckillTimeLogic::getError());
+        }
+    }
+}

+ 133 - 0
app/admin/controller/sign_daily/SignDaily.php

@@ -0,0 +1,133 @@
+<?php
+
+
+namespace app\admin\controller\sign_daily;
+
+
+use app\admin\logic\sign_daily\SignDailyLogic;
+use app\admin\validate\sign_daily\SignDailyValidate;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+
+/**
+ * 签到
+ * Class SignDaily
+ * @package app\admin\controller\shop
+ */
+class SignDaily extends AdminBase
+{
+
+    /**
+     * @notes 连续签到列表
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2022/2/17 14:28
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $lists = SignDailyLogic::lists();
+            return JsonServer::success('获取成功', $lists);
+        }
+        return view('sign_daily/lists', [
+            'config' => SignDailyLogic::getSignRule()
+        ]);
+    }
+
+
+    /**
+     * @notes 签到记录
+     * @return \think\response\Json|void
+     * @author 段誉
+     * @date 2022/2/17 14:29
+     */
+    public function record()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            return JsonServer::success('获取成功', SignDailyLogic::record($get));
+        }
+    }
+
+
+    /**
+     * @notes 每日签到奖励
+     * @return \think\response\Json|void
+     * @author 段誉
+     * @date 2022/2/17 14:29
+     */
+    public function signRule()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['integral_status'] = isset($post['integral_status']) && $post['integral_status'] == 'on' ? 1 : 0;
+            $post['growth_status'] = isset($post['growth_status']) && $post['growth_status'] == 'on' ? 1 : 0;
+            (new SignDailyValidate())->goCheck('sign', $post);
+            $result = SignDailyLogic::setSignRule($post);
+            if (true === $result) {
+                return JsonServer::success('设置成功');
+            }
+            return JsonServer::error(SignDailyLogic::getError() ?: '操作失败');
+        }
+    }
+
+
+    /**
+     * @notes 添加连续签到奖励
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2022/2/17 14:29
+     */
+    public function add()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['integral_status'] = isset($post['integral_status']) && $post['integral_status'] == 'on' ? 1 : 0;
+            $post['growth_status'] = isset($post['growth_status']) && $post['growth_status'] == 'on' ? 1 : 0;
+            (new SignDailyValidate())->goCheck('add', $post);
+            SignDailyLogic::add($post);
+            return JsonServer::success('添加成功');
+        }
+        return view('sign_daily/add');
+    }
+
+
+    /**
+     * @notes 编辑连续签到奖励
+     * @param $id
+     * @return \think\response\Json|\think\response\View
+     * @author 段誉
+     * @date 2022/2/17 14:30
+     */
+    public function edit($id)
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $post['integral_status'] = isset($post['integral_status']) && $post['integral_status'] == 'on' ? 1 : 0;
+            $post['growth_status'] = isset($post['growth_status']) && $post['growth_status'] == 'on' ? 1 : 0;
+            (new SignDailyValidate())->goCheck('edit', $post);
+            SignDailyLogic::edit($post);
+            return JsonServer::success('修改成功');
+        }
+        return view('sign_daily/edit', ['info' => SignDailyLogic::getSignDaily($id)]);
+    }
+
+
+    /**
+     * @notes 删除连续签到奖励
+     * @return \think\response\Json
+     * @author 段誉
+     * @date 2022/2/17 14:30
+     */
+    public function del()
+    {
+        if ($this->request->isAjax()) {
+            $id = $this->request->post('id');
+            SignDailyLogic::del($id);
+            return JsonServer::success('删除成功');
+        }
+        return JsonServer::error('请求异常');
+    }
+
+
+}

+ 113 - 0
app/admin/controller/team/Activity.php

@@ -0,0 +1,113 @@
+<?php
+
+
+namespace app\admin\controller\team;
+
+
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use app\admin\logic\team\ActivityLogic;
+use think\facade\View;
+
+class Activity extends AdminBase
+{
+    /**
+     * @Notes: 拼团商品
+     * @Author: 张无忌
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = ActivityLogic::lists($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+
+        View::assign('statistics', ActivityLogic::statistics());
+        return view();
+    }
+
+    /**
+     * @notes 拼团商品的开团记录
+     * @author 张无忌
+     * @date 2021/7/19 11:00
+     */
+    public function record()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = ActivityLogic::record($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+
+
+        $get = $this->request->get();
+        View::assign('shop_id', $get['shop_id']);
+        View::assign('team_activity_id', $get['id']);
+        View::assign('recordStatistics', ActivityLogic::recordStatistics($get));
+        return view();
+    }
+
+    /**
+     * @Notes: 统计
+     * @Author: 张无忌
+     */
+    public function statistics()
+    {
+        if ($this->request->isAjax()) {
+            $detail = ActivityLogic::statistics();
+            return JsonServer::success('获取成功', $detail);
+        }
+        return JsonServer::error('异常');
+    }
+
+    /**
+     * @Notes: 审核
+     * @Author: 张无忌
+     */
+    public function audit()
+    {
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            $res = ActivityLogic::audit($post);
+            if ($res === false) {
+                $message = ActivityLogic::getError() ?: '审核失败';
+                return JsonServer::error($message);
+            }
+            return JsonServer::success('审核成功');
+        }
+
+        return view();
+    }
+
+    /**
+     * @Notes: 违规重审
+     * @Author: 张无忌
+     */
+    public function violation()
+    {
+        if ($this->request->isAjax()) {
+            $id = $this->request->post('id');
+            $res = ActivityLogic::violation($id);
+            if ($res === false) {
+                $message = ActivityLogic::getError() ?: '操作失败';
+                return JsonServer::error($message);
+            }
+            return JsonServer::success('操作成功');
+        }
+
+        return JsonServer::error("异常");
+    }
+
+    /**
+     * @Notes: 拼团信息
+     * @Author: 张无忌
+     * @return \think\response\View
+     */
+    public function details()
+    {
+        $id = $this->request->get('id');
+        View::assign('detail', ActivityLogic::detail($id));
+        return view();
+    }
+}

+ 72 - 0
app/admin/controller/team/Found.php

@@ -0,0 +1,72 @@
+<?php
+
+
+namespace app\admin\controller\team;
+
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use app\admin\logic\team\FoundLogic;
+use think\facade\View;
+
+/**
+ * 拼团记录管理
+ * Class Record
+ * @package app\shop\controller\team
+ */
+class Found extends AdminBase
+{
+    /**
+     * @Notes: 拼团记录
+     * @Author: 张无忌
+     */
+    public function lists()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = FoundLogic::lists($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+
+        View::assign('statistics', FoundLogic::statistics());
+        return view();
+    }
+
+    /**
+     * @Notes: 数据统计
+     * @Author: 张无忌
+     */
+    public function statistics()
+    {
+        if ($this->request->isAjax()) {
+            $detail = FoundLogic::statistics();
+            return JsonServer::success('获取成功', $detail);
+        }
+        return JsonServer::error('异常');
+    }
+
+
+    /**
+     * @Notes: 拼团记录详细
+     * @Author: 张无忌
+     */
+    public function detail()
+    {
+        $id = $this->request->get('id');
+        View::assign('detail', FoundLogic::detail($id));
+        return view();
+    }
+
+    /**
+     * @Notes: 参团列表
+     * @Author: 张无忌
+     */
+    public function join()
+    {
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            $lists = FoundLogic::join($get);
+            return JsonServer::success('获取成功', $lists);
+        }
+        return JsonServer::error('请求异常');
+    }
+}

+ 39 - 0
app/admin/controller/team/Setting.php

@@ -0,0 +1,39 @@
+<?php
+
+
+namespace app\admin\controller\team;
+
+
+use app\common\basics\AdminBase;
+use app\common\server\ConfigServer;
+use app\common\server\JsonServer;
+use think\facade\View;
+
+class Setting extends AdminBase
+{
+    /**
+     * @Notes: 拼团设置页
+     * @Author: 张无忌
+     * @return \think\response\View
+     */
+    public function index()
+    {
+        $automatic = ConfigServer::get('team', 'automatic', 0);
+        View::assign('automatic', $automatic);
+        return view();
+    }
+
+    /**
+     * @Notes: 设置拼团
+     * @Author: 张无忌
+     */
+    public function set()
+    {
+        if ($this->request->isAjax()) {
+            $automatic = $this->request->post('automatic', 0, 'intval');
+            ConfigServer::set('team', 'automatic', $automatic);
+            return JsonServer::success('设置成功');
+        }
+        return JsonServer::error('异常');
+    }
+}

+ 89 - 0
app/admin/controller/user/Level.php

@@ -0,0 +1,89 @@
+<?php
+namespace app\admin\controller\user;
+
+
+use app\common\basics\AdminBase;
+use app\common\server\ConfigServer;
+use app\common\server\JsonServer;
+use think\exception\ValidateException;
+use app\admin\validate\user\LevelValidate;
+use app\admin\logic\user\LevelLogic;
+
+class Level extends AdminBase
+{
+    public function lists()
+    {
+        if($this->request->isAjax()){
+            $get = $this->request->get();
+            $lists = LevelLogic::lists($get);
+            return JsonServer::success('', $lists);
+        }
+        return view();
+    }
+
+    public function add()
+    {
+        if($this->request->isAjax()) {
+            try{
+                $post = $this->request->post();
+                validate(LevelValidate::class)->scene('add')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = LevelLogic::add($post);
+            if($result === true) {
+                return JsonServer::success('添加成功');
+            }
+            return JsonServer::error(LevelLogic::getError());
+        }
+        return view();
+    }
+
+    public function edit(){
+        if($this->request->isAjax()){
+            try{
+                $post = $this->request->post();
+                validate(LevelValidate::class)->scene('edit')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = LevelLogic::edit($post);
+            if($result === true) {
+                return JsonServer::success('编辑成功');
+            }
+            return JsonServer::error(LevelLogic::getError());
+        }
+
+        $id = $this->request->get('id', '', 'intval');
+        $detail = LevelLogic::getUserLevel($id);
+        return view('', [
+            'detail' => $detail
+        ]);
+    }
+
+    public function del()
+    {
+        $id = $this->request->post('id', '',  'intval');
+        $result = LevelLogic::del($id);
+        if($result === true) {
+            return JsonServer::success('删除成功');
+        }
+        return JsonServer::error(LevelLogic::getError());
+    }
+
+    public function set()
+    {
+        if($this->request->isAjax()) {
+            $post = $this->request->post();
+            ConfigServer::set('user_level', 'intro', $post['intro']);
+            return JsonServer::success('设置成功');
+        }
+        $intro = ConfigServer::get('user_level', 'intro');
+        $intro_default = config('default.user_level.intro');
+
+        return view('', [
+            'intro' => $intro,
+            'intro_default' => $intro_default
+        ]);
+    }
+}

+ 72 - 0
app/admin/controller/user/Tag.php

@@ -0,0 +1,72 @@
+<?php
+namespace app\admin\controller\user;
+
+use app\admin\logic\user\TagLogic;
+use app\common\basics\AdminBase;
+use app\common\server\JsonServer;
+use think\exception\ValidateException;
+use app\admin\validate\user\TagValidate;
+
+class Tag extends AdminBase
+{
+    public function lists()
+    {
+        if($this->request->isAjax()) {
+            $get = $this->request->get();
+            $data = TagLogic::lists($get);
+            return JsonServer::success('', $data);
+        }
+        return view();
+    }
+
+    public function add()
+    {
+        if($this->request->isPost()) {
+            $post = $this->request->post();
+            try{
+                validate(TagValidate::class)->scene('add')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = TagLogic::add($post);
+            if($result === true) {
+                return JsonServer::success('添加成功');
+            }
+            return JsonServer::error(TagLogic::getError());
+        }
+        return view();
+    }
+
+    public function edit()
+    {
+        if($this->request->isPost()) {
+            $post = $this->request->post();
+            try{
+                validate(TagValidate::class)->scene('edit')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+            $result = TagLogic::edit($post);
+            if($result === true) {
+                return JsonServer::success('编辑成功');
+            }
+            return JsonServer::error(TagLogic::getError());
+        }
+
+        $id = $this->request->get('id', '', 'intval');
+        $detail = TagLogic::detail($id);
+        return view('', [
+            'detail' => $detail
+        ]);
+    }
+
+    public function del()
+    {
+        $id = $this->request->post('id', '', 'intval');
+        $result = TagLogic::del($id);
+        if($result === true) {
+            return JsonServer::success('删除成功');
+        }
+        return JsonServer::error(TagLogic::getError());
+    }
+}

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

@@ -0,0 +1,171 @@
+<?php
+namespace app\admin\controller\user;
+
+use app\admin\logic\user\TagLogic;
+use app\common\basics\AdminBase;
+use app\admin\logic\user\LevelLogic;
+use app\admin\logic\user\UserLogic;
+use app\common\model\user\UserLevel;
+use app\common\server\JsonServer;
+use app\common\enum\ClientEnum;
+use app\admin\validate\user\UserValidate;
+use think\exception\ValidateException;
+
+class User extends  AdminBase
+{
+    public function lists(){
+        if ($this->request->isAjax()) {
+            $get = $this->request->get();
+            return JsonServer::success('', UserLogic::lists($get));
+        }
+
+        return view('', [
+            'level_list' => LevelLogic::getLevelList(),
+            'tag_list' => TagLogic::getTagList(),
+            'client_list' => ClientEnum::getClient(true)
+        ]);
+    }
+
+    public function setTag(){
+        if($this->request->isAjax()){
+            $post = $this->request->post();
+            try{
+                validate(UserValidate::class)->scene('setTag')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getMessage());
+            }
+            $result = UserLogic::setTag($post);
+            if($result === true) {
+                return JsonServer::success('设置成功');
+            }
+            return JsonServer::error(UserLogic::getError());
+        }
+        return view('', [
+            'tag_list' => json_encode(TagLogic::getTagList())
+        ]);
+    }
+
+    public function edit(){
+        if($this->request->isAjax()){
+            $post = $this->request->post();
+            try{
+                validate(UserValidate::class)->scene('edit')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getMessage());
+            }
+            $result = UserLogic::edit($post);
+            if($result === true) {
+                return JsonServer::success('编辑成功');
+            }
+            return JsonServer::error(UserLogic::getError());
+        }
+
+        $id = $this->request->get('id', '', 'intval');
+        $detail = UserLogic::getUser($id);
+
+        return view('', [
+            'info' => $detail,
+            'tag_list' => json_encode(TagLogic::getTagList())
+        ]);
+    }
+
+    public function info(){
+        $id = $this->request->get('id', '', 'intval');
+        $detail = UserLogic::getInfo($id);
+        return view('', [
+            'detail' => $detail
+        ]);
+    }
+
+    public function adjustAccount(){
+        if ($this->request->isAjax()) {
+            $post = $this->request->post();
+            try{
+                validate(UserValidate::class)->scene('adjustAccount')->check($post);
+            }catch(ValidateException $e) {
+                return JsonServer::error($e->getError());
+            }
+
+            $result = UserLogic::adjustAccount($post);
+            if($result === true) {
+                return JsonServer::success('调整成功');
+            }
+            return JsonServer::error(UserLogic::getError());
+
+        }
+        $id = $this->request->get('id', '', 'intval');
+        return view('', [
+            'info' => UserLogic::getUser($id)
+        ]);
+    }
+
+    public function adjustLevel(){
+        if ($this->request->isPost()) {
+            $params = $this->request->post();
+            $result = UserLogic::adjustLevel($params);
+            if ($result) {
+                return JsonServer::success('调整成功');
+            }
+            return JsonServer::error(UserLogic::getError());
+        }
+
+        $id = $this->request->get('id/d');
+        $levels = UserLevel::where('del', 0)->order('growth_value', 'asc')->column('id,name', 'id');
+        $userLevel = \app\common\model\user\User::where('id', $id)->value('level');
+        $userLevelName = isset($levels[$userLevel]) ? $levels[$userLevel]['name'] : '无等级';
+        return view('', [
+            'levels' => $levels,
+            'user_level_name' => $userLevelName,
+            'user_id' => $id
+        ]);
+    }
+
+    public function adjustFirstLeader()
+    {
+        if($this->request->isPost()) {
+            $params = $this->request->post();
+            $result = UserLogic::adjustFirstLeader($params);
+            if ($result) {
+                return JsonServer::success('调整成功');
+            }
+            return JsonServer::error(UserLogic::getError());
+        }
+
+        $id = $this->request->get('id/d');
+        $user =  \app\common\model\user\User::field('id,sn,nickname,first_leader')->findOrEmpty($id)->toArray();
+        $firstLeader = \app\common\model\user\User::getUserInfo($user['first_leader']);
+        return view('', [
+            'user_id' => $id,
+            'user' => $user,
+            'first_leader' => $firstLeader
+        ]);
+    }
+
+    public function userLists()
+    {
+        if ($this->request->isPost()) {
+            $params = $this->request->post();
+            $lists = UserLogic::userLists($params);
+            return JsonServer::success('', $lists);
+        }
+        return view();
+    }
+
+    /**
+     * @notes 推荐下级
+     * @return \think\response\View
+     * @author Tab
+     * @date 2021/9/8 20:40
+     */
+    public function fans()
+    {
+        if ($this->request->isPost()) {
+            $params = $this->request->post();
+            $result = UserLogic::fans($params);
+            return JsonServer::success('', $result);
+        }
+
+        $id = $this->request->get('id/d');
+        return view('', ['id' => $id]);
+    }
+}

+ 77 - 0
app/admin/logic/FootprintLogic.php

@@ -0,0 +1,77 @@
+<?php
+
+
+namespace app\admin\logic;
+
+
+use app\common\basics\Logic;
+use app\common\model\Footprint;
+use app\common\server\ConfigServer;
+use Exception;
+
+class FootprintLogic extends Logic
+{
+    /**
+     * @Notes: 气泡场景列表
+     * @Author: 张无忌
+     * @return array
+     */
+    public static function lists()
+    {
+        try {
+            $footprintModel = new Footprint();
+            return $footprintModel->select()->toArray();
+        } catch (Exception $e) {
+            return ['error'=>$e->getMessage()];
+        }
+    }
+
+    /**
+     * @Notes: 气泡详细
+     * @Author: 张无忌
+     * @param $id
+     * @return array
+     */
+    public static function detail($id)
+    {
+        $footprintModel = new Footprint();
+        return $footprintModel->findOrEmpty((int)$id)->toArray();
+    }
+
+    /**
+     * @Notes: 编辑足迹气泡
+     * @Author: 张无忌
+     * @param $post
+     * @return bool
+     */
+    public static function edit($post)
+    {
+        try {
+            $footprintModel = new Footprint();
+            $footprintModel->where(['id' => (int)$post['id']])
+                ->update(['status' => $post['status']]);
+
+            return true;
+        } catch (Exception $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @Notes: 足迹设置
+     * @Author: 张无忌
+     * @param $post
+     * @return bool
+     */
+    public static function set($post)
+    {
+        try {
+            ConfigServer::set('footprint', 'footprint_duration', $post['duration']);
+            ConfigServer::set('footprint', 'footprint_status', $post['status']);
+            return true;
+        } catch (Exception $e) {
+            return false;
+        }
+    }
+}

+ 139 - 0
app/admin/logic/RechargeLogic.php

@@ -0,0 +1,139 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\logic;
+
+use app\common\basics\Logic;
+use app\common\model\RechargeTemplate;
+use think\facade\Db;
+use app\common\server\ConfigServer;
+
+class RechargeLogic extends Logic
+{
+    public static function templatelists(){
+        $list = RechargeTemplate::where(['del'=>0])->order(['sort' => 'desc'])->select()->toArray();
+        foreach ($list as &$item){
+            $item['money'] && $item['money'] = '¥'.$item['money'];
+            $item['give_money'] && $item['give_money'] = '¥'.$item['give_money'];
+        }
+        return $list;
+    }
+
+    public static function getRechargeConfig(){
+        $config =  [
+            'open_racharge'  => ConfigServer::get('recharge','open_racharge',0),
+            'give_growth'    => ConfigServer::get('recharge', 'give_growth', 0),
+            'min_money'      => ConfigServer::get('recharge', 'min_money', 0),
+        ];
+        return [$config];
+    }
+
+    public static function add($post){
+        try{
+            // 判断充值金额是否已存在
+            $recharge_template = RechargeTemplate::where([
+                'del' =>0,
+                'money' => $post['money']
+            ])->findOrEmpty();
+            if(!$recharge_template->isEmpty()) {
+                throw new \think\Exception('该充值金额的模板已存在');
+            }
+            $new = time();
+            $add_data = [
+                'money'         => $post['money'],
+                'give_money'    => $post['give_money'],
+                'sort'          => $post['sort'],
+                'is_recommend'  => $post['is_recommend'],
+                'create_time'   => $new,
+                'update_time'   => $new,
+            ];
+            RechargeTemplate::create($add_data);
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function changeTableValue($table,$pk_name,$pk_value,$field,$field_value){
+        //允许修改的字段
+        $allow_field = [
+            'is_show','sort','status','is_new','is_best','is_like','is_recommend'
+        ];
+        if(!in_array($field,$allow_field)){
+            return false;
+        }
+        if(is_array($pk_value)){
+            $where[] = [$pk_name,'in',$pk_value];
+        }else{
+            $where[] = [$pk_name,'=',$pk_value];
+        }
+
+        $data= [
+            $field          => $field_value,
+            'update_time'   => time(),
+        ];
+
+        return Db::name($table)->where($where)->update($data);
+    }
+
+
+    public static function getRechargeTemplate($id){
+        return Db::name('recharge_template')->where(['id'=>$id])->find();
+    }
+
+    public static function edit($post){
+        try{
+            // 判断充值金额是否已存在
+            $recharge_template = RechargeTemplate::where([
+                ['del', '=', 0],
+                ['money', '=', $post['money']],
+                ['id', '<>', $post['id']],
+            ])->findOrEmpty();
+            if(!$recharge_template->isEmpty()) {
+                throw new \think\Exception('该充值金额的模板已存在');
+            }
+            $new = time();
+            $update_data = [
+                'id'            => $post['id'],
+                'money'         => $post['money'],
+                'give_money'    => $post['give_money'],
+                'sort'          => $post['sort'],
+                'is_recommend'  => $post['is_recommend'],
+                'update_time'   => $new,
+            ];
+            RechargeTemplate::update($update_data);
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function del($id){
+        return Db::name('recharge_template')->where(['id'=>$id])->update(['update_time'=>time(),'del'=>1]);
+    }
+
+    public static function setRecharge($post){
+        ConfigServer::set('recharge','open_racharge',$post['open_racharge']);
+        ConfigServer::set('recharge','give_growth',$post['give_growth']);
+        ConfigServer::set('recharge','min_money',$post['min_money']);
+    }
+}

+ 110 - 0
app/admin/logic/account_log/AccountLogLogic.php

@@ -0,0 +1,110 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+namespace app\admin\logic\account_log;
+use app\common\model\AccountLog;
+use think\Db;
+
+class AccountLogLogic{
+    /**
+     * 获取变动类型描述
+     */
+    public static function getTypeDesc($typeArr)
+    {
+        $temp = [];
+        foreach($typeArr as $type) {
+            $temp[] = ['id' => $type, 'name' => AccountLog::getAcccountDesc($type)];
+        }
+        return $temp;
+    }
+
+    /**
+     * 获取常用时间段
+     */
+    public static function getTime(){
+        $today_date = date('Y-m-d', time());
+        $today_start = $today_date.' 00:00:00';
+        $today_end = $today_date.' 23:59:59';
+        $today = [$today_start, $today_end];
+
+        $yesterday_date = date('Y-m-d', strtotime('-1 day'));
+        $yesterday_start = $yesterday_date . ' 00:00:00';
+        $yesterday_end = $yesterday_date . ' 23:59:59';
+        $yesterday = [$yesterday_start, $yesterday_end];
+
+        $ago7_date = date('Y-m-d', strtotime('-7 day'));
+        $ago7_start = $ago7_date . ' 00:00:00';
+//        $ago7_end = $ago7_date . ' 23:59:59';
+        $ago7_end = $today_date . ' 23:59:59';
+        $ago7 = [$ago7_start, $ago7_end];
+
+        $ago30_date = date('Y-m-d', strtotime('-30 day'));
+        $ago30_start = $ago30_date . ' 00:00:00';
+//        $ago30_end = $ago30_date . ' 23:59:59';
+        $ago30_end = $today_date . ' 23:59:59';
+        $ago30 = [$ago30_start, $ago30_end];
+
+        $time = [
+            'today'         => $today,
+            'yesterday'     => $yesterday,
+            'days_ago7'     => $ago7,
+            'days_ago30'    => $ago30,
+        ];
+
+        return $time;
+    }
+
+    public static function growthLists($get)
+    {
+        $where = [
+          ['al.source_type', 'in', AccountLog::growth_change]
+        ];
+
+        if(isset($get['keyword']) && !empty($get['keyword'])) {
+            $where[] = ['u.'.$get['keyword_type'], '=',$get['keyword']];
+        }
+        if(isset($get['order_source']) && !empty($get['order_source'])) {
+            $where[] = ['al.source_type', '=', $get['order_source']];
+        }
+
+        if(isset($get['start_time']) && !empty($get['start_time'])) {
+            $where[] = ['al.create_time', '>=', strtotime($get['start_time'])];
+        }
+
+        if(isset($get['end_time']) && !empty($get['end_time'])) {
+            $where[] = ['al.create_time', '<=', strtotime($get['end_time'])];
+        }
+
+        $count = AccountLog::alias('al')
+            ->leftJoin('user u', 'u.id=al.user_id')
+            ->where($where)
+            ->count();
+        $lists = AccountLog::alias('al')
+            ->field('al.*, u.nickname,u.sn,u.mobile')
+            ->leftJoin('user u', 'u.id=al.user_id')
+            ->where($where)
+            ->order('create_time', 'desc')
+            ->page($get['page'], $get['limit'])
+            ->select()
+            ->toArray();
+        return [
+            'count' => $count,
+            'lists' => $lists
+        ];
+    }
+}

+ 142 - 0
app/admin/logic/activity_area/AreaLogic.php

@@ -0,0 +1,142 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+namespace app\admin\logic\activity_area;
+
+use app\common\basics\Logic;
+use app\common\server\JsonServer;
+use think\facade\Db;
+use app\common\model\activity_area\ActivityArea;
+use app\common\model\activity_area\ActivityAreaGoods;
+use app\common\server\UrlServer;
+
+/**
+ * Class AreaLogic
+ * @package app\admin\logic\activity_area
+ */
+class  AreaLogic extends Logic
+{
+
+    /**
+     * @notes 活动专区列表
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:53 上午
+     */
+    public static function lists($get)
+    {
+
+        $where[] = ['del', '=', 0];
+        $lists = ActivityArea::where($where)
+            ->page($get['page'], $get['limit'])
+            ->select();
+
+        $count = ActivityArea::where($where)
+            ->count();
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 添加活动专区
+     * @param $post
+     * @return int|string
+     * @author suny
+     * @date 2021/7/14 9:53 上午
+     */
+    public static function add($post)
+    {
+
+        $post['create_time'] = time();
+        if (isset($post['status']) && $post['status'] == 'on') {
+            $post['status'] = 1; //专区显示
+        } else {
+            $post['status'] = 0; //专区隐藏
+        }
+        $post['image'] = UrlServer::setFileUrl($post['image']);
+        return ActivityArea::insert($post);
+    }
+
+    /**
+     * @notes 获取活动专区
+     * @param $id
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:53 上午
+     */
+    public static function getActivityArea($id)
+    {
+
+        $data = ActivityArea::where(['id' => $id, 'del' => 0])->find();
+        $data = $data->getData();
+        $data['image'] = UrlServer::getFileUrl($data['image']);
+        return $data;
+    }
+
+    /**
+     * @notes 获取所有活动专区
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:53 上午
+     */
+    public static function getActivityAreaAll()
+    {
+
+        return ActivityArea::where(['del' => 0])
+            ->select();
+    }
+
+    /**
+     * @notes 编辑活动专区
+     * @param $post
+     * @return ActivityArea
+     * @author suny
+     * @date 2021/7/14 9:53 上午
+     */
+    public static function edit($post)
+    {
+
+        $post['image'] = UrlServer::setFileUrl($post['image']);
+        return ActivityArea::update($post);
+    }
+
+    /**
+     * @notes 删除活动专区
+     * @param $id
+     * @return bool
+     * @author suny
+     * @date 2021/7/14 9:54 上午
+     */
+    public static function del($id)
+    {
+
+        $AreaResult = ActivityArea::update(['del' => 1, 'id' => $id]);
+        $AreaGoodsResult = ActivityAreaGoods::where('activity_area_id', $id)->update(['del' => 1]);
+        return $AreaResult;
+    }
+}

+ 193 - 0
app/admin/logic/activity_area/GoodsLogic.php

@@ -0,0 +1,193 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+namespace app\admin\logic\activity_area;
+
+use app\common\model\activity_area\ActivityAreaGoods;
+use app\common\basics\Logic;
+use app\common\server\UrlServer;
+use think\facade\Db;
+
+/**
+ * Class GoodsLogic
+ * @package app\admin\logic\activity_area
+ */
+class GoodsLogic extends Logic
+{
+
+    /**
+     * @notes 活动专区商品列表
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:54 上午
+     */
+    public static function lists($get)
+    {
+
+        $where[] = ['AG.del', '=', 0];
+        if (!isset($get['type'])) {
+            $get['type'] = 1;
+        }
+        switch ($get['type']) {
+            case 1:
+                $audit_status = ActivityAreaGoods::AUDIT_STATUS_PASS;
+                break;
+            case 0:
+                $audit_status = ActivityAreaGoods::AUDIT_STATUS_WAIT;
+                break;
+            case 2:
+                $audit_status = ActivityAreaGoods::AUDIT_STATUS_REFUSE;
+                break;
+        }
+        $where[] = ['AG.audit_status', '=', $audit_status];
+
+        if (isset($get['shop_name']) && $get['shop_name']) {
+            $where[] = ['S.name', 'like', '%' . $get['shop_name'] . '%'];
+        }
+
+        if (isset($get['goods_name']) && $get['goods_name']) {
+            $where[] = ['G.name', 'like', '%' . $get['goods_name'] . '%'];
+        }
+
+        if (isset($get['activity_area']) && $get['activity_area']) {
+            $where[] = ['AA.id', '=', $get['activity_area']];
+        }
+
+        $count = ActivityAreaGoods::alias('AG')
+            ->join('activity_area AA', 'AG.activity_area_id = AA.id')
+            ->join('shop S', 'S.id = AG.shop_id')
+            ->join('goods G', 'AG.Goods_id = G.id')
+            ->where($where)
+            ->count();
+
+        $lists = ActivityAreaGoods::alias('AG')
+            ->join('activity_area AA', 'AG.activity_area_id = AA.id')
+            ->join('goods G', 'AG.Goods_id = G.id')
+            ->join('shop S', 'S.id = AG.shop_id')
+            ->where($where)
+            ->field('AG.id,AG.goods_id,AG.activity_area_id,AG.audit_status,AG.audit_remark,AA.name as activity_area_name,G.id as gid,G.name,G.image,G.min_price,G.max_price,S.id as sid,S.name as shop_name,S.type')
+            ->order('AG.id desc')
+            ->page($get['page'], $get['limit'])
+            ->select();
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 获取活动专区商品
+     * @param $id
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:55 上午
+     */
+    public static function getActivityAreaGoods($id)
+    {
+
+        return ActivityAreaGoods::where(['del' => 0, 'id' => $id])
+            ->select();
+    }
+
+    /**
+     * @notes 审核
+     * @param $post
+     * @return ActivityAreaGoods
+     * @author suny
+     * @date 2021/7/14 9:55 上午
+     */
+    public static function audit($post)
+    {
+
+        $data = [
+            'audit_status' => $post['review_status'],
+            'audit_remark' => $post['description'],
+        ];
+        return ActivityAreaGoods::where(['id' => $post['id']])
+            ->update($data);
+    }
+
+    /**
+     * @notes 违规重审
+     * @param $post
+     * @return ActivityAreaGoods
+     * @author suny
+     * @date 2021/7/14 9:55 上午
+     */
+    public static function violation($post)
+    {
+
+        $data = [
+            'audit_status' => 2,
+            'audit_remark' => $post['description'],
+        ];
+        return ActivityAreaGoods::where(['id' => $post['id']])
+            ->update($data);
+    }
+
+    /**
+     * @notes 活动专区商品详情
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:55 上午
+     */
+    public static function detail($get)
+    {
+
+        $where = [];
+        $where['AG.id'] = $get['id'];
+        $info = ActivityAreaGoods::alias('AG')
+            ->join('activity_area AA', 'AG.activity_area_id = AA.id')
+            ->join('goods G', 'AG.Goods_id = G.id')
+            ->join('shop S', 'S.id = AG.shop_id')
+            ->where($where)
+            ->field('AG.id,AG.goods_id,AG.activity_area_id,AG.audit_status,AG.audit_remark,AA.name as activity_area_name,AA.image as aimage,G.id as gid,G.name,G.image,G.min_price,G.max_price,S.id as sid,S.name as shop_name,S.type')
+            ->find()->toArray();
+        $info['aimage'] = UrlServer::getFileUrl($info['aimage']);
+        return $info;
+    }
+
+    /**
+     * @notes 获取各列表数量
+     * @return array
+     * @author suny
+     * @date 2021/7/14 9:55 上午
+     */
+    public static function getNum()
+    {
+
+        $unaudit = ActivityAreaGoods::where(['audit_status' => 0, 'del' => 0])->count('id');
+        $audit_pass = ActivityAreaGoods::where(['audit_status' => 1, 'del' => 0])->count('id');
+        $audit_refund = ActivityAreaGoods::where(['audit_status' => 2, 'del' => 0])->count('id');
+        $num = [
+            'unaudit' => $unaudit,
+            'audit_pass' => $audit_pass,
+            'audit_refund' => $audit_refund
+        ];
+        return $num;
+    }
+}

+ 433 - 0
app/admin/logic/bargain/BargainLogic.php

@@ -0,0 +1,433 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\logic\bargain;
+
+
+use app\admin\controller\finance\Shop;
+use app\common\basics\Logic;
+use app\common\model\shop\Shop as ShopModel;
+use app\common\model\bargain\Bargain;
+use app\common\model\bargain\BargainItem;
+use app\common\model\bargain\BargainKnife;
+use app\common\model\bargain\BargainLaunch;
+use app\common\model\goods\Goods as GoodsModel;
+use app\common\model\order\Order;
+use app\common\model\team_activity\TeamActivity as TeamActivityModel;
+use app\common\model\user\User;
+use app\common\server\UrlServer;
+use think\facade\Db;
+use think\Exception;
+
+/**
+ * Class BargainLogic
+ * @package app\admin\logic\bargain
+ */
+class BargainLogic extends Logic
+{
+    protected static $error; //错误信息
+
+    /**
+     * @notes 砍价活动列表
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:57 上午
+     */
+    public static function activity($get)
+    {
+
+        $where = [
+            ['del', '=', 0],
+        ];
+
+        // 查询条件
+
+        if (!empty($get['shop_name']) and $get['shop_name'] !== '') {
+            $shopModel = new ShopModel();
+            $ids = $shopModel->field('id,name')->where([
+                ['name', 'like', '%' . $get['shop_name'] . '%']
+            ])->column('id');
+
+            $where[] = ['shop_id', 'in', $ids];
+        }
+
+        if (!empty($get['goods_name']) and $get['goods_name'] !== '') {
+            $goodsModel = new GoodsModel();
+            $ids = $goodsModel->field('id,name')->where([
+                ['name', 'like', '%' . $get['goods_name'] . '%']
+            ])->column('id');
+
+            $where[] = ['goods_id', 'in', $ids];
+        }
+
+        if (isset($get['status']) and is_numeric($get['status'])) {
+            $where[] = ['status', '=', (int)$get['status']];
+        }
+
+        //审核状态
+        if (isset($get['type']) && $get['type'] != "") {
+            $where[] = ['audit_status', '=', $get['type']];
+        }
+
+        $bargainModel = new Bargain();
+        $count = $bargainModel->where($where)->count('id');
+        $lists = $bargainModel->field(true)
+            ->where($where)
+            ->with(['goods', 'shop'])
+            ->withCount(['launchPeopleNumber', 'successKnifePeopleNumber'])
+            ->page($get['page'], $get['limit'])
+            ->select();
+
+        foreach ($lists as &$item) {
+            $item['goods']['image'] = UrlServer::getFileUrl($item['goods']['image']);
+            $item['activity_start_time'] = date('Y-m-d H:i:s', $item['activity_start_time']);
+            $item['activity_end_time'] = date('Y-m-d H:i:s', $item['activity_end_time']);
+        }
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 砍价活动审核
+     * @param $post
+     * @return Bargain
+     * @author suny
+     * @date 2021/7/14 9:57 上午
+     */
+    public static function audit($post)
+    {
+
+        $data = [
+            'audit_status' => $post['review_status'],
+            'audit_remark' => $post['description'],
+        ];
+        return Bargain::where(['id' => $post['id']])
+            ->update($data);
+    }
+
+    /**
+     * @notes 违规重审
+     * @param $post
+     * @return bool
+     * @author suny
+     * @date 2021/7/14 9:58 上午
+     */
+    public static function violation($post)
+    {
+
+        try {
+            $data = [
+                'audit_status' => 2,
+                'audit_remark' => $post['description'],
+            ];
+            Bargain::where(['id' => $post['id']])
+                ->update($data);
+            BargainLaunch::where(['bargain_id' => $post['id']])
+                ->update(['status' => 2]);//砍失败
+            return true;
+        } catch (Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @notes 切换状态
+     * @param $post
+     * @return bool
+     * @throws \think\exception\PDOException
+     * @author suny
+     * @date 2021/7/14 9:58 上午
+     */
+    public static function switchStatus($post)
+    {
+
+        Db::startTrans();
+        try {
+            $bargainModel = new Bargain();
+            // 切换状态
+            $bargainModel->where(['id' => (int)$post['id']])
+                ->update([$post['field'] => $post['status']]);
+
+            Db::commit();
+            return true;
+        } catch (\Exception $e) {
+            static::$error = $e->getMessage();
+            Db::rollback();
+            return false;
+        }
+    }
+
+    /**
+     * @notes 砍价列表
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @author suny
+     * @date 2021/7/14 9:58 上午
+     */
+    public static function getLaunch($get)
+    {
+
+        // 查询条件
+        $where = [];
+
+        //砍价订单编号bargain_sn
+        if (isset($get['bargain_sn']) and $get['bargain_sn']) {
+            $where[] = ['bargain_sn', '=', (int)$get['bargain_sn']];
+        }
+
+        if (isset($get['goods_name']) and $get['goods_name'] !== '') {
+            $goodsModel = new GoodsModel();
+            $ids = $goodsModel->field('id,name')->where([
+                ['name', 'like', '%' . $get['goods_name'] . '%']
+            ])->column('id');
+
+            $where[] = ['goods_id', 'in', $ids];
+        }
+
+        if (isset($get['status']) and is_numeric($get['status'])) {
+            $where[] = ['status', '=', (int)$get['status']];
+        }
+
+        if (isset($get['launch_start_time']) and $get['launch_start_time'] !== '') {
+            $where[] = ['launch_start_time', '>=', strtotime($get['launch_start_time'])];
+        }
+
+        if (isset($get['launch_end_time']) and $get['launch_end_time'] !== '') {
+            $where[] = ['launch_end_time', '<=', strtotime($get['launch_end_time'])];
+        }
+
+        if (isset($get['keyword_type']) and $get['keyword_type'] !== '') {
+            if (isset($get['keyword']) and $get['keyword'] !== '') {
+                switch ($get['keyword_type']) {
+                    case 'sn':
+                        $uid = User::where('sn', '=', $get['keyword'])->column('id');
+                        $where[] = ['user_id', 'in', $uid];
+                        break;
+                    case 'nickname':
+                        $uid = User::where('nickname', 'like', '%' . $get['keyword'] . '%')->column('id');
+                        $where[] = ['user_id', 'in', $uid];
+                        break;
+                }
+            }
+        }
+
+        $model = new BargainLaunch();
+        $count = $model->where($where)->count('id');
+        $lists = $model->field(true)
+            ->where($where)
+            ->with(['user.level'])
+            ->order('id', 'desc')
+            ->page($get['page'], $get['limit'])
+            ->select()->toArray();
+
+        foreach ($lists as &$item) {
+            // 解决用户被删除及Indirect modification of overloaded element报错
+            if (empty($item['user'])) {
+                $user = [
+                    'avatar' => '',
+                    'sn' => '-',
+                    'nickname' => '-',
+                    'level' => [
+                        'name' => '-'
+                    ]
+                ];
+            } else {
+                $user = $item['user'];
+            }
+            $user['avatar'] = UrlServer::getFileUrl($user['avatar']);
+            $item['user'] = $user;
+            $item['launch_start_time'] = date('Y-m-d H:i:s', $item['launch_start_time']);
+            $item['launch_end_time'] = date('Y-m-d H:i:s', $item['launch_end_time']);
+            $item['status'] = BargainLaunch::getStatusDesc($item['status']);
+            $item['goods_image'] = $item['goods_snap']['image'] == "" ? $item['goods_snap']['goods_iamge'] : $item['goods_snap']['image'];
+        }
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 砍价订单详情
+     * @param $id
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:58 上午
+     */
+    public static function getLaunchDetail($id)
+    {
+
+        $model = new BargainLaunch();
+        $detail = $model->field(true)
+            ->where(['id' => (int)$id])
+            ->with(['user.level'])
+            ->find()->toArray();
+
+        $detail['domain'] = UrlServer::getFileUrl();
+        $detail['launch_start_time'] = date('Y-m-d H:i:s', $detail['launch_start_time']);
+        $detail['launch_end_time'] = date('Y-m-d H:i:s', $detail['launch_end_time']);
+        $detail['payment_where'] = $detail['bargain_snap']['payment_where'] == 1 ? '任意金额购买' : '固定金额购买';
+        $detail['status'] = BargainLaunch::getStatusDesc($detail['status']);
+        return $detail;
+    }
+
+    /**
+     * @notes 砍价订单
+     * @param $launch_id
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:59 上午
+     */
+    public static function getKnifeOrderRecord($launch_id, $get)
+    {
+
+        $model = new BargainLaunch();
+        $count = $model->where(['id' => (int)$launch_id])
+            ->where('order_id', '>', 0)->count('id');
+        $lists = $model->field(true)
+            ->where(['id' => (int)$launch_id])
+            ->where('order_id', '>', 0)
+            ->with(['user.level', 'order'])
+            ->page($get['page'], $get['limit'])
+            ->select();
+
+        foreach ($lists as &$item) {
+            $item['user']['avatar'] = UrlServer::getFileUrl($item['user']['avatar']);
+            $item['order_status'] = Order::getOrderStatus($item['order']['order_status']);
+        }
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 砍价记录
+     * @param $launch_id
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:59 上午
+     */
+    public static function getKnifeRecord($launch_id, $get)
+    {
+
+        $model = new BargainKnife();
+
+        $count = $model->where(['launch_id' => (int)$launch_id])->count();
+        $lists = $model->field(true)
+            ->where(['launch_id' => (int)$launch_id])
+            ->with(['user.level'])
+            ->page($get['page'], $get['limit'])
+            ->select();
+
+        foreach ($lists as &$item) {
+            $item['user']['avatar'] = UrlServer::getFileUrl($item['user']['avatar']);
+            $item['help_time'] = date('Y-m-d H:i:s', $item['help_time']);
+            $item['help_price'] = '¥' . $item['help_price'];
+            $item['surplus_price'] = '¥' . $item['surplus_price'];
+        }
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 砍价详情
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 9:59 上午
+     */
+    public static function detail($get)
+    {
+
+        $where = [];
+        $where['b.id'] = $get['id'];
+        $info = Bargain::alias('b')
+            ->join('goods g', 'b.goods_id = g.id')
+            ->join('shop s', 's.id = b.shop_id')
+            ->where($where)
+            ->field('b.id,b.goods_id,b.audit_status,b.audit_remark,b.time_limit,b.payment_where,b.share_title,b.share_intro,g.image,g.name,g.min_price,g.max_price,s.id as sid,s.name as shop_name,s.type')
+            ->find()->toArray();
+
+        switch ($info['type']) {
+            case 1 :
+                $info['type'] = '官方自营';
+                break;
+            case 2 :
+                $info['type'] = '入驻商家';
+                break;
+        }
+
+        switch ($info['audit_status']) {
+            case 0 :
+                $info['audit_status'] = '待审核';
+                break;
+            case 1 :
+                $info['audit_status'] = '审核通过';
+                break;
+            case 2 :
+                $info['audit_status'] = '审核拒绝';
+                break;
+        }
+        $info['image'] = UrlServer::getFileUrl($info['image']);
+        return $info;
+    }
+
+    /**
+     * @notes 获取各列表数量
+     * @return array
+     * @author suny
+     * @date 2021/7/14 9:59 上午
+     */
+    public static function getNum()
+    {
+
+        $all = Bargain::where('del', 0)->count('id');
+        $unaudit = Bargain::where(['audit_status' => 0, 'del' => 0])->count('id');
+        $audit_pass = Bargain::where(['audit_status' => 1, 'del' => 0])->count('id');
+        $audit_refund = Bargain::where(['audit_status' => 2, 'del' => 0])->count('id');
+        $num = [
+            'all' => $all,
+            'unaudit' => $unaudit,
+            'audit_pass' => $audit_pass,
+            'audit_refund' => $audit_refund
+        ];
+        return $num;
+    }
+}

+ 191 - 0
app/admin/logic/coupon/ShopCouponLogic.php

@@ -0,0 +1,191 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+namespace app\admin\logic\coupon;
+
+use app\common\server\UrlServer;
+use app\common\basics\Logic;
+use app\common\model\coupon\Coupon;
+use app\common\model\coupon\CouponGoods;
+use app\common\model\coupon\CouponList;
+use app\common\model\user\UserLevel;
+
+
+class ShopCouponLogic extends Logic{
+    public static function lists($get)
+    {
+        $where = [
+            ['c.del','=',0]
+        ];
+
+        if(empty($get['type'])) {
+            // 已下架
+            $where[] = ['c.status', '=', '0'];
+        }else{
+            $where[] = ['c.status', '=', '1'];
+        }
+
+        // 商家名称
+        if(isset($get['shop_name']) && !empty($get['shop_name'])) {
+            $where[] = ['s.name', 'like', '%'.trim($get['shop_name']).'%' ];
+        }
+
+        // 优惠券名称
+        if(isset($get['name']) && !empty($get['name'])) {
+            $where[] = ['c.name', 'like', '%'.trim($get['name']).'%' ];
+        }
+
+        // 领取方式
+        if(isset($get['get_type']) && !empty($get['get_type'])) {
+            $where[] = ['c.get_type', '=', $get['get_type'] ];
+        }
+
+        // 创建时间
+        if(isset($get['start_time']) && !empty($get['start_time'])) {
+            $where[] = ['c.create_time', '>=', strtotime($get['start_time']) ];
+        }
+
+        if(isset($get['end_time']) && !empty($get['end_time'])) {
+            $where[] = ['c.create_time', '<=', strtotime($get['end_time']) ];
+        }
+
+        $coupon_count = Coupon::alias('c')
+            ->leftJoin('shop s', 's.id=c.shop_id')
+            ->where($where)->count();
+
+        $coupon_list = Coupon::alias('c')
+            ->leftJoin('shop s', 's.id=c.shop_id')
+            ->field('c.id,c.name,c.money,c.use_goods_type,c.use_goods_type as use_goods_type_desc,c.condition_type,c.condition_money,c.condition_type as condition_type_desc,c.send_total_type,c.send_total_type as send_total_type_desc,c.send_total,c.get_type,c.get_type as get_type_desc,c.status,c.status as statusDesc,c.send_time_start,c.send_time_end,c.send_time_start as send_time,c.use_time_type,c.use_time_start,c.use_time_end,c.use_time,c.use_time_type as use_time_desc,c.create_time,s.id as shop_id,s.name as shop_name,s.logo as shop_logo,s.type as shop_type')
+            ->where($where)
+            ->page($get['page'], $get['limit'])
+            ->order('id desc')
+            ->select()
+            ->toArray();
+
+        $shopTypeDesc = [1=>'官方自营', 2=>'入驻商家'];
+        foreach($coupon_list as &$item) {
+            $item['shop_type_desc'] = $shopTypeDesc[$item['shop_type']];
+            $item['logo'] = UrlServer::getFileUrl($item['shop_logo']);
+        }
+
+        return ['count' => $coupon_count, 'list' => $coupon_list];
+
+    }
+
+    public static function getCoupon($id,$get_data = false)
+    {
+        $coupon = Coupon::findOrEmpty($id);
+        $coupon['goods_coupon'] = [];
+        if($get_data) {
+            $coupon = $coupon->getData();
+            $coupon['send_time_start'] = date('Y-m-d H:i:s',$coupon['send_time_start']);
+            $coupon['send_time_end'] = date('Y-m-d H:i:s',$coupon['send_time_end']);
+            if($coupon['use_goods_type'] != 1){ // 非全部商品
+                $goods_coupon= CouponGoods::alias('cg')
+                    ->join('goods g','cg.goods_id = g.id')
+                    ->where(['coupon_id'=>$id])
+                    ->field('g.id,name,max_price,min_price,stock')
+                    ->select();
+                foreach ($goods_coupon as &$item){
+                    $item['price'] = '¥'.$item['min_price'].'~'.'¥'.$item['max_price'];
+                    if($item['max_price'] == $item['min_price']){
+                        $item['price'] = '¥'.$item['min_price'];
+                    }
+                }
+                $coupon['goods_coupon'] = $goods_coupon;
+            }
+            if($coupon['use_time_start']){
+                $coupon['use_time_start'] = date('Y-m-d H:i:s',$coupon['use_time_start']);
+                $coupon['use_time_end'] = date('Y-m-d H:i:s',$coupon['use_time_end']);
+            }
+        }
+
+        return $coupon;
+    }
+
+    /*
+ * 发放记录
+ */
+    public static function record($get)
+    {
+        $where[] = ['cl.del','=',0];
+        $where[] = ['cl.coupon_id','=',$get['id']];
+
+        if(isset($get['keyword']) && $get['keyword']){
+            switch($get['search_type']) {
+                case 'sn';
+                    $where[] = ['u.sn', '=', $get['keyword']];
+                    break;
+                case 'nickname';
+                    $where[] = ['u.nickname', '=', $get['keyword']];
+                    break;
+                case 'mobile';
+                    $where[] = ['u.mobile', '=', $get['keyword']];
+                    break;
+            }
+        }
+
+        if(isset($get['status']) && $get['status'] != '') {
+            $where[] = ['cl.status', '=', $get['status']];
+        }
+
+        $log_count = CouponList::alias('cl')
+            ->join('user u','cl.user_id = u.id')
+            ->where($where)
+            ->count();
+
+        $log_list = CouponList::alias('cl')
+            ->join('user u','cl.user_id = u.id')
+            ->where($where)
+            ->field('cl.coupon_id,cl.status as cl_status,coupon_code,cl.create_time as cl_create_time,cl.use_time,u.nickname,u.avatar,u.mobile,u.sn,u.level')
+            ->page($get['page'], $get['limit'])
+            ->select();
+
+        $coupon = Coupon::find($get['id']);
+        $coupon_list = Coupon::where(['del'=>0])->column('name','id');
+        $level_name =  UserLevel::where(['del'=>0])->column('name','id');
+
+        foreach ($log_list as &$item)
+        {
+            // 计算过期时间
+            switch($coupon->use_time_type) {
+                case 1:
+                    $item['expired_time_desc'] = date('Y-m-d H:i:s', $coupon['use_time_end']);
+                    break;
+                case 2: // 领券当天起
+                    $datatime = '+'.$coupon['use_time']. ' day';
+                    $expired_time = strtotime($datatime, $item['cl_create_time']);
+                    $item['expired_time_desc'] = date('Y-m-d H:i:s', $expired_time);
+                    break;
+                case 3: // 领券次日起
+                    $datatime = '+'.($coupon['use_time'] + 1). ' day';
+                    $expired_time = strtotime($datatime, $item['cl_create_time']);
+                    $item['expired_time_desc'] = date('Y-m-d H:i:s', $expired_time);
+                    break;
+            }
+
+            $item['coupon_name'] = $coupon_list[$item['coupon_id']] ?? '';
+            $item['avatar'] = UrlServer::getFileUrl($item['avatar']);
+            $item['level_name'] = $level_name[$item['level']] ?? '';
+            $item['status_desc'] = $item['cl_status'] ? '已使用' : '未使用';
+            $item['cl_create_time'] = date('Y-m-d H:i:s',$item['cl_create_time']);
+            $item['use_time_desc'] = $item['use_time'] ? date('Y-m-d H:i:s',$item['use_time']) : '';
+        }
+        return ['count'=>$log_count , 'lists'=>$log_list];
+    }
+}

+ 143 - 0
app/admin/logic/distribution/ApplyLogic.php

@@ -0,0 +1,143 @@
+<?php
+
+
+namespace app\admin\logic\distribution;
+
+
+use app\common\basics\Logic;
+use app\common\logic\DistributionLogic;
+use app\common\model\distribution\Distribution;
+use app\common\model\distribution\DistributionMemberApply;
+use app\common\model\user\User;
+use app\common\server\AreaServer;
+use app\common\server\UrlServer;
+use think\facade\Db;
+
+class ApplyLogic extends Logic
+{
+    /**
+     * @Notes: 分销申请列表
+     * @Author: 张无忌
+     * @param $get
+     * @return array
+     */
+    public static function lists($get)
+    {
+        try {
+            $where[] = ['DMA.status', '=', $get['type'] ?? 0];
+            $where[] = ['U.user_delete', '=', 0];
+            if (!empty($get['keyword']) and $get['keyword']) {
+                switch ($get['keyword_type']) {
+                    case 'sn':
+                        $where[] = ['U.sn', 'like', '%'.$get['keyword'].'%'];
+                        break;
+                    case 'nickname':
+                        $where[] = ['U.nickname', 'like', '%'.$get['keyword'].'%'];
+                        break;
+                    case 'mobile':
+                        $where[] = ['U.mobile', '=', $get['keyword']];
+                        break;
+                }
+            }
+
+            $model = new DistributionMemberApply();
+            $lists = $model->field(['DMA.*'])->alias('DMA')
+                ->where($where)
+                ->with(['user.level'])
+                ->join('user U', 'U.id = DMA.user_id')
+                ->paginate([
+                    'page'      => $get['page'],
+                    'list_rows' => $get['limit'],
+                    'var_page' => 'page'
+                ])->toArray();
+
+            foreach ($lists['data'] as &$item) {
+                if ($item['user']) {
+                    $item['user']['avatar'] = UrlServer::getFileUrl($item['user']['avatar']);
+                }
+                $item['region'] = AreaServer::getAddress([
+                    $item['province'],
+                    $item['city'],
+                    $item['district']]
+                );
+            }
+
+            return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+        } catch (\Exception $e) {
+            return ['error'=>$e->getMessage()];
+        }
+    }
+
+    /**
+     * @Notes: 分销申请详细
+     * @Author: 张无忌
+     * @param $id
+     * @return array
+     */
+    public static function detail($id)
+    {
+        $model = new DistributionMemberApply();
+        $detail = $model->field(true)
+            ->with(['user.level'])
+            ->findOrEmpty($id)
+            ->toArray();
+
+        $detail['status_text'] = DistributionMemberApply::getApplyStatus($detail['status']);
+        $detail['region'] = AreaServer::getAddress([
+                $detail['province'],
+                $detail['city'],
+                $detail['district']]
+        );
+
+        return $detail;
+    }
+
+    /**
+     * @Notes: 审核分销申请
+     * @Author: 张无忌
+     * @param $post
+     * @return bool
+     */
+    public static function audit($post)
+    {
+        Db::startTrans();
+        try {
+            if ($post['audit_status'] == 1) {
+                // 审核通过
+                $model = new DistributionMemberApply();
+                $apply = $model->field(true)->findOrEmpty((int)$post['id'])->toArray();
+
+                DistributionMemberApply::update([
+                    'status'        => $post['audit_status'],
+                    'denial_reason' => $post['denial_reason'] ?? '',
+                    'update_time'   => time()
+                ], ['id'=>(int)$post['id']]);
+
+                $distribution = Distribution::where('user_id', $apply['user_id'])->findOrEmpty()->toArray();
+                if (empty($distribution)) {
+                    // 生成分销基础信息表
+                    DistributionLogic::add($apply['user_id']);
+                }
+                // 更新分销基础信息表
+                Distribution::where('user_id', $apply['user_id'])->update([
+                    'is_distribution' => 1,
+                    'distribution_time' => time()
+                ]);
+            } else {
+                // 审核拒绝
+                DistributionMemberApply::update([
+                    'status'        => $post['audit_status'],
+                    'denial_reason' => $post['denial_reason'] ?? '',
+                    'update_time'   => time()
+                ], ['id'=>(int)$post['id']]);
+            }
+
+            Db::commit();
+            return true;
+        } catch (\Exception $e) {
+            Db::rollback();
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+}

+ 143 - 0
app/admin/logic/distribution/CenterLogic.php

@@ -0,0 +1,143 @@
+<?php
+namespace app\admin\logic\distribution;
+
+use app\common\basics\Logic;
+use app\common\model\distribution\Distribution;
+use app\common\model\distribution\DistributionOrderGoods;
+use app\common\server\UrlServer;
+
+class CenterLogic extends Logic
+{
+    /**
+     * @notes 数据概览
+     * @return array
+     * @author Tab
+     * @date 2021/9/6 14:40
+     */
+    public static function center()
+    {
+        $data = [
+            'earnings' => self::earnings(),
+            'members' => self::members(),
+            'topGoods' => self::topGoods(),
+            'topMembers' => self::topMembers(),
+        ];
+
+        return $data;
+    }
+
+    /**
+     * @notes 佣金数据
+     * @return array
+     * @author Tab
+     * @date 2021/9/6 14:46
+     */
+    public static function earnings()
+    {
+        // 累计已入账佣金
+        $totalSuccess = DistributionOrderGoods::where([
+            'status' => 2,
+        ])->sum('money');
+        // 今日已入账佣金
+        $totalTodaySuccess = DistributionOrderGoods::where([
+            'status' => 2,
+        ])->whereDay('settlement_time')->sum('money');
+        // 累计待结算佣金
+        $totalWait = DistributionOrderGoods::where([
+            'status' => 1,
+        ])->sum('money');
+        // 今日待结算佣金
+        $totalTodayWait = DistributionOrderGoods::where([
+            'status' => 1,
+        ])->whereDay('create_time')->sum('money');
+
+        return [
+            'total_success' => $totalSuccess,
+            'total_today_success' => $totalTodaySuccess,
+            'total_wait' => $totalWait,
+            'total_today_wait' => $totalTodayWait,
+        ];
+    }
+
+    /**
+     * @notes 分销会员数据
+     * @author Tab
+     * @date 2021/9/6 14:57
+     */
+    public static function members()
+    {
+        $members = Distribution::where('is_distribution', 1)->count();
+        $users = Distribution::count();
+        $proportion = 0;
+        if ($users) {
+            $proportion = round(($members / $users), 2) * 100;
+        }
+
+
+        return [
+            'members' => $members,
+            'proportion' => $proportion,
+        ];
+    }
+
+    /**
+     * @notes 分销商品排行榜
+     * @author Tab
+     * @date 2021/9/6 14:59
+     */
+    public static function topGoods()
+    {
+        $field = [
+            'sum(dog.money)' => 'total_money',
+            'og.image' => 'goods_image',
+            'og.goods_name',
+        ];
+        $where = [
+            'dog.status' => 2, // 已入账
+        ];
+        $topGoods = DistributionOrderGoods::alias('dog')
+            ->leftJoin('order_goods og', 'og.id = dog.order_goods_id')
+            ->field($field)
+            ->where($where)
+            ->group('dog.money,og.image,og.goods_name')
+            ->order('total_money', 'desc')
+            ->limit(10)
+            ->select()
+            ->toArray();
+
+        return $topGoods;
+    }
+
+    /**
+     * @notes 分销会员排行榜
+     * @return mixed
+     * @author Tab
+     * @date 2021/9/6 15:01
+     */
+    public static function topMembers()
+    {
+        $field = [
+            'sum(dog.money)' => 'total_money',
+            'u.avatar',
+            'u.nickname',
+        ];
+        $where = [
+            'dog.status' => 2, // 已入账
+        ];
+        $topMembers = DistributionOrderGoods::alias('dog')
+            ->leftJoin('user u', 'u.id = dog.user_id')
+            ->field($field)
+            ->where($where)
+            ->group('dog.money,u.avatar,u.nickname')
+            ->order('total_money', 'desc')
+            ->limit(10)
+            ->select()
+            ->toArray();
+
+        foreach($topMembers as &$item) {
+            $item['avatar'] = empty($item['avatar']) ? '' : UrlServer::getFileUrl($item['avatar']);
+        }
+
+        return $topMembers;
+    }
+}

+ 169 - 0
app/admin/logic/distribution/DistributionGoodsLogic.php

@@ -0,0 +1,169 @@
+<?php
+namespace app\admin\logic\distribution;
+
+use app\common\basics\Logic;
+use app\common\model\distribution\DistributionGoods;
+use app\common\model\distribution\DistributionLevel;
+use app\common\model\goods\Goods;
+
+class DistributionGoodsLogic extends Logic
+{
+    /**
+     * @notes 分销商品列表
+     * @param $params
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author Tab
+     * @date 2021/9/2 17:41
+     */
+    public static function lists($params)
+    {
+        $where = [
+            ['del', '<>', '1'],
+        ];
+        // 商品信息
+        if (isset($params['keyword']) && !empty($params['keyword'])) {
+            $where[] = ['name|code', 'like', '%'. $params['keyword']. '%'];
+        }
+        // 平台商品分类
+        if (isset($params['platform_cate_id']) && $params['platform_cate_id'] != 'all') {
+            $where[] = ['first_cate_id|second_cate_id|third_cate_id', '=', $params['platform_cate_id']];
+        }
+
+        $field = [
+            'id',
+            'code',
+            'name',
+            'image',
+            'max_price',
+            'min_price',
+            'id' => 'distribution_flag',
+            'shop_id',
+        ];
+        $lists = Goods::with(['Shop'])
+            ->field($field)
+            ->where($where)
+            ->withSearch('is_distribution', ["is_distribution" => 1])
+            ->page($params['page'], $params['limit'])
+            ->order([
+                'shop_id' => 'desc',
+                'id' => 'desc'
+            ])
+            ->select()
+            ->toArray();
+
+        $count = Goods::field($field)
+            ->where($where)
+            ->withSearch('is_distribution', ["is_distribution" => 1])
+            ->count();
+
+        return [
+            'count' => $count,
+            'lists' => $lists
+        ];
+    }
+
+    /**
+     * @notes 商品详情
+     * @param $params
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author Tab
+     * @date 2021/9/1 19:59
+     */
+    public static function detail($params)
+    {
+        // 商品信息
+        $goods = Goods::field('id,code,name')->with('goods_item')->findOrEmpty($params['id'])->toArray();
+        // 分销等级信息
+        $distributionLevelLists = DistributionLevel::order('weights', 'asc')->select()->toArray();
+        // 商品分销信息
+        $distributionGoods = DistributionGoods::where('goods_id', $params['id'])->select()->toArray();
+        if(empty($distributionGoods)) {
+            // 未参与分销
+            $goods['is_distribution'] = 0;
+            $goods['rule'] = 1;
+            $ratio = self::formatLevel($distributionLevelLists, $goods);
+        } else {
+            $goods['is_distribution'] = $distributionGoods[0]['is_distribution'];
+            $goods['rule'] = $distributionGoods[0]['rule'];
+            if($distributionGoods[0]['rule'] == 1) {
+                $ratio = self::formatLevel($distributionLevelLists, $goods);
+            } else {
+                $ratio = self::formatGoods($distributionLevelLists, $goods);
+            }
+        }
+
+        return [
+            'goods' => $goods,
+            'ratio' => $ratio
+        ];
+    }
+
+    /**
+     * @notes 拼装分销等级佣金比例
+     * @param $distributionLevelLists
+     * @param $goods
+     * @return array
+     * @author Tab
+     * @date 2021/9/1 19:44
+     */
+    public static function formatLevel($distributionLevelLists, $goods)
+    {
+        $ratio = [];
+        foreach($distributionLevelLists as $level) {
+            foreach($goods['goods_item'] as $item) {
+                $temp = [
+                    'level_id' => $level['id'],
+                    'level_name' => $level['name'],
+                    'first_ratio' => $level['first_ratio'],
+                    'second_ratio' => $level['second_ratio'],
+                    'goods_id' => $item['goods_id'],
+                    'item_id' => $item['id'],
+                    'spec_value_str' => $item['spec_value_str'],
+                    'price' => $item['price']
+                ];
+                $ratio[] = $temp;
+            }
+        }
+        return $ratio;
+    }
+
+    /**
+     * @notes 拼装单独设置的佣金比例
+     * @param $distributionLevelLists
+     * @param $goods
+     * @param $distributionGoods
+     * @return array
+     * @author Tab
+     * @date 2021/9/2 9:28
+     */
+    public static function formatGoods($distributionLevelLists, $goods)
+    {
+        $ratio = [];
+        foreach($distributionLevelLists as $level) {
+            foreach($goods['goods_item'] as $item) {
+                $record = DistributionGoods::where([
+                    'level_id' => $level['id'],
+                    'item_id' =>  $item['id'],
+                ])->findOrEmpty()->toArray();
+                $temp = [
+                    'level_id' => $level['id'],
+                    'level_name' => $level['name'],
+                    'first_ratio' => $record['first_ratio'],
+                    'second_ratio' => $record['second_ratio'],
+                    'goods_id' => $item['goods_id'],
+                    'item_id' => $item['id'],
+                    'spec_value_str' => $item['spec_value_str'],
+                    'price' => $item['price']
+                ];
+                $ratio[] = $temp;
+            }
+        }
+        return $ratio;
+    }
+}

+ 514 - 0
app/admin/logic/distribution/DistributionLevelLogic.php

@@ -0,0 +1,514 @@
+<?php
+namespace app\admin\logic\distribution;
+
+use app\common\basics\Logic;
+use app\common\model\distribution\Distribution;
+use app\common\model\distribution\DistributionGoods;
+use app\common\model\distribution\DistributionLevel;
+use app\common\model\distribution\DistributionLevelUpdate;
+use app\common\model\distribution\DistributionOrderGoods;
+use app\common\model\order\Order;
+use app\common\model\order\OrderTrade;
+use think\facade\Db;
+
+class DistributionLevelLogic extends Logic
+{
+    /**
+     * @notes 分销等级列表
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author Tab
+     * @date 2021/9/1 16:19
+     */
+    public static function index()
+    {
+        $field = [
+            'id',
+            'name',
+            'weights' => 'weights_desc',
+            'first_ratio',
+            'second_ratio',
+            'is_default',
+            'id' => 'members_num'
+        ];
+        $lists = DistributionLevel::field($field)
+            ->order('weights', 'asc')
+            ->select()
+            ->toArray();
+
+        $count = DistributionLevel::count();
+
+        return [
+            'count' => $count,
+            'lists' => $lists,
+        ];
+    }
+
+    /**
+     * @notes 添加分销会员等级
+     * @param $params
+     * @return bool
+     * @author Tab
+     * @date 2021/9/1 14:53
+     */
+    public static function add($params)
+    {
+        Db::startTrans();
+        try{
+            // 写入等级主表
+            $params['remark'] = $params['remark'] ?? '';
+            // 佣金比例保留两位小数
+            $params['first_ratio'] = !empty($params['first_ratio']) ? round($params['first_ratio'], 2) : 0;
+            $params['second_ratio'] = !empty($params['second_ratio']) ? round($params['second_ratio'], 2) : 0;
+            $newLevel = DistributionLevel::create($params);
+
+            // 写入升级条件表
+            self::addUpdateCondition($params, $newLevel->id);
+
+            // 处理分销商品比例
+            self::updateDistributionGoods($newLevel->id);
+
+            Db::commit();
+            return true;
+        }catch(\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @notes 添加更新升级条件
+     * @param $params
+     * @param $level_id
+     * @throws \Exception
+     * @author Tab
+     * @date 2021/9/1 15:08
+     */
+    public static function addUpdateCondition($params, $level_id)
+    {
+        $updateConditionData = [];
+        foreach($params['update_condition'] as $key) {
+            // 判断是否在规定的条件字段
+            if(!in_array($key, DistributionLevel::UPDATE_CONDITION_FIELDS, true)) {
+                continue;
+            }
+            if ($params[$key] < 0) {
+                throw new \Exception('升级条件不允许小于0');
+            }
+            // 获取键对应值的字段名
+            $valueField = DistributionLevel::getValueFiled($key);
+            $updateConditionData[] = [
+                'level_id' => $level_id,
+                'key' => $key,
+                $valueField => $params[$key]
+            ];
+        }
+        (new DistributionLevelUpdate())->saveAll($updateConditionData);
+    }
+
+    /**
+     * @notes 获取分销等级详情
+     * @param $params
+     * @return array
+     * @author Tab
+     * @date 2021/9/1 15:36
+     */
+    public static function detail($params)
+    {
+        $level = DistributionLevel::withoutField('create_time,update_time,delete_time')->findOrEmpty($params['id']);
+        if($level->isEmpty()) {
+            return [];
+        }
+        $level = $level->toArray();
+        // 默认等级
+        if($level['is_default']) {
+            unset($level['self_ratio']);
+            unset($level['third_ratio']);
+            unset($level['update_relation']);
+            return $level;
+        }
+        // 自定义等级
+        $level['update_condition'] = self::getUpdateCondition($level);
+        unset($level['self_ratio']);
+        unset($level['third_ratio']);
+
+        return $level;
+    }
+
+    /**
+     * @notes 获取升级条件
+     * @param $level
+     * @return array
+     * @author Tab
+     * @date 2021/9/1 15:36
+     */
+    public static function getUpdateCondition($level)
+    {
+        $updateCondition = DistributionLevelUpdate::where('level_id', $level['id'])->column('key,value_int,value_decimal,value_text');
+        $updateConditionData = [];
+        foreach($updateCondition as $item) {
+            if($item['value_int']) {
+                $updateConditionData[$item['key']] = $item['value_int'];
+                continue;
+            }
+            if($item['value_decimal']) {
+                $updateConditionData[$item['key']] = $item['value_decimal'];
+                continue;
+            }
+            if($item['value_text']) {
+                $updateConditionData[$item['key']] = $item['value_text'];
+                continue;
+            }
+        }
+        $data = [
+            'keys' => array_keys($updateConditionData),
+            'data' => $updateConditionData
+        ];
+        // 补全条件
+        foreach(DistributionLevel::UPDATE_CONDITION_FIELDS as $field) {
+            if(!isset($data['data'][$field])) {
+                $data['data'][$field] =  '';
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * @notes 编辑分销等级
+     * @param $params
+     * @return bool
+     * @author Tab
+     * @date 2021/9/1 16:20
+     */
+    public static function edit($params)
+    {
+        Db::startTrans();
+        try{
+            $params['remark'] = $params['remark'] ?? '';
+            $level = DistributionLevel::findOrEmpty($params['id']);
+            if($level->isEmpty()) {
+                throw new \Exception('等级不存在');
+            }
+
+            // 佣金比例保留两位小数
+            $params['first_ratio'] = !empty($params['first_ratio']) ? round($params['first_ratio'], 2) : 0;
+            $params['second_ratio'] = !empty($params['second_ratio']) ? round($params['second_ratio'], 2) : 0;
+
+            // 默认等级
+            if($level->is_default) {
+                $level->allowField(['name', 'first_ratio', 'second_ratio','remark'])->save($params);
+                Db::commit();
+                return true;
+            }
+            // 自定义等级 - 更新主表信息
+            if(!$params['weights'] > 1) {
+                throw new \Exception('级别须大于1');
+            }
+            if(!isset($params['update_relation'])) {
+                throw new \Exception('请选择升级关系');
+            }
+            if(!isset($params['update_condition']) || !count($params['update_condition'])) {
+                throw new \Exception('请选择升级条件');
+            }
+            $level->allowField(['name', 'weights', 'first_ratio', 'second_ratio','remark', 'update_relation'])->save($params);
+
+            // 自定义等级 - 删除旧升级条件
+            $deleteIds = DistributionLevelUpdate::where('level_id', $level->id)->column('id');
+            DistributionLevelUpdate::destroy($deleteIds);
+
+            // 自定义等级 - 添加新的升级条件
+            self::addUpdateCondition($params, $level->id);
+
+            Db::commit();
+            return true;
+        }catch(\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @notes 删除分销等级
+     * @param $params
+     * @return bool
+     * @author Tab
+     * @date 2021/9/1 16:21
+     */
+    public static function delete($params)
+    {
+        Db::startTrans();
+        try{
+            $level = DistributionLevel::findOrEmpty($params['id']);
+            if($level->isEmpty()) {
+                throw new \Exception('等级不存在');
+            }
+            if($level->is_default) {
+                throw new \Exception('系统默认等级不允许删除');
+            }
+
+            // 重置该等级下的分销会员为系统默认等级
+            $defaultId = DistributionLevel::where('is_default', 1)->value('id');
+            Distribution::where('level_id', $level->id)->update(['level_id' => $defaultId]);
+
+            // 删除升级条件
+            $deleteIds = DistributionLevelUpdate::where('level_id', $level->id)->column('id');
+            DistributionLevelUpdate::destroy($deleteIds);
+
+            // 删除该等级下的分销商品比例
+            $deleteIds = DistributionGoods::where('level_id', $level->id)->column('id');
+            DistributionGoods::destroy($deleteIds);
+
+            // 删除等级
+            $level->delete();
+
+            Db::commit();
+            return true;
+        }catch(\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @notes 更新分销会员等级
+     * @param $userId
+     * @return false
+     * @author Tab
+     * @date 2021/9/2 16:39
+     */
+    public static function updateDistributionLevel($userId)
+    {
+        // 非默认等级
+        $levels = DistributionLevel::where('is_default', 0)
+            ->order('weights', 'desc')
+            ->column('id,name,weights,update_relation', 'id');
+
+        $userInfo = Distribution::alias('d')
+            ->leftJoin('distribution_level dl', 'dl.id = d.level_id')
+            ->field('d.is_distribution,d.level_id,dl.weights')
+            ->where('d.user_id', $userId)
+            ->findOrEmpty()
+            ->toArray();
+
+        // 非分销会员直接返回false
+        if(empty($userInfo) || !$userInfo['is_distribution']) {
+            return false;
+        }
+
+        foreach($levels as $level) {
+            if(self::isMeetConditions($userId, $level) && $level['weights'] > $userInfo['weights']) {
+                // 满足升级条件且是升更高的等级
+                Distribution::where(['user_id' => $userId])->update(['level_id' => $level['id']]);
+                break;
+            }
+        }
+    }
+
+    /**
+     * @notes 判断是否满足当前等级的升级条件
+     * @param $userId
+     * @param $level
+     * @return bool
+     * @author Tab
+     * @date 2021/9/2 16:42
+     */
+    public static function isMeetConditions($userId, $level)
+    {
+        $updateRelation = $level['update_relation'];
+        // 任一条件满足升级
+        if($updateRelation == 1) {
+            $flagOr = self::singleConsumptionAmountFlag($userId, $level, $updateRelation)
+                || self::cumulativeConsumptionAmountFlag($userId, $level, $updateRelation)
+                || self::cumulativeConsumptionTimesFlag($userId, $level, $updateRelation)
+                || self::returnedCommissionFlag($userId, $level, $updateRelation);
+            return $flagOr;
+        }
+
+        // 全部条件满足升级
+        if($updateRelation == 2) {
+            $flagAnd = self::singleConsumptionAmountFlag($userId, $level, $updateRelation)
+                && self::cumulativeConsumptionAmountFlag($userId, $level, $updateRelation)
+                && self::cumulativeConsumptionTimesFlag($userId, $level, $updateRelation)
+                && self::returnedCommissionFlag($userId, $level, $updateRelation);
+            return $flagAnd;
+        }
+    }
+
+    /**
+     * @notes 判断是否满足单笔消费金额条件
+     * @param $userId
+     * @param $level
+     * @return bool
+     * @author Tab
+     * @date 2021/9/2 16:44
+     */
+    public static function singleConsumptionAmountFlag($userId, $level, $updateRelation)
+    {
+        $condition = DistributionLevelUpdate::field('value_int,value_decimal,value_text')
+            ->where([
+                'level_id' => $level['id'],
+                'key' => 'singleConsumptionAmount'
+            ])
+            ->findOrEmpty();
+        if($condition->isEmpty()) {
+            // 等级条件为满足任一条件(updateRelation=1)  返回false (满足已设置的任一条件时才升级,未设置的条件归为未满足,返回false)
+            // 等级条件为满足全部条件(updateRelation=2)  返回true  (满足已设置的所有条件时才升级,未设置的条件归为已满足,返回true)
+            return $updateRelation == 2;
+        }
+        $recentOrder = Order::where([
+            'user_id' =>  $userId,
+            'pay_status' => 1
+        ])
+            ->order('id', 'desc')
+            ->findOrEmpty();
+        if($recentOrder->isEmpty()) {
+            return false;
+        }
+        $singleConsumptionAmount = OrderTrade::where('id', $recentOrder['trade_id'])->findOrEmpty()->toArray();
+        if($singleConsumptionAmount['order_amount'] >= $condition['value_decimal']) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @notes 判断是否满足累计消费金额条件
+     * @param $userId
+     * @param $level
+     * @return bool
+     * @author Tab
+     * @date 2021/9/2 16:50
+     */
+    public static function cumulativeConsumptionAmountFlag($userId, $level, $updateRelation)
+    {
+        $condition = DistributionLevelUpdate::field('value_int,value_decimal,value_text')
+            ->where([
+                'level_id' => $level['id'],
+                'key' => 'cumulativeConsumptionAmount'
+            ])
+            ->findOrEmpty();
+        if($condition->isEmpty()) {
+            // 等级条件为满足任一条件(updateRelation=1)  返回false (满足已设置的任一条件时才升级,未设置的条件归为未满足,返回false)
+            // 等级条件为满足全部条件(updateRelation=2)  返回true  (满足已设置的所有条件时才升级,未设置的条件归为已满足,返回true)
+            return $updateRelation == 2;
+        }
+        $cumulativeConsumptionAmount = Order::where([
+            'user_id' =>  $userId,
+            'pay_status' => 1
+        ])->sum('order_amount');
+        if($cumulativeConsumptionAmount >= $condition['value_decimal']) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @notes 判断是否满足累计消费次数条件
+     * @param $userId
+     * @param $level
+     * @return bool
+     * @author Tab
+     * @date 2021/9/2 16:53
+     */
+    public static function cumulativeConsumptionTimesFlag($userId, $level, $updateRelation)
+    {
+        $condition = DistributionLevelUpdate::field('value_int,value_decimal,value_text')
+            ->where([
+                'level_id' => $level['id'],
+                'key' => 'cumulativeConsumptionTimes'
+            ])
+            ->findOrEmpty();
+        if($condition->isEmpty()) {
+            // 等级条件为满足任一条件(updateRelation=1)  返回false (满足已设置的任一条件时才升级,未设置的条件归为未满足,返回false)
+            // 等级条件为满足全部条件(updateRelation=2)  返回true  (满足已设置的所有条件时才升级,未设置的条件归为已满足,返回true)
+            return $updateRelation == 2;
+        }
+        $allTradeIds = Order::where([
+            'user_id' =>  $userId,
+            'pay_status' => 1
+        ])->column('trade_id');
+        $cumulativeConsumptionTimes = count(array_unique($allTradeIds));
+        if($cumulativeConsumptionTimes >= $condition['value_int']) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @notes 判断是否消费已返佣金条件
+     * @param $userId
+     * @param $level
+     * @return bool
+     * @author Tab
+     * @date 2021/9/2 17:06
+     */
+    public static function returnedCommissionFlag($userId, $level, $updateRelation)
+    {
+        $condition = DistributionLevelUpdate::field('value_int,value_decimal,value_text')
+            ->where([
+                'level_id' => $level['id'],
+                'key' => 'returnedCommission'
+            ])
+            ->findOrEmpty();
+        if($condition->isEmpty()) {
+            // 等级条件为满足任一条件(updateRelation=1)  返回false (满足已设置的任一条件时才升级,未设置的条件归为未满足,返回false)
+            // 等级条件为满足全部条件(updateRelation=2)  返回true  (满足已设置的所有条件时才升级,未设置的条件归为已满足,返回true)
+            return $updateRelation == 2;
+        }
+        $returnedCommission = DistributionOrderGoods::where([
+            'user_id' => $userId,
+            'status' => 2
+        ])->sum('money');
+        if($returnedCommission >= $condition['value_decimal']) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @notes 获取所有分销会员等级
+     * @return array
+     * @author Tab
+     * @date 2021/9/2 18:31
+     */
+    public static function getLevels()
+    {
+        return DistributionLevel::order('weights', 'asc')->column('id, name,weights');
+    }
+
+    /**
+     * @notes 更新分销商品比例
+     * @param $levelId
+     * @author Tab
+     * @date 2021/9/7 17:27
+     */
+    public static function updateDistributionGoods($levelId)
+    {
+        // 处理单独设置比例的商品,新增分销会等级佣金比例初始化为0
+        $field = [
+            'shop_id',
+            'goods_id',
+            'item_id',
+        ];
+       $distribution = DistributionGoods::distinct(true)->field($field)->where('rule', 2)->select()->toArray();
+       $addData = [];
+       foreach($distribution as $item) {
+            $temp = [
+                'shop_id' => $item['shop_id'],
+                'goods_id' => $item['goods_id'],
+                'item_id' => $item['item_id'],
+                'level_id' => $levelId,
+                'first_ratio' => 0,
+                'second_ratio' => 0,
+                'rule' => 2,
+            ];
+            $addData[] = $temp;
+       }
+        (new  DistributionGoods())->saveAll($addData);
+    }
+}

+ 231 - 0
app/admin/logic/distribution/DistributionMemberLogic.php

@@ -0,0 +1,231 @@
+<?php
+namespace app\admin\logic\distribution;
+
+use app\common\basics\Logic;
+use app\common\model\distribution\Distribution;
+use app\common\model\distribution\DistributionLevel;
+use app\common\model\distribution\DistributionOrderGoods;
+use app\common\model\user\User;
+use app\common\server\UrlServer;
+
+/**
+ * 分销会员逻辑层
+ * Class DistributionMemberLogic
+ * @package app\admin\logic\distribution
+ */
+class DistributionMemberLogic extends Logic
+{
+    /**
+     * @notes 分销会员列表
+     * @param $params
+     * @return array
+     * @author Tab
+     * @date 2021/9/2 18:44
+     */
+    public static function lists($params)
+    {
+        $where = [
+            ['d.is_distribution', '=', 1]
+        ];
+        // 用户信息
+        if (isset($params['keyword']) && !empty($params['keyword'])) {
+            $where[] = ['u.sn|u.nickname', 'like', '%'. $params['keyword'] .'%'];
+        }
+        // 分销等级
+        if (isset($params['level_id']) && $params['level_id'] != 'all') {
+            $where[] = ['d.id', '=', $params['level_id']];
+        }
+        // 分销状态
+        if (isset($params['is_freeze']) && $params['is_freeze'] != 'all') {
+            $where[] = ['d.is_freeze', '=', $params['is_freeze']];
+        }
+
+        $field = [
+            'u.id' => 'user_id',
+            'u.sn' => 'user_sn',
+            'u.avatar',
+            'u.nickname',
+            'u.user_delete',
+            'dl.id' => 'level_id',
+            'dl.weights',
+            'dl.name' => 'level_name',
+            'd.is_freeze',
+            'd.distribution_time',
+        ];
+        $lists = Distribution::alias('d')
+            ->leftJoin('user u', 'u.id = d.user_id')
+            ->leftJoin('distribution_level dl', 'dl.id = d.level_id')
+            ->field($field)
+            ->where($where)
+            ->order('u.id', 'desc')
+            ->page($params['page'], $params['limit'])
+            ->select()
+            ->toArray();
+
+        $count = Distribution::alias('d')
+            ->leftJoin('user u', 'u.id = d.user_id')
+            ->leftJoin('distribution_level dl', 'dl.id = d.level_id')
+            ->field($field)
+            ->where($where)
+            ->count();
+
+        foreach($lists as &$item) {
+            $item['avatar'] = empty($item['avatar']) ? '' : UrlServer::getFileUrl($item['avatar']);
+            $item['earnings'] = DistributionOrderGoods::getEarnings($item['user_id']);
+        }
+
+        return [
+            'count' => $count,
+            'lists' => $lists
+        ];
+    }
+
+    /**
+     * @notes 用户列表
+     * @param $params
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author Tab
+     * @date 2021/9/3 9:55
+     */
+    public static function getUserLists($params)
+    {
+        $where[] = ['del', '=', 0];
+        $where[] = ['user_delete', '=', 0];
+        // 用户信息
+        if (isset($params['keyword']) && !empty($params['keyword'])) {
+            $where[] = ['sn|nickname', 'like', '%'. $params['keyword'] .'%'];
+        }
+
+        $lists = User::field('id,sn,nickname,id as distribution')
+            ->where($where)
+            ->withSearch(['distribution'], $params)
+            ->page($params['page'], $params['limit'])
+            ->select()
+            ->toArray();
+        $count = User::where($where)->withSearch(['distribution'], $params)->count();
+
+        return [
+            'count' => $count,
+            'lists' => $lists,
+        ];
+    }
+
+    /**
+     * @notes 开通分销会员
+     * @param $params
+     * @return bool
+     * @author Tab
+     * @date 2021/9/3 11:09
+     */
+    public  static function open($params)
+    {
+        try {
+            $user = User::where('id', $params['user_id'])->findOrEmpty()->toArray();
+            if(empty($user)) {
+                throw new \Exception('用户不存在');
+            }
+            if (User::UserIsDelete($params['user_id'])) {
+                throw new \Exception('用户已注销');
+            }
+            $distribution = Distribution::where('user_id', $params['user_id'])->findOrEmpty()->toArray();
+            if(!empty($distribution) && $distribution['is_distribution'] == 1) {
+                throw new \Exception('用户已是分销会员');
+            }
+            if(!empty($distribution) && $distribution['is_distribution'] == 0) {
+                Distribution::where('user_id', $params['user_id'])->update([
+                    'is_distribution'   => 1,
+                    'distribution_time' => time(),
+                    'level_id'          => $params['level_id'],
+                ]);
+            }
+            if(empty($distribution)) {
+                $data = [
+                    'user_id' => $params['user_id'],
+                    'level_id' => $params['level_id'],
+                    'is_distribution' => 1,
+                    'is_freeze' => 0,
+                    'remark' => '后台开通分销',
+                    'distribution_time' => time()
+                ];
+
+                Distribution::create($data);
+            }
+
+            return true;
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function getUser($params)
+    {
+        $field = [
+            'u.id' => 'user_id',
+            'u.sn' => 'user_sn',
+            'u.nickname' => 'user_nickname',
+            'dl.name' => 'level_name',
+            'dl.weights',
+        ];
+        $info = Distribution::alias('d')
+            ->leftJoin('user u', 'u.id = d.user_id')
+            ->leftJoin('distribution_level dl', 'dl.id = d.level_id')
+            ->field($field)
+            ->where('d.user_id', $params['id'])
+            ->findOrEmpty()
+            ->toArray();
+
+        return $info;
+    }
+
+    /**
+     * @notes 分销会员等级调整
+     * @param $params
+     * @return bool
+     * @author Tab
+     * @date 2021/9/3 14:14
+     */
+    public static function adjust($params)
+    {
+        try {
+            if (User::UserIsDelete($params['user_id'])) {
+                throw new \Exception('用户已注销');
+            }
+            Distribution::where(['user_id' => $params['user_id']])->update([
+                'level_id' => $params['level_id']
+            ]);
+
+            return true;
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @notes 冻结资格/恢复资格
+     * @param $params
+     * @return bool
+     * @author Tab
+     * @date 2021/9/3 14:24
+     */
+    public static function isFreeze($params)
+    {
+        try {
+            if (User::UserIsDelete($params['user_id'])) {
+                throw new \Exception('用户已注销');
+            }
+            Distribution::where(['user_id' => $params['user_id']])->update([
+                'is_freeze' => $params['is_freeze']
+            ]);
+
+            return true;
+        } catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+}

+ 110 - 0
app/admin/logic/distribution/DistributionOrderLogic.php

@@ -0,0 +1,110 @@
+<?php
+namespace app\admin\logic\distribution;
+
+use app\common\basics\Logic;
+use app\common\model\distribution\DistributionLevel;
+use app\common\model\distribution\DistributionOrderGoods;
+use app\common\model\user\User;
+use app\common\server\UrlServer;
+
+class DistributionOrderLogic extends Logic
+{
+    /**
+     * @notes 分销订单列表
+     * @param $params
+     * @return int[]
+     * @author Tab
+     * @date 2021/9/3 14:53
+     */
+    public static function lists($params)
+    {
+        $where= [];
+        // 订单信息
+        if (isset($params['order_keyword']) && !empty($params['order_keyword'])) {
+            $where[] = ['o.order_sn', '=', $params['order_keyword']];
+        }
+        // 商品名称
+        if (isset($params['goods_keyword']) && !empty($params['goods_keyword'])) {
+            $where[] = ['og.goods_name', 'like', '%'.$params['goods_keyword'].'%'];
+        }
+        // 分销会员
+        if (isset($params['distribution_keyword']) && !empty($params['distribution_keyword'])) {
+            $where[] = ['u.sn|u.nickname', 'like', '%'.$params['distribution_keyword'].'%'];
+        }
+        // 佣金状态
+        if (isset($params['status']) && !empty($params['status'])) {
+            $where[] = ['dog.status', '=', $params['status']];
+        }
+
+        $field = [
+            'o.id' => 'order_id',
+            'o.order_sn',
+            'o.create_time' => 'order_create_time',
+            'o.user_id' => 'order_user_id',
+            'u.id' => 'distribution_user_id',
+            'u.avatar' => 'distribution_avatar',
+            'u.sn' => 'distribution_sn',
+            'u.nickname' => 'distribution_nickname',
+            'og.image' => 'goods_image',
+            'og.goods_name' => 'goods_name',
+            'og.spec_value' => 'spec_value',
+            'og.goods_num' => 'goods_num',
+            'og.total_pay_price' => 'total_pay_price',
+            'dog.level_id',
+            'dog.level',
+            'dog.ratio',
+            'dog.money',
+            'dog.status' => 'status_desc',
+            'dog.settlement_time',
+            's.id' => 'shop_id',
+            's.name' => 'shop_name',
+            's.logo' => 'shop_logo',
+        ];
+
+        $lists = DistributionOrderGoods::alias('dog')
+            ->leftJoin('order o', 'o.id = dog.order_id')
+            ->leftJoin('user u', 'u.id = dog.user_id')
+            ->leftJoin('order_goods og', 'og.id = dog.order_goods_id')
+            ->leftJoin('distribution_level dl', 'dl.id = dog.level_id')
+            ->leftJoin('shop s', 's.id = dog.shop_id')
+            ->field($field)
+            ->where($where)
+            ->order('dog.id', 'desc')
+            ->page($params['page'], $params['limit'])
+            ->select()
+            ->toArray();
+
+        $count = DistributionOrderGoods::alias('dog')
+            ->leftJoin('order o', 'o.id = dog.order_id')
+            ->leftJoin('user u', 'u.id = dog.user_id')
+            ->leftJoin('order_goods og', 'og.id = dog.order_goods_id')
+            ->leftJoin('distribution_level dl', 'dl.id = dog.level_id')
+            ->leftJoin('shop s', 's.id = dog.shop_id')
+            ->field($field)
+            ->where($where)
+            ->count();
+
+        foreach($lists as &$item) {
+            $item['order_create_time'] = date('Y-m-d H:i:s', $item['order_create_time']);
+            $item['user_info'] = User::getUserInfo($item['order_user_id']);
+            if ($item['user_info'] == '系统') {
+                // 用户不存在(已被删除的情况)
+                $item['user_info'] = [
+                    'avatar' => '',
+                    'nickname' => '-',
+                    'sn' => '-',
+                ];
+            }
+            $item['distribution_avatar'] = empty($item['distribution_avatar']) ? '' : UrlServer::getFileUrl($item['distribution_avatar']);
+            $item['user_info']['avatar'] = empty($item['user_info']['avatar']) ? '' : UrlServer::getFileUrl($item['user_info']['avatar']);
+            $item['level_name'] = DistributionLevel::getLevelName($item['level_id']);
+            $item['shop_logo'] = empty($item['shop_logo']) ? '' : UrlServer::getFileUrl($item['shop_logo']);
+            $item['goods_image'] = empty($item['goods_image']) ? '' : UrlServer::getFileUrl($item['goods_image']);
+        }
+
+        return [
+            'count' => $count,
+            'lists' => $lists
+        ];
+    }
+}

+ 95 - 0
app/admin/logic/distribution/DistributionSettingLogic.php

@@ -0,0 +1,95 @@
+<?php
+namespace app\admin\logic\distribution;
+
+use app\common\basics\Logic;
+use app\common\logic\DistributionLogic;
+use app\common\model\distribution\Distribution;
+use app\common\model\user\User;
+use app\common\server\ConfigServer;
+use think\facade\Db;
+
+class DistributionSettingLogic extends Logic
+{
+    /**
+     * @notes 获取分销配置
+     * @return array
+     * @author Tab
+     * @date 2021/8/31 17:45
+     */
+    public static function getConfig()
+    {
+        $config = [
+            // 分销功能 0-关闭(默认) 1-开启
+            'is_open' => ConfigServer::get('distribution', 'is_open', 0),
+            // 分销层级 1-一级分销 2-二级分销(默认)
+            'level' => ConfigServer::get('distribution', 'level', 2),
+            // 商品详情是否显示佣金 0-不显示(默认) 1-默认
+            'is_show_earnings' => ConfigServer::get('distribution', 'is_show_earnings', 0),
+            // 详情页佣金可见用户 0-全部用户 1-分销商
+            'show_earnings_scope' => ConfigServer::get('distribution', 'show_earnings_scope', 0),
+            // 开通分销会员条件 1-无条件 2-申请分销(默认) 3-指定分销
+            'apply_condition' => ConfigServer::get('distribution', 'apply_condition', 2),
+            // 佣金计算方式 1-商品实际支付金额(默认)
+            'cale_method' => ConfigServer::get('distribution', 'cale_method', 1),
+            // 结算时机 1-订单完成后(默认)
+            'settlement' => ConfigServer::get('distribution', 'settlement', 1),
+            // 结算时机 订单完成后多少天内(默认7天)
+            'settlement_days' => ConfigServer::get('distribution', 'settlement_days', 7),
+        ];
+        return $config;
+    }
+
+    /**
+     * @notes 分销设置
+     * @param $params
+     * @return bool
+     * @author Tab
+     * @date 2021/9/2 14:47
+     */
+    public static function set($params)
+    {
+        Db::startTrans();
+        try {
+            $allowFields = ['is_open', 'level', 'is_show_earnings', 'apply_condition', 'cale_method', 'settlement_days', 'show_earnings_scope'];
+            foreach ($allowFields as $field) {
+                if(isset($params[$field])) {
+                    ConfigServer::set('distribution', $field, $params[$field]);
+                }
+                if($field == 'apply_condition' && isset($params[$field]) && $params[$field] == 1) {
+                    // 开通分销会员无条件时,所有会员均成为分销会员
+                    self::distribution();
+                }
+            }
+            Db::commit();
+            return true;
+        } catch (\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @notes 全员分销
+     * @author Tab
+     * @date 2021/9/2 14:38
+     */
+    public static function distribution()
+    {
+        // 将非分销会员变为分销会员
+        Distribution::where('is_distribution', 0)->update([
+            'is_distribution' => 1
+        ]);
+        // 获取所有分销会员id
+        $distributionIds = Distribution::distinct(true)->column('user_id');
+        // 查找未生成分销会员基础信息表的会员
+        $notDistributionIds = User::where([
+            ['id', 'not in', $distributionIds],
+            ['del', '=', 0],
+        ])->column('id');
+        foreach($notDistributionIds as $userId) {
+            // 生成分销会员基础信息表
+            DistributionLogic::add($userId);
+        }
+    }
+}

+ 414 - 0
app/admin/logic/distribution/MemberLogic.php

@@ -0,0 +1,414 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\logic\distribution;
+
+use app\common\basics\Logic;
+use app\common\model\user\User;
+use app\common\model\user\UserLevel;
+use app\common\server\UrlServer;
+use app\common\model\WithdrawApply;
+use app\common\model\distribution\DistributionOrderGoods;
+use app\common\model\distribution\DistributionMemberApply;
+use think\facade\Db;
+
+class MemberLogic extends Logic
+{
+    public static function memberLists($get)
+    {
+        // 关键词
+        $where[] = ['is_distribution', '=', 1];
+        if (!empty($get['search_key']) && !empty($get['keyword'])) {
+            $where[] = [$get['search_key'], '=', trim($get['keyword'])];
+        }
+        //分销状态
+        if (isset($get['freeze_distribution']) && $get['freeze_distribution'] != '') {
+            $where[] = ['freeze_distribution', '=', $get['freeze_distribution']];
+        }
+
+        $user = new User();
+        $count = $user->where($where)->count();
+
+        $lists = $user
+            ->where($where)
+            ->page($get['page'], $get['limit'])
+            ->append(['fans', 'distribution_order', 'leader'])
+            ->hidden(['password,pay_password,salt'])
+            ->order('id desc')
+            ->select()
+            ->toArray();
+
+        foreach ($lists as &$item) {
+            $item['avatar'] = UrlServer::getFileUrl($item['avatar']);
+
+            $item['distribution_num'] = $item['distribution_order']['num'] ?? 0;//分销订单数
+            $item['distribution_amount'] = $item['distribution_order']['amount'] ?? 0;//分销订单金额
+            $item['distribution_money'] = $item['distribution_order']['money'] ?? 0;//分销佣金
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    public static function addMember($post)
+    {
+        // 根据会员编号查询用户
+        $user = User::field('id,sn,is_distribution,distribution_add_remarks,del')
+            ->where(['sn'=>$post['sn']])->findOrEmpty();
+        // 校验用户
+        if ($user->isEmpty()) { return '该用户不存在!'; }
+        $user = $user->toArray();
+        if ($user['del'] === 1) { return '该用户已被删除!'; }
+        if ($user['is_distribution']) { return '该用户已是分销会员,无需重复添加'; }
+        $result =  User::where(['id' => (int)$user['id']])->update([
+            'is_distribution'          => 1,
+            'distribution_add_remarks' => $post['remarks'] ?? '',
+            'update_time' => time()
+        ]);
+        return $result ? true : '添加失败';
+    }
+
+    public static function getMemberInfo($get)
+    {
+        $user_id = $get['id'];
+        $user = User::alias('u')
+            ->field('u.*,u.sn as user_sn')
+            ->leftJoin('distribution_order_goods d', 'd.user_id = u.id')
+            ->where('u.id', $user_id)
+            ->append(['distribution_order'])
+            ->hidden(['password', 'pay_password', 'salt'])
+            ->find();
+
+        $user['distribution_text'] = '否';
+        if ($user['is_distribution'] == 1) {
+            $user['distribution_text'] = '是';
+        }
+
+        //上级编号
+        $user['first_leader_sn'] = User::where('id', $user['first_leader'])->value('sn');
+        //直推会员数
+        $user['first_fans'] = User::where(['first_leader' => $user_id, 'del' => 0])->count();
+        // 已提现金额
+        $have_withdraw = WithdrawApply::where(['status' => WithdrawApply::STATUS_SUCCESS, 'user_id' => $user_id])
+            ->sum('money');
+
+        $user['distribution_num'] = $user['distribution_order']['num'] ?? 0;//分销订单数
+        $user['distribution_amount'] = $user['distribution_order']['amount'] ?? 0;//分销订单金额
+        $user['distribution_money'] = $user['distribution_order']['money'] ?? 0;//分销佣金
+        $user['have_withdraw'] = $have_withdraw;//已提现金额
+        return $user;
+    }
+
+    public static function getFansLists($get)
+    {
+        $user_id = $get['id'];
+        $where = [];
+        if (!empty($get['search_key']) && !empty($get['keyword'])) {
+            $keyword = $get['keyword'];
+            $where[] = [$get['search_key'], 'like', '%' . $keyword . '%'];
+        }
+
+        $fans_type = $get['type'] ?? 'all';
+        if ($fans_type == 'all') {
+            $where[] = ['first_leader|second_leader|third_leader', '=', $user_id];
+        } else {
+            $where[] = [$fans_type, '=', $user_id];
+        }
+
+        $user = new User();
+        $count = $user
+            ->where($where)
+            ->append(['fans', 'distribution_order'])
+            ->hidden(['password,pay_password,salt'])
+            ->count();
+
+        $lists = $user
+            ->where($where)
+            ->append(['fans', 'distribution_order'])
+            ->hidden(['password,pay_password,salt'])
+            ->page($get['page'], $get['limit'])
+            ->select()->toArray();
+
+        // 用户等级列表
+        $user_level = UserLevel::where(['del' => 0])->column('name', 'id');
+        // 提取所有上级id
+        $leader_ids = array_column($lists, 'first_leader');
+        // 所有上级列表
+        $leaders = User::where('id', 'in', $leader_ids)
+            ->column('sn,nickname,mobile,level', 'id');
+
+        foreach ($lists as &$item) {
+            $item['avatar'] = UrlServer::getFileUrl($item['avatar']);
+            $item['leader'] = $leaders[$item['first_leader']] ?? [];
+            if (!empty($item['leader'])) {
+                $leader_level = $item['leader']['level'] ?? 0;
+                $item['leader']['level'] = $user_level[$leader_level] ?? '无等级';
+            }
+            $item['distribution_num'] = $item['distribution_order']['num'] ?? 0;//分销订单数
+            $item['distribution_amount'] = $item['distribution_order']['amount'] ?? 0;//分销订单金额
+            $item['distribution_money'] = $item['distribution_order']['money'] ?? 0;//分销佣金
+        }
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    public static function getEarningsDetail($get)
+    {
+        $user_id = $get['id'];
+        $where = [];
+        $where[] = ['d.user_id', '=', $user_id];
+        $where[] = ['d.status', '=', DistributionOrderGoods::STATUS_SUCCESS];
+
+        //记录时间
+        if (isset($get['start_time']) && $get['start_time'] != '') {
+            $where[] = ['d.create_time', '>=', strtotime($get['start_time'])];
+        }
+        if (isset($get['end_time']) && $get['end_time'] != '') {
+            $where[] = ['d.create_time', '<=', strtotime($get['end_time'])];
+        }
+
+        $count = DistributionOrderGoods::alias('d')
+            ->field('d.id as distribution_id, d.sn, o.order_sn, d.money, d.create_time')
+            ->join('order_goods og', 'og.id = d.order_goods_id')
+            ->join('order o', 'o.id = og.order_id')
+            ->where($where)
+            ->count();
+
+        $lists = DistributionOrderGoods::alias('d')
+            ->field('d.id as distribution_id, d.sn, o.order_sn, d.money, d.create_time')
+            ->join('order_goods og', 'og.id = d.order_goods_id')
+            ->join('order o', 'o.id = og.order_id')
+            ->where($where)
+            ->page($get['page'], $get['limit'])
+            ->select();
+
+        foreach ($lists as &$item) {
+            $item['type'] = '分销佣金';
+        }
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    public static function getLeaderInfo($user_id)
+    {
+        $first_leader = User::alias('u')
+            ->field('u1.nickname,u1.sn')
+            ->join('user u1', 'u1.id = u.first_leader')
+            ->where('u.id', $user_id)
+            ->find();
+
+        $leader_data = '无';
+        if ($first_leader) {
+            $leader_data = $first_leader['nickname'] . '(' . $first_leader['sn'] . ')';
+        }
+        return $leader_data;
+    }
+
+    public static function updateRelation($post)
+    {
+        Db::startTrans();
+        try{
+            $user_id = $post['user_id'];
+            $referrer_sn =  $post['referrer_sn'];
+
+            //清空上级
+            $data = [
+                'first_leader' => 0,
+                'second_leader' => 0,
+                'third_leader' => 0,
+                'ancestor_relation' => '',
+            ];
+            $my_first_leader = 0;
+            $my_second_leader = 0;
+            $my_ancestor_relation = '';
+
+            if ($post['change_type'] == 'appoint'){
+                //指定上级
+                $my_leader = User::where(['sn' => $referrer_sn])->findOrEmpty();
+
+                //更新我的第一上级、第二上级、第三上级、关系链
+                $my_first_leader = $my_leader['id'];
+                $my_second_leader = $my_leader['first_leader'];
+                $my_third_leader = $my_leader['second_leader'];
+                $my_ancestor_relation = trim("{$my_first_leader},{$my_leader['ancestor_relation']}", ',');
+                $data = [
+                    'first_leader' => $my_first_leader,
+                    'second_leader' => $my_second_leader,
+                    'third_leader' => $my_third_leader,
+                    'ancestor_relation' => $my_ancestor_relation,
+                ];
+            }
+            // 更新我的上级、上上级、上上上级、关系链
+            User::where(['id' => $user_id])->update($data);
+
+            //更新我向下一级的第二上级、第三上级
+            $data = [
+                'second_leader' => $my_first_leader,
+                'third_leader' => $my_second_leader,
+            ];
+            User::where(['first_leader' => $user_id])->update($data);
+
+            //更新我向下二级的第三级
+            $data = [
+                'third_leader' => $my_first_leader,
+            ];
+            User::where(['second_leader' => $user_id])->update($data);
+
+            //更新当前用户所有后代的关系链
+            $posterityArr = User::field('id,ancestor_relation')
+                ->whereFindInSet('ancestor_relation', $post['user_id'])
+                ->select()
+                ->toArray();
+            $updateData = [];
+            $replace_ancestor_relation = $post['user_id'] . ','. $my_ancestor_relation;
+            foreach($posterityArr as $item) {
+                $updateData[] = [
+                    'id' => $item['id'],
+                    'ancestor_relation' => str_replace($post['user_id'], $replace_ancestor_relation, $item['ancestor_relation'])
+                ];
+            }
+            // 批量更新
+            (new User())->saveAll($updateData);
+
+            Db::commit();
+            return true;
+        } catch (Exception $e){
+            Db::rollback();
+            return $e->getMessage();
+        }
+    }
+
+    public static function freeze($post)
+    {
+        $user = User::where('id', $post['id'])->find();
+        $user->freeze_distribution = 1;
+        if ($post['type'] == 'unfreeze'){
+            $user->freeze_distribution = 0;
+        }
+        return $user->save();
+    }
+
+    public static function del($post)
+    {
+        $user = User::find($post['id']);
+        $user->is_distribution = 0;
+        $user->update_time = time();
+        return $user->save();
+    }
+
+    /**
+     * 待审核会员列表
+     */
+    public static function auditLists($get)
+    {
+        $where = [];
+        if (!empty($get['search_key']) && !empty($get['keyword'])) {
+            $keyword = $get['keyword'];
+            if ($get['search_key'] == 'mobile') {
+                $where[] = ['u.mobile', 'like', '%' . $keyword . '%'];
+            } else {
+                $where[] = [$get['search_key'], 'like', '%' . $keyword . '%'];
+            }
+        }
+        //审核状态
+        if (isset($get['status']) && $get['status'] != '') {
+            $where[] = ['status', '=', $get['status']];
+        }
+
+
+        $field = [
+            'a.*', 'u.sn', 'u.nickname', 'u.mobile', 'u.level', 'u.sex', 'a.reason',
+            'u.create_time' => 'register_time', 'u.avatar', 'u.first_leader'
+        ];
+
+        $count = DistributionMemberApply::alias('a')
+            ->join('user u', 'u.id = a.user_id')
+            ->where($where)
+            ->count();
+
+        $lists = DistributionMemberApply::alias('a')
+            ->field($field)
+            ->join('user u', 'u.id = a.user_id')
+            ->order('a.id desc')
+            ->page($get['page'], $get['limit'])
+            ->where($where)
+            ->select()
+            ->toArray();
+
+        $user_level = UserLevel::where(['del' => 0])->column('name', 'id');
+
+        $leader_ids = array_column($lists, 'first_leader');
+        $leaders = User::where('id', 'in', $leader_ids)
+            ->column('sn,nickname,mobile,level', 'id');
+
+        foreach ($lists as &$item) {
+            $item['level'] = $user_level[$item['level']] ?? '无等级';
+            $item['sex'] = self::getSexText($item['sex']);
+            $item['register_time'] = date('Y-m-d H:i:s', $item['register_time']);
+            $item['status_text'] = DistributionMemberApply::getApplyStatus($item['status']);
+            $item['leader'] = $leaders[$item['first_leader']] ?? [];
+            $item['avatar'] = UrlServer::getFileUrl($item['avatar']);
+            if (!empty($item['leader'])) {
+                $leader_level = $item['leader']['level'] ?? 0;
+                $item['leader']['level'] = $user_level[$leader_level] ?? '无等级';
+            }
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    public static function getSexText($value)
+    {
+        switch ($value) {
+            case 1:
+                return '男';
+            case 2:
+                return '女';
+            default:
+                return '未知';
+        }
+    }
+
+    public static function auditPass($post)
+    {
+        Db::startTrans();
+        try {
+            $apply = DistributionMemberApply::where('id', $post['id'])->find();
+            $apply->status = DistributionMemberApply::STATUS_AUDIT_SUCCESS;
+            $apply->update_time = time();
+            $apply->save();
+
+            $user = User::where('id', $apply['user_id'])->find();
+            $user->is_distribution = 1;
+            $user->save();
+
+            Db::commit();
+            return true;
+        } catch (Exception $e) {
+            Db::rollback();
+            return $e->getMessage();
+        }
+    }
+
+    public static function auditRefuse($post)
+    {
+        $apply = DistributionMemberApply::where('id', $post['id'])->find();
+        $apply->status = DistributionMemberApply::STATUS_AUDIT_ERROR;
+        $apply->denial_reason = $post['denial_reason'] ?? '';
+        $apply->save();
+        return true;
+    }
+}

+ 84 - 0
app/admin/logic/distribution/RecordLogic.php

@@ -0,0 +1,84 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\logic\distribution;
+
+use app\common\basics\Logic;
+use app\common\model\distribution\DistributionOrderGoods;
+
+class RecordLogic extends Logic
+{
+    public static function lists($get)
+    {
+        $where = [];
+        // 搜索
+        if(!empty($get['keyword'])) {
+            $fieldDesc = '';
+            switch($get['keyword_type']) {
+                case 'order_sn':
+                    $fieldDesc = 'o.order_sn';
+                    break;
+                case 'user_nickname':
+                    $fieldDesc = 'u.nickname';
+                    break;
+                case 'user_sn':
+                    $fieldDesc = 'u.sn';
+                    break;
+                case 'user_mobile':
+                    $fieldDesc = 'u.mobile';
+                    break;
+            }
+            $where[] = [$fieldDesc, '=', trim($get['keyword'])];
+        }
+        // 佣金状态
+        if(!empty($get['status'])) {
+            $where[] = ['dog.status', '=', $get['status']];
+        }
+        // 记录时间
+        if(!empty($get['start_time'])) {
+            $where[] = ['dog.create_time', '>=', strtotime($get['start_time'])];
+        }
+        if(!empty($get['end_time'])) {
+            $where[] = ['dog.create_time', '<=', strtotime($get['end_time'])];
+        }
+        $lists = DistributionOrderGoods::alias('dog')
+            ->field('dog.money, dog.status as status_desc,dog.create_time as distribution_create_time,u.nickname as user_nickname,u.sn as user_sn,u.mobile as user_mobile,og.total_pay_price,o.order_sn')
+            ->leftJoin('user u', 'u.id=dog.user_id')
+            ->leftJoin('order_goods og', 'og.id=dog.order_goods_id')
+            ->leftJoin('order o', 'o.id=og.order_id')
+            ->where($where)
+            ->order('dog.create_time', 'desc')
+            ->page($get['page'], $get['limit'])
+            ->select()
+            ->toArray();
+
+        $count = DistributionOrderGoods::alias('dog')
+            ->field('dog.money, dog.status as status_desc,dog.create_time as distribution_create_time,u.nickname as user_nickname,u.sn as user_sn,u.mobile as user_mobile,og.total_pay_price,o.order_sn')
+            ->leftJoin('user u', 'u.id=dog.user_id')
+            ->leftJoin('order_goods og', 'og.id=dog.order_goods_id')
+            ->leftJoin('order o', 'o.id=og.order_id')
+            ->where($where)
+            ->count();
+
+        return [
+            'count' => $count,
+            'lists' => $lists
+        ];
+    }
+}

+ 232 - 0
app/admin/logic/finance/FinanceLogic.php

@@ -0,0 +1,232 @@
+<?php
+
+
+namespace app\admin\logic\finance;
+
+
+use app\common\basics\Logic;
+use app\common\model\AccountLog;
+use app\common\model\order\Order;
+use app\common\enum\PayEnum;
+use app\common\enum\OrderEnum;
+use app\common\enum\OrderRefundEnum;
+use app\common\enum\AfterSaleEnum;
+use app\common\enum\WithdrawalEnum;
+use app\common\enum\DistributionOrderGoodsEnum;
+use app\common\enum\WithdrawEnum;
+use app\common\model\user\User;
+use app\common\model\shop\Shop;
+use app\common\model\shop\ShopWithdrawal;
+use app\common\model\shop\ShopSettlement;
+use app\common\model\WithdrawApply;
+
+
+class FinanceLogic extends Logic
+{
+    /**
+     * @Notes: 商家汇总
+     */
+    public static function shop()
+    {
+
+        $model = new Order();
+        $modelShopSettlement = new ShopSettlement();
+        $modelShopWithdrawal = new ShopWithdrawal();
+        $modelWithdrawApply  = new WithdrawApply();
+
+
+
+
+        //已结算交易服务费(平台收入)、(商家)已结算交易服务费
+        $shopAmount = $settlePoundageAmount = $modelShopSettlement
+            ->sum('trade_service_fee');
+
+        //会员提现手续费(平台收入
+        $userPoundage =  $modelWithdrawApply
+            ->where([
+                ['status', '=', WithdrawEnum::STATUS_SUCCESS]
+            ])
+            ->sum('poundage');
+
+        //商家提现手续费(平台收入)
+        $commissionAmount =  $modelShopWithdrawal
+            ->sum('poundage_amount');
+
+        //成交订单笔数
+        $orderNum = $model
+            ->where([
+                ['pay_status', '>', PayEnum::UNPAID]
+            ])
+            ->count('id');
+
+        //营业额
+        $orderAmount = $model
+            ->where([
+                ['pay_status', '>', PayEnum::UNPAID]
+            ])
+            ->sum('order_amount');
+
+
+        //退款订单金额
+        $refundAmount = $model
+            ->where([
+                ['shipping_status', '=', OrderEnum::SHIPPING_NO],
+                ['pay_status', '=', PayEnum::REFUNDED],
+                ['refund_status', 'in', [OrderEnum::REFUND_STATUS_PART_REFUND, OrderEnum::REFUND_STATUS_ALL_REFUND]],
+            ])
+            ->sum('refund_amount');
+
+        //待退款订单金额
+        $refundAmountIng = $model->alias('o')
+            ->join('order_refund or', 'or.order_id = o.id')
+            ->where([
+                ['o.shipping_status', '=', OrderEnum::SHIPPING_NO],
+                ['or.refund_status', '<>', OrderRefundEnum::REFUND_STATUS_COMPLETE]
+            ])
+            ->sum('or.refund_amount');
+
+        //售后退款金额
+        $salesRefundAmount = $model->alias('o')
+            ->join('after_sale as', 'as.order_id = o.id')
+            ->where([
+                ['o.shipping_status', '=', OrderEnum::SHIPPING_FINISH],
+                ['as.status', '=', AfterSaleEnum::STATUS_COMPLETE]
+            ])
+            ->sum('as.refund_price');
+
+        //待售后退款金额
+        $salesRefundAmountIng = $model->alias('o')
+            ->join('after_sale as', 'as.order_id = o.id')
+            ->where([
+                ['o.shipping_status', '=', OrderEnum::SHIPPING_FINISH],
+                ['as.status', '=', AfterSaleEnum::STATUS_WAITING]
+            ])
+            ->sum('as.refund_price');
+
+
+        //已结算成交订单数
+        $settleOrederNum = $modelShopSettlement
+            ->sum('deal_order_count');
+
+        //已结算营业额
+        $settleOrederAmount = $modelShopSettlement
+            ->sum('business_money');
+
+        //待结算营业额
+        $settleOrederAmountWait = $model
+            ->where([
+                ['refund_status', '=', 0 ],
+                ['settle_id', '=', OrderEnum::SETTLE_WAIT]
+            ])
+            ->sum('order_amount');
+
+        //已结算分销佣金金额
+        $settleDistributionAmount = $modelShopSettlement
+            ->sum('distribution_money');
+
+        //已结算入账金额
+        $settleWithdrawalAmount = $modelShopSettlement
+            ->sum('entry_account_money');
+
+        //已提现金额
+        $withdrawaLeftamount = $modelShopWithdrawal
+            ->where([
+                ['status', '=', WithdrawalEnum::SUCCESS_STATUS]
+            ])
+            ->sum('apply_amount');
+
+        //提现中金额
+        $withdrawaLeftamountIng = $modelShopWithdrawal
+            ->where([
+                ['status', '=', WithdrawalEnum::HANDLE_STATUS]
+            ])
+            ->sum('apply_amount');
+
+        //可提现金额       
+        $modelShop = new Shop();
+        $shopWallet = $modelShop->sum('wallet');
+
+        //会员余额
+        $modelUser = new User();
+        $userMoney = $modelUser
+            ->where([
+                ['del', '=', 0]
+            ])
+            ->sum('user_money');
+
+
+        //会员已结算分销佣金金额                   
+        $userSettleDistributionAmount = $model->alias('o')
+            ->join('order_goods og', 'og.order_id = o.id')
+            ->join('distribution_order_goods dog', 'dog.order_goods_id = og.id')
+            ->where([
+                ['o.settle_id', '=', OrderEnum::SETTLE_FINISH],
+                ['dog.status', '=', DistributionOrderGoodsEnum::STATUS_SUCCESS]
+            ])
+            ->sum('dog.money');
+
+        //已提现佣金金额
+        $userDistributionMoney = $modelWithdrawApply
+            ->where([
+                ['status', '=', WithdrawEnum::STATUS_SUCCESS]
+            ])
+            ->sum('money');
+
+        //提现中佣金金额
+        $userDistributionMoneyIng = $modelWithdrawApply
+            ->where([
+                ['status', '=', WithdrawEnum::STATUS_ING]
+            ])
+            ->sum('money');
+
+        //可提现佣金金额
+        $userDistributionMoneyWait = $modelUser
+            ->where([
+                ['del', '=', 0]
+            ])
+            ->sum('earnings');
+
+
+        //总积分
+        $all_integral = AccountLog::where(['change_type'=>1,'source_type'=>AccountLog::integral_change])->sum('change_amount');
+
+        //签到送出积分
+        $sign_in_integral = AccountLog::where(['source_type'=>AccountLog::sign_in_integral])->sum('change_amount');
+
+        //使用积分
+        $use_integral = AccountLog::where(['change_type'=>2,'source_type'=>AccountLog::integral_change])->sum('change_amount');
+
+        //下单赠送积分
+        $consume_award_integral = AccountLog::where(['source_type'=>AccountLog::consume_award_integral])->sum('change_amount');
+
+        return [
+            'shopAmount'                    =>  $shopAmount, //已结算交易服务费(平台收入)
+            'userPoundage'                  =>  $userPoundage, //会员提现手续费(平台收入)
+            'commissionAmount'              =>  $commissionAmount, //提现中佣金金额
+            'orderNum'                      =>  $orderNum, //成交订单笔数
+            'orderAmount'                   =>  $orderAmount, //营业额
+            'refundAmount'                  =>  $refundAmount, //退款订单金额
+            'refundAmountIng'               =>  $refundAmountIng, //待退款订单金额
+            'salesRefundAmount'             =>  $salesRefundAmount, //售后退款金额
+            'salesRefundAmountIng'          =>  $salesRefundAmountIng, //待售后退款金额
+            'settleOrederNum'               =>  $settleOrederNum, //已结算成交订单数
+            'settleOrederAmount'            =>  $settleOrederAmount, //已结算营业额
+            'settleOrederAmountWait'        =>  $settleOrederAmountWait, //待结算营业额
+            'settleDistributionAmount'      =>  $settleDistributionAmount, //已结算分销佣金金额
+            'settleWithdrawalAmount'        =>  $settleWithdrawalAmount, //已结算入账金额
+            'settlePoundageAmount'          =>  $settlePoundageAmount, //已结算交易服务费
+            'withdrawaLeftamount'           =>  $withdrawaLeftamount, //已提现金额
+            'withdrawaLeftamountIng'        =>  $withdrawaLeftamountIng, //提现中金额
+            'shopWallet'                    =>  $shopWallet, //可提现金额
+            'userMoney'                     =>  $userMoney, //会员余额
+            'userSettleDistributionAmount'  =>  $userSettleDistributionAmount, //会员已结算分销佣金金额
+            'userDistributionMoney'         =>  $userDistributionMoney, //已提现佣金金额
+            'userDistributionMoneyIng'      =>  $userDistributionMoneyIng, //提现中佣金金额
+            'userDistributionMoneyWait'     =>  $userDistributionMoneyWait, //可提现佣金金额
+            'all_integral'                  =>  $all_integral, //总积分
+            'sign_in_integral'              =>  $sign_in_integral, //签到送出积分
+            'use_integral'                  =>  $use_integral, //使用积分
+            'consume_award_integral'        =>  $consume_award_integral, //下单赠送积分
+        ];
+    }
+}

+ 123 - 0
app/admin/logic/finance/IntegralLogic.php

@@ -0,0 +1,123 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\logic\finance;
+
+
+use app\common\basics\Logic;
+use app\common\model\AccountLog;
+use app\common\server\ExportExcelServer;
+
+class IntegralLogic extends Logic
+{
+    /**
+     * @notes 积分明细
+     * @param $get
+     * @return array
+     * @author ljj
+     * @date 2022/2/22 5:59 下午
+     */
+    public static function integral($get, $is_export = false)
+    {
+        $where[] = ['source_type','in',AccountLog::integral_change];
+        //用户信息
+        if (isset($get['user_info']) && $get['user_info'] != '') {
+            $where[] = ['u.sn|u.nickname', '=', $get['user_info']];
+        }
+        //开始时间
+        if (isset($get['start_time']) && $get['start_time'] != '') {
+            $where[] = ['al.create_time', '>=', strtotime($get['start_time'])];
+        }
+        //结束时间
+        if (isset($get['end_time']) && $get['end_time'] != '') {
+            $where[] = ['al.create_time', '<=', strtotime($get['end_time'])];
+        }
+
+        // 导出
+        if (true === $is_export) {
+            return self::export($where);
+        }
+
+        $lists = AccountLog::alias('al')
+            ->join('user u', 'al.user_id = u.id')
+            ->field('al.id,al.user_id,al.source_type,al.change_amount,al.left_amount,al.remark,al.change_type,al.create_time,u.sn as user_sn,u.nickname')
+            ->where($where)
+            ->page($get['page'], $get['limit'])
+            ->order('id','desc')
+            ->select()
+            ->toArray();
+
+        foreach ($lists as &$list) {
+            $list['change_amount'] = $list['change_type'] == 1 ? '+'.$list['change_amount'] : '-'.$list['change_amount'];
+        }
+
+
+        $count = AccountLog::alias('al')
+            ->join('user u', 'al.user_id = u.id')
+            ->where($where)
+            ->count();
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+
+    /**
+     * @notes 导出商家账户明细Excel
+     * @param array $where
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function export($where)
+    {
+        try {
+            $lists = AccountLog::alias('al')
+                ->join('user u', 'al.user_id = u.id')
+                ->field('al.id,al.user_id,al.source_type,al.change_amount,al.left_amount,al.remark,al.change_type,al.create_time,u.sn as user_sn,u.nickname')
+                ->where($where)
+                ->order('id','desc')
+                ->select()
+                ->toArray();
+
+            foreach ($lists as &$list) {
+                $list['change_amount'] = $list['change_type'] == 1 ? '+'.$list['change_amount'] : '-'.$list['change_amount'];
+            }
+
+            $excelFields = [
+                'user_sn' => '用户编号',
+                'nickname' => '会员信息',
+                'source_type' => '变动类型',
+                'change_amount' => '积分变动',
+                'left_amount' => '剩余积分',
+                'remark' => '备注',
+                'create_time' => '变动时间',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('积分明细');
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+}

+ 233 - 0
app/admin/logic/finance/ShopSettlementLogic.php

@@ -0,0 +1,233 @@
+<?php
+
+
+namespace app\admin\logic\finance;
+
+
+use app\common\basics\Logic;
+use app\common\enum\ShopEnum;
+use app\common\enum\PayEnum;
+use app\common\enum\OrderEnum;
+use app\common\model\order\Order;
+use app\common\model\shop\ShopSettlement;
+use app\common\model\shop\ShopSettlementRecord;
+use app\common\server\ExportExcelServer;
+use app\common\server\UrlServer;
+
+class ShopSettlementLogic extends Logic
+{
+    /**
+     * @Notes: 商家结算列表
+     * @Author: 张无忌
+     * @param $get
+     * @return array
+     */
+    public static function lists($get, $is_export = false)
+    {
+        try {
+            $where = [];
+            if (!empty($get['name'])) {
+                $where[] = ['S.name', 'like', '%'.$get['name'].'%'];
+            }
+
+            if (!empty($get['start_time'])) {
+                $where[] = ['SL.create_time', '>=', strtotime($get['start_time'])];
+            }
+
+            if (!empty($get['end_time'])) {
+                $where[] = ['SL.create_time', '<=', strtotime($get['end_time'])];
+            }
+
+            // 导出
+            if (true === $is_export) {
+                return self::settlementExport($where);
+            }
+
+            $model = new ShopSettlement();
+            $lists = $model->field([
+                    'SL.id,SL.shop_id,S.name,S.type,S.logo',
+                    'sum(SL.deal_order_count) AS deal_order_count',
+                    'sum(SL.business_money) AS business_money',
+                ])->alias('SL')
+                ->join('shop S', 'S.id = SL.shop_id')
+                ->group('shop_id')
+                ->where($where)
+                ->paginate([
+                    'page'      => $get['page'],
+                    'list_rows' => $get['limit'],
+                    'var_page'  => 'page'
+                ])->toArray();
+
+            foreach ($lists['data'] as &$item) {
+                $item['type'] = ShopEnum::getShopTypeDesc($item['type']);
+                $item['logo'] = UrlServer::getFileUrl($item['logo']);
+            }
+
+            return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+        } catch (\Exception $e) {
+            return ['error'=>$e->getMessage()];
+        }
+    }
+
+    /**
+     * @Notes: 商家结算记录
+     * @Author: 张无忌
+     * @param $get
+     * @return array
+     */
+    public static function record($get)
+    {
+        try {
+            $model = new ShopSettlement();
+            $lists = $model->field(true)
+                ->where(['shop_id'=>$get['shop_id']])
+                ->order('id', 'desc')
+                ->paginate([
+                    'page'      => $get['page'],
+                    'list_rows' => $get['limit'],
+                    'var_page' => 'page'
+                ])
+                ->toArray();
+
+            return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+        } catch (\Exception $e) {
+            return ['error'=>$e->getMessage()];
+        }
+    }
+
+    /**
+     * @Notes: 结算详细
+     * @Author: 张无忌
+     * @param $get
+     * @return array
+     */
+    public static function detail($get)
+    {
+        try {
+            $where[] = ['settle_id', '=', (int)$get['settle_id']];
+            if (!empty($get['order_sn']) and $get['order_sn'])
+                $where[] = ['order_sn', 'like', '%'.$get['order_sn'].'%'];
+
+            $model = new ShopSettlementRecord();
+            $lists = $model->field(true)
+                ->where($where)
+                ->order('id', 'asc')
+                ->paginate([
+                    'page'      => $get['page'],
+                    'list_rows' => $get['limit'],
+                    'var_page' => 'page'
+                ])
+                ->toArray();
+
+            return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+        } catch (\Exception $e) {
+            return ['error'=>$e->getMessage()];
+        }
+    }
+
+    /**
+     * @Notes: 结算统计
+     * @return array
+     */
+    public static function statistics($shop_id = 0)
+    {
+        $where = [];
+        if($shop_id){
+            $where[] = ['shop_id', '=' , $shop_id];
+        }
+                   
+        //营业额
+        $modelOrder = new Order();
+
+        //已结算成交订单数
+        $modelShopSettlement = new ShopSettlement();
+        $settleOrederNum = $modelShopSettlement
+                ->where($where)
+                ->sum('deal_order_count');
+
+        //已结算营业额
+        $settleOrederAmount = $modelShopSettlement
+                ->where($where)
+                ->sum('business_money');
+
+        //待结算营业额
+        $settleOrederAmountWait =  $modelOrder
+                ->where([
+                    ['pay_status', '>', PayEnum::UNPAID],
+                    ['settle_id', '=', OrderEnum::SETTLE_WAIT]
+                ])
+                ->sum('order_amount');
+        
+        //已结算分销佣金金额
+        $settleDistributionAmount = $modelShopSettlement
+                ->where($where)
+                ->sum('distribution_money');
+                        
+        //已结算入账金额
+        $settleWithdrawalAmount = $modelShopSettlement
+                ->where($where)
+                ->sum('entry_account_money');  
+
+        //已结算交易服务费
+        $settlePoundageAmount = $modelShopSettlement
+                ->where($where)
+                ->sum('trade_service_fee');     
+
+        return [
+            'settleOrederNum'               =>  $settleOrederNum, //已结算成交订单数
+            'settleOrederAmount'            =>  $settleOrederAmount, //已结算营业额
+            'settleOrederAmountWait'        =>  $settleOrederAmountWait, //待结算营业额
+            'settleDistributionAmount'      =>  $settleDistributionAmount, //已结算分销佣金金额
+            'settleWithdrawalAmount'        =>  $settleWithdrawalAmount, //已结算入账金额
+            'settlePoundageAmount'          =>  $settlePoundageAmount, //已结算交易服务费
+        ];
+    }
+
+
+
+    /**
+     * @notes 导出商家结算Excel
+     * @param array $where
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function settlementExport($where)
+    {
+        try {
+            $model = new ShopSettlement();
+            $lists = $model->field([
+                'SL.id,SL.shop_id,S.name,S.type,S.logo',
+                'sum(SL.deal_order_count) AS deal_order_count',
+                'sum(SL.business_money) AS business_money',
+            ])->alias('SL')
+                ->join('shop S', 'S.id = SL.shop_id')
+                ->group('shop_id')
+                ->where($where)
+                ->select()
+                ->toArray();
+
+            foreach ($lists as &$item) {
+                $item['type'] = ShopEnum::getShopTypeDesc($item['type']);
+            }
+
+            $excelFields = [
+                'name' => '商家名称',
+                'type' => '商家类型',
+                'deal_order_count' => '已结算成交订单数',
+                'business_money' => '已结算营业额',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('商家结算');
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+    
+}

+ 446 - 0
app/admin/logic/finance/ShopWithdrawalLogic.php

@@ -0,0 +1,446 @@
+<?php
+
+
+namespace app\admin\logic\finance;
+
+
+use app\common\basics\Logic;
+use app\common\enum\ShopEnum;
+use app\common\enum\ShopWithdrawEnum;
+use app\common\enum\WithdrawalEnum;
+use app\common\model\shop\Shop;
+use app\common\model\shop\ShopAccountLog;
+use app\common\model\shop\ShopAlipay;
+use app\common\model\shop\ShopBank;
+use app\common\model\shop\ShopWithdrawal;
+use app\common\server\ExportExcelServer;
+use app\common\server\UrlServer;
+use app\common\server\YansongdaAliPayTransferServer;
+
+class ShopWithdrawalLogic extends Logic
+{
+    /**
+     * @Notes: 申请提现记录列表
+     * @Author: 张无忌
+     * @param $get
+     * @return array
+     */
+    public static function lists($get, $is_export = false)
+    {
+        try {
+            $where[] = ['status', '=', $get['type'] ?? 0];
+
+            if (!empty($get['start_time']) and $get['start_time']) {
+                $where[] = ['create_time', '>=', strtotime($get['start_time'])];
+            }
+
+            if (!empty($get['end_time']) and $get['end_time']) {
+                $where[] = ['create_time', '<=', strtotime($get['start_time'])];
+            }
+
+            // 导出
+            if (true === $is_export) {
+                return self::withdrawalExport($where);
+            }
+
+            $model = new ShopWithdrawal();
+            $lists = $model->field(true)
+                ->where($where)
+                ->with(['shop'])
+                ->order('id desc')
+                ->paginate([
+                    'page'      => $get['page'],
+                    'list_rows' => $get['limit'],
+                    'var_page' => 'page'
+                ])->toArray();
+
+            foreach ($lists['data'] as &$item) {
+                $item['status_text'] = WithdrawalEnum::getStatusDesc($item['status']);
+            }
+
+            return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+        } catch (\Exception $e) {
+            static::$error = $e->getMessage();
+            return ['error'=>$e->getMessage()];
+        }
+    }
+
+    /**
+     * @Notes: 统计
+     * @Author: 张无忌
+     * @return array
+     */
+    public static function statistics()
+    {
+        $model = new ShopWithdrawal();
+        $apply   = $model->where(['status'=>WithdrawalEnum::APPLY_STATUS])->count();
+        $handle  = $model->where(['status'=>WithdrawalEnum::HANDLE_STATUS])->count();
+        $success = $model->where(['status'=>WithdrawalEnum::SUCCESS_STATUS])->count();
+        $error   = $model->where(['status'=>WithdrawalEnum::ERROR_STATUS])->count();
+
+        return ['apply'=>$apply, 'handle'=>$handle, 'success'=>$success, 'error'=>$error];
+    }
+
+    /**
+     * @Notes: 数据汇总
+     * @Author: 张无忌
+     */
+    public static function summary()
+    {
+        $model = new ShopWithdrawal();
+        $successWithdrawn = $model->where(['status'=>WithdrawalEnum::SUCCESS_STATUS])->sum('apply_amount');
+        $handleWithdrawn = $model->where(['status'=>WithdrawalEnum::HANDLE_STATUS])->sum('apply_amount');
+        $totalWallet = (new Shop())->where(['del'=>0])->sum('wallet');
+
+        return ['successWithdrawn'=>$successWithdrawn, 'handleWithdrawn'=>$handleWithdrawn, 'totalWallet'=>$totalWallet];
+    }
+
+    /**
+     * @Notes: 提现详细
+     * @Author: 张无忌
+     * @param $id
+     * @return array
+     */
+    public static function detail($id)
+    {
+        $withdrawal = (new ShopWithdrawal())->findOrEmpty($id)->toArray();
+        $shop       = (new Shop())->with(['category'])->findOrEmpty($withdrawal['shop_id'])->toArray();
+        $bank       = (new ShopBank())->findOrEmpty($withdrawal['bank_id'])->toArray();
+        $alipay     = (new ShopAlipay())->findOrEmpty($withdrawal['alipay_id'])->toArray();
+
+        $shop['type'] = ShopEnum::getShopTypeDesc($shop['type']);
+        $withdrawal['status_text'] = WithdrawalEnum::getStatusDesc($withdrawal['status']);
+        $withdrawal['type_text'] = ShopWithdrawEnum::getTypeText($withdrawal['type']);
+    
+        return [ 'withdrawal' => $withdrawal, 'shop' => $shop, 'bank' => $bank, 'alipay' => $alipay ];
+    }
+
+    /**
+     * @Notes: 审核提现
+     * @Author: 张无忌
+     * @param $post
+     * @return bool
+     */
+    public static function examine($post)
+    {
+        try {
+            if ($post['is_examine']) {
+                // 同意提现
+                ShopWithdrawal::update([
+                    'explain'     => $post['explain'] ?? '',
+                    'status'      => WithdrawalEnum::HANDLE_STATUS,
+                    'update_time' => time()
+                ], ['id'=>$post['id']]);
+
+            } else {
+                // 拒绝提现
+                $withdrawal = (new ShopWithdrawal())->findOrEmpty($post['id'])->toArray();
+                ShopWithdrawal::update([
+                    'explain'     => $post['explain'] ?? '',
+                    'status'      => WithdrawalEnum::ERROR_STATUS,
+                    'update_time' => time()
+                ], ['id'=>$post['id']]);
+
+                Shop::update([
+                    'wallet'      => ['inc', $withdrawal['apply_amount']],
+                    'update_time' => time()
+                ], ['id'=>$withdrawal['shop_id']]);
+
+                (new ShopAccountLog())->where([
+                    'source_id' => $withdrawal['id'],
+                    'source_sn' => $withdrawal['sn']
+                ])->update([
+                    'change_type' => 1,
+                    'left_amount' => ['inc', $withdrawal['apply_amount']],
+                    'source_type' => ShopAccountLog::withdrawal_fail_money
+                ]);
+            }
+
+            return true;
+        } catch (\Exception $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @Notes: 审核提现转账
+     * @Author: 张无忌
+     * @param $post
+     * @return bool
+     */
+    public static function transfer($post)
+    {
+        try {
+            if ($post['is_examine']) {
+                // 转账成功
+                ShopWithdrawal::update([
+                    'transfer_content' => $post['transfer_content'] ?? '',
+                    'status'           => WithdrawalEnum::SUCCESS_STATUS,
+                    'transfer_voucher' => $post['image'] ?? '',
+                    'transfer_time'    => time(),
+                    'update_time'      => time()
+                ], ['id'=>(int)$post['id']]);
+
+                $withdrawal = (new ShopWithdrawal())->findOrEmpty($post['id'])->toArray();
+                (new ShopAccountLog())->where([
+                    'source_id' => $withdrawal['id'],
+                    'source_sn' => $withdrawal['sn']
+                ])->update([
+                    'change_type' => 2,
+                    'source_type' => ShopAccountLog::withdrawal_dec_money
+                ]);
+
+            } else {
+                // 转账失败
+                $withdrawal = (new ShopWithdrawal())->findOrEmpty($post['id'])->toArray();
+                ShopWithdrawal::update([
+                    'transfer_content' => $post['transfer_content'] ?? '',
+                    'status'           => WithdrawalEnum::ERROR_STATUS,
+                    'transfer_voucher' => $post['image'] ?? '',
+                    'transfer_time'    => time(),
+                    'update_time'      => time()
+                ], ['id'=>$post['id']]);
+
+                Shop::update([
+                    'wallet'      => ['inc', $withdrawal['apply_amount']],
+                    'update_time' => time()
+                ], ['id'=>$withdrawal['shop_id']]);
+
+                (new ShopAccountLog())->where([
+                    'source_id' => $withdrawal['id'],
+                    'source_sn' => $withdrawal['sn']
+                ])->update([
+                    'change_type' => 1,
+                    'left_amount' => ['inc', $withdrawal['apply_amount']],
+                    'source_type' => ShopAccountLog::withdrawal_fail_money
+                ]);
+            }
+
+            return true;
+        } catch (\Exception $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+    
+    static function transfer_online($post) : bool
+    {
+        try {
+            
+            $detail = ShopWithdrawal::with([ 'alipay' ])->findOrEmpty($post['id']);
+            $result = (new YansongdaAliPayTransferServer())->shopWithdrawTransfer($detail);
+            if (true === $result) {
+                // 转账成功
+                ShopWithdrawal::update([
+                    'explain'          => '',
+                    'status'           => WithdrawalEnum::SUCCESS_STATUS,
+                    'transfer_voucher' => '',
+                    'transfer_time'    => time(),
+                    'update_time'      => time()
+                ], [ 'id' => (int) $post['id'] ]);
+    
+                $withdrawal = (new ShopWithdrawal())->findOrEmpty($post['id'])->toArray();
+                (new ShopAccountLog())->where([
+                    'source_id' => $withdrawal['id'],
+                    'source_sn' => $withdrawal['sn']
+                ])->update([
+                    'change_type' => 2,
+                    'source_type' => ShopAccountLog::withdrawal_dec_money
+                ]);
+            } else {
+                static::$error = (string) $result;
+    
+                // 转账失败
+                $withdrawal = (new ShopWithdrawal())->findOrEmpty($post['id'])->toArray();
+                ShopWithdrawal::update([
+                    'explain'          => '支付宝转账失败',
+                    'status'           => WithdrawalEnum::ERROR_STATUS,
+                    'transfer_voucher' => '',
+                    'transfer_time'    => time(),
+                    'update_time'      => time()
+                ], [ 'id' => $post['id'] ]);
+    
+                Shop::update([
+                    'wallet'      => ['inc', $withdrawal['apply_amount']],
+                    'update_time' => time()
+                ], [ 'id' => $withdrawal['shop_id'] ]);
+    
+                (new ShopAccountLog())->where([
+                    'source_id' => $withdrawal['id'],
+                    'source_sn' => $withdrawal['sn']
+                ])->update([
+                    'change_type' => 1,
+                    'left_amount' => ['inc', $withdrawal['apply_amount']],
+                    'source_type' => ShopAccountLog::withdrawal_fail_money
+                ]);
+            }
+            
+            return true;
+        } catch (\Throwable $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @Notes: 账户明细
+     * @Author: 张无忌
+     * @param $get
+     * @return array
+     */
+    public static function account($get, $is_export = false)
+    {
+        $where = [];
+        if (isset($get['shop_name']) && $get['shop_name']) { 
+            $where[] = ['S.name', 'like', '%' . $get['shop_name'] . '%'];
+        }
+        if (isset($get['search_key']) && $get['search_key']) {
+            switch($get['search_key']){
+                case 'settle':
+                    $where[] = ['SAL.source_type', '=', ShopAccountLog::settlement_add_money];
+                    break;
+                case 'withdrawal':
+                    $where[] = ['SAL.source_type', '=', ShopAccountLog::withdrawal_dec_money];
+                    break;
+                case 'withdrawal_stay':
+                    $where[] = ['SAL.source_type', '=', ShopAccountLog::withdrawal_stay_money];
+                    break;
+                case 'withdrawal_error':
+                    $where[] = ['SAL.source_type', '=', ShopAccountLog::withdrawal_fail_money];
+                    break;
+            }
+        }
+
+        if (!empty($get['start_time']) and $get['start_time']) {
+            $where[] = ['SAL.create_time', '>=', strtotime($get['start_time'])];
+        }
+
+        if (!empty($get['end_time']) and $get['end_time']) {
+            $where[] = ['SAL.create_time', '<=', strtotime($get['end_time'])];
+        }
+
+        // 导出
+        if (true === $is_export) {
+            return self::accountExport($where);
+        }
+
+        $model = new ShopAccountLog();
+        $lists = $model->alias('SAL')
+                    ->field(['SAL.*', 'S.name,S.logo,S.type'])
+                    ->join('shop S', 'S.id = SAL.shop_id')
+                    ->order('SAL.id desc')
+                    ->where($where)
+                    ->paginate([
+                        'page'      => $get['page'],
+                        'list_rows' => $get['limit'],
+                        'var_page'  => 'page'
+                    ])->toArray();
+
+
+        foreach ($lists['data'] as &$item) {
+            $item['logo'] = empty($item['logo']) ? '' : UrlServer::getFileUrl($item['logo']);
+            $item['type'] = ShopEnum::getShopTypeDesc($item['type']);
+            $item['source_type'] = ShopAccountLog::getSourceType($item['source_type']);
+            $item['change_amount'] = $item['change_type'] == 1 ? '+'.$item['change_amount'] : '-'.$item['change_amount'];
+            $item['logo'] = !empty($item['logo']) ? UrlServer::getFileUrl($item['logo']) : "";
+        }
+
+        return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+    }
+
+    /**
+     * @notes 导出商家明细Excel
+     * @param array $where
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function withdrawalExport($where)
+    {
+        try {
+            $model = new ShopWithdrawal();
+            $lists = $model->field(true)
+                ->where($where)
+                ->with(['shop'])
+                ->select()->toArray();
+
+            foreach ($lists as &$item) {
+                $item['status_text'] = WithdrawalEnum::getStatusDesc($item['status']);
+                $item['shop_name'] = $item['shop']['name'];
+                $item['shop_type'] = ShopEnum::getShopTypeDesc($item['shop']['type']);
+            }
+
+            $excelFields = [
+                'shop_name' => '商家名称',
+                'shop_type' => '商家类型',
+                'sn' => '提现单号',
+                'apply_amount' => '提现金额',
+                'poundage_amount' => '提现手续费',
+                'left_amount' => '到账金额',
+                'status_text' => '提现状态',
+                'create_time' => '提现时间',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('商家提现');
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 导出商家账户明细Excel
+     * @param array $where
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function accountExport($where)
+    {
+        try {
+            $model = new ShopAccountLog();
+            $lists = $model->alias('SAL')
+                ->field(['SAL.*', 'S.name,S.type'])
+                ->join('shop S', 'S.id = SAL.shop_id')
+                ->order('SAL.id desc')
+                ->where($where)
+                ->select()->toArray();
+
+            foreach ($lists as &$item) {
+                $item['type'] = ShopEnum::getShopTypeDesc($item['type']);
+                $item['source_type'] = ShopAccountLog::getSourceType($item['source_type']);
+                $item['change_amount'] = $item['change_type'] == 1 ? '+'.$item['change_amount'] : '-'.$item['change_amount'];
+            }
+
+            $excelFields = [
+                'name' => '商家名称',
+                'type' => '商家类型',
+                'log_sn' => '明细流水号',
+                'source_sn' => '来源单号',
+                'source_type' => '明细类型',
+                'change_amount' => '变动金额',
+                'left_amount' => '剩余金额',
+                'create_time' => '记录时间',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('商家账户明细');
+            $export->setExportNumber(['log_sn', 'source_sn']);
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+}

+ 929 - 0
app/admin/logic/finance/WithdrawLogic.php

@@ -0,0 +1,929 @@
+<?php
+
+namespace app\admin\logic\finance;
+
+use app\admin\logic\WechatMerchantTransferLogic;
+use app\common\basics\Logic;
+use app\common\model\RechargeOrder;
+use app\common\model\WithdrawApply;
+use app\common\enum\WithdrawEnum;
+use app\common\server\ConfigServer;
+use app\common\server\ExportExcelServer;
+use app\common\server\UrlServer;
+use app\common\model\user\User;
+use app\common\logic\AccountLogLogic;
+use app\common\model\AccountLog;
+use app\admin\logic\WechatCorporatePaymentLogic;
+use think\facade\Db;
+use think\Exception;
+
+/**
+ * Class WithdrawLogic
+ * @package app\admin\logic\finance
+ */
+class WithdrawLogic extends Logic
+{
+    /**
+     * @notes 会员佣金提现列表
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:00 上午
+     */
+    public static function lists($get, $is_export = false)
+    {
+
+        $where = [];
+        // 会员信息
+        if (!empty($get['search_key']) && !empty($get['keyword'])) {
+            $keyword = $get['keyword'];
+            if ($get['search_key'] == 'user_sn') {
+                $where[] = ['u.sn', '=', $keyword];
+            } elseif ($get['search_key'] == 'nickname') {
+                $where[] = ['u.nickname', 'like', '%' . $keyword . '%'];
+            }
+        }
+
+        //提现单号
+        if (isset($get['withdraw_sn']) && $get['withdraw_sn'] != '') {
+            $where[] = ['w.sn', '=', $get['withdraw_sn']];
+        }
+
+        //提现方式
+        if (isset($get['type']) && $get['type'] != '') {
+            $where[] = ['w.type', '=', $get['type']];
+        }
+
+        //提现状态
+        if (isset($get['status']) && $get['status'] != '') {
+            $where[] = ['status', '=', $get['status']];
+        }
+
+        if (empty($get['start_time']) && empty($get['end_time'])) {
+            $where[] = ['w.create_time', '>=', strtotime(date("Y-m-d", time()))];
+            $where[] = ['w.create_time', '<=', strtotime(date("Y-m-d", time())) + 86399];
+        }
+
+        // 提现时间
+        if (isset($get['start_time']) && $get['start_time'] && isset($get['end_time']) && $get['end_time']) {
+            $where[] = ['w.create_time', 'between', [strtotime($get['start_time']), strtotime($get['end_time'])]];
+//        }else{
+////            $where[] = ['w.create_time', 'between', Time::today()];
+        }
+
+        // 导出
+        if (true === $is_export) {
+            return self::withdrawExport($where);
+        }
+
+
+        $lists = WithdrawApply::alias('w')
+            ->field('w.*, u.nickname,u.avatar, u.sn as user_sn, u.mobile, ul.name as user_level_name')
+            ->with('user')
+            ->leftJoin('user u', 'u.id = w.user_id')
+            ->leftJoin('user_level ul', 'ul.id = u.level')
+            ->where($where)
+            ->page($get['page'], $get['limit'])
+            ->order('w.id desc')
+            ->select();
+        $count = WithdrawApply::alias('w')
+            ->field('w.*, u.nickname,u.avatar, u.sn as user_sn, u.mobile, ul.name as user_level_name')
+            ->leftJoin('user u', 'u.id = w.user_id')
+            ->leftJoin('user_level ul', 'ul.id = u.level')
+            ->where($where)
+            ->order('w.id desc')
+            ->count();
+
+
+        foreach ($lists as &$item) {
+            if (empty($item['user'])) {
+                // 用户不存在
+                $user = [
+                    'avatar' => '',
+                    'sn' => '-',
+                    'nickname' => '-',
+                ];
+            } else {
+                $user  = $item['user'];
+            }
+            $item['type_text'] = WithdrawEnum::getTypeDesc($item['type']);
+            $item['status_text'] = WithdrawEnum::getStatusDesc($item['status']);
+            $item['avatar'] = UrlServer::getFileUrl($item['avatar']);
+            $user['avatar'] = UrlServer::getFileUrl($user['avatar']);
+            $item['user_level_name'] = $item['user_level_name'] ? $item['user_level_name'] : '无等级';
+            $user['user_level_name'] = $item['user_level_name'];
+            // 通过中间变量$user解决Indirect modification of overloaded element报错
+            $item['user'] = $user;
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 数据汇总
+     * @return array
+     * @author suny
+     * @date 2021/7/14 10:01 上午
+     */
+    public static function summary()
+    {
+
+        $model = new WithdrawApply();
+        $successWithdraw = $model->where(['status' => WithdrawEnum::STATUS_SUCCESS])->sum('money');
+        $handleWithdraw = $model->where(['status' => WithdrawEnum::STATUS_ING])->sum('money');
+        $totalEarnings = (new User())->where(['del' => 0])->sum('earnings');
+
+        return ['successWithdraw' => $successWithdraw, 'handleWithdraw' => $handleWithdraw, 'totalEarnings' => $totalEarnings];
+    }
+
+    /**
+     * @notes 佣金明细
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:01 上午
+     */
+    public static function commission($get, $is_export = false)
+    {
+
+        $where = [];
+
+        // 明细类型
+        $source_type = AccountLog::earnings_change;
+        if (isset($get['source_type']) && !empty($get['source_type'])) {
+            $where[] = ['a.source_type', '=', $get['source_type']];
+        } else {
+            $where[] = ['a.source_type', 'in', $source_type];
+        }
+
+        //明细搜索
+        if (!empty($get['search_key']) && !empty($get['keyword'])) {
+            $keyword = $get['keyword'];
+            switch ($get['search_key']) {
+                case  'user_sn' :
+                    $where[] = ['u.sn', '=', $keyword];
+                    break;
+                case  'nickname' :
+                    $where[] = ['u.nickname', 'like', '%' . $keyword . '%'];
+                    break;
+            }
+        }
+
+        if (empty($get['start_time']) && empty($get['end_time'])) {
+            $where[] = ['a.create_time', '>=', strtotime(date("Y-m-d", time()))];
+            $where[] = ['a.create_time', '<=', strtotime(date("Y-m-d", time())) + 86399];
+        }
+
+        //明细时间
+        if (isset($get['start_time']) && $get['start_time'] != '') {
+            $where[] = ['a.create_time', '>=', strtotime($get['start_time'])];
+        }
+
+        if (isset($get['end_time']) && $get['end_time'] != '') {
+            $where[] = ['a.create_time', '<=', strtotime($get['end_time'])];
+        }
+
+        // 导出
+        if (true === $is_export) {
+            return self::commissionExport($where);
+        }
+
+        $lists = AccountLog::alias('a')
+            ->field('a.*,u.nickname,u.sn as user_sn,u.mobile,w.sn as withdraw_sn')
+            ->join('user u', 'u.id = a.user_id')
+            ->leftjoin('withdraw_apply w', 'w.sn = a.source_sn')
+            ->where($where)
+            ->page($get['page'], $get['limit'])
+            ->order('a.id desc')
+            ->select();
+
+        $count = AccountLog::alias('a')
+            ->field('a.*,u.nickname,u.sn as user_sn,u.mobile,w.sn as withdraw_sn')
+            ->join('user u', 'u.id = a.user_id')
+            ->leftjoin('withdraw_apply w', 'w.sn = a.source_sn')
+            ->where($where)
+            ->order('a.id desc')
+            ->count();
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 账户明细
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:01 上午
+     */
+    public static function account($get, $is_export = false)
+    {
+
+        $where = [];
+
+        // 明细类型
+        $source_type = AccountLog::money_change;
+        if (isset($get['type']) && !empty($get['type'])) {
+            switch ($get['type']) {
+                case 'admin_add_money' :
+                    $type = AccountLog::admin_add_money;
+                    break;
+                case 'admin_reduce_money' :
+                    $type = AccountLog::admin_reduce_money;
+                    break;
+                case 'recharge_money' :
+                    $type = AccountLog::recharge_money;
+                    break;
+                case 'balance_pay_order' :
+                    $type = AccountLog::balance_pay_order;
+                    break;
+                case 'cancel_order_refund' :
+                    $type = AccountLog::cancel_order_refund;
+                    break;
+                case 'after_sale_refund' :
+                    $type = AccountLog::after_sale_refund;
+                    break;
+                case 'withdraw_to_balance' :
+                    $type = AccountLog::withdraw_to_balance;
+                    break;
+                case 'user_transfer_inc_balance' :
+                    $type = AccountLog::user_transfer_inc_balance;
+                    break;
+                case 'user_transfer_dec_balance' :
+                    $type = AccountLog::user_transfer_dec_balance;
+                    break;
+                case 'integral_order_inc_balance' :
+                    $type = AccountLog::integral_order_inc_balance;
+                    break;
+                case 'integral_order_dec_balance' :
+                    $type = AccountLog::integral_order_dec_balance;
+                    break;
+            }
+            $where[] = ['a.source_type', '=', $type];
+        } else {
+            $where[] = ['a.source_type', 'in', $source_type];
+        }
+
+        //明细搜索
+        if (!empty($get['search_key']) && !empty($get['keyword'])) {
+            $keyword = $get['keyword'];
+            switch ($get['search_key']) {
+                case  'user_sn' :
+                    $where[] = ['u.sn', '=', $keyword];
+                    break;
+                case  'nickname' :
+                    $where[] = ['u.nickname', 'like', '%' . $keyword . '%'];
+                    break;
+            }
+        }
+
+        if (empty($get['start_time']) && empty($get['end_time'])) {
+            $where[] = ['a.create_time', '>=', strtotime(date("Y-m-d", time()))];
+            $where[] = ['a.create_time', '<=', strtotime(date("Y-m-d", time())) + 86399];
+        }
+
+        //明细时间
+        if (isset($get['start_time']) && $get['start_time'] != '') {
+            $where[] = ['a.create_time', '>=', strtotime($get['start_time'])];
+        }
+
+        if (isset($get['end_time']) && $get['end_time'] != '') {
+            $where[] = ['a.create_time', '<=', strtotime($get['end_time'])];
+        }
+
+        // 导出
+        if (true === $is_export) {
+            return self::accountExport($where);
+        }
+
+        $lists = AccountLog::alias('a')
+            ->field('a.*,u.nickname,u.sn as user_sn,u.mobile')
+            ->join('user u', 'u.id = a.user_id')
+            ->where($where)
+            ->page($get['page'], $get['limit'])
+            ->order('a.id desc')
+            ->select();
+
+        $count = AccountLog::alias('a')
+            ->field('a.*,u.nickname,u.sn as user_sn,u.mobile')
+            ->join('user u', 'u.id = a.user_id')
+            ->where($where)
+            ->order('a.id desc')
+            ->count();
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 充值明细
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:01 上午
+     */
+    public static function recharge($get, $is_export = false)
+    {
+
+        $where = [];
+
+        //明细搜索
+        if (isset($get['search_key']) && !empty($get['search_key'])) {
+            $keyword = $get['keyword'];
+            switch ($get['search_key']) {
+                case  'nickname' :
+                    $where[] = ['u.nickname', 'like', '%' . $keyword . '%'];
+                    break;
+                case  'order_sn' :
+                    $where[] = ['order_sn', '=', $keyword];
+                    break;
+                case  'user_mobile' :
+                    $where[] = ['u.mobile', '=', $keyword];
+                    break;
+            }
+        }
+
+        //订单来源
+        if (isset($get['order_source']) && $get['order_source'] != '') {
+            $where[] = ['r.order_source', '=', $get['order_source']];
+        }
+
+        //订单状态
+        if (isset($get['pay_status']) && $get['pay_status'] != '') {
+            $where[] = ['r.pay_status', '=', $get['pay_status']];
+        }
+
+        //支付方式
+        if (isset($get['pay_way']) && $get['pay_way'] != '') {
+            $where[] = ['r.pay_way', '=', $get['pay_way']];
+        }
+
+        if (! empty($get['start_time']) && ! empty($get['end_time'])) {
+            $where[] = ['r.create_time', '>=', strtotime($get['start_time']) ];
+            $where[] = ['r.create_time', '<=', strtotime($get['end_time']) ];
+        }
+
+        // 导出
+        if (true === $is_export) {
+            return self::rechargeExport($where);
+        }
+
+        $lists = RechargeOrder::alias('r')
+            ->field('r.*,u.id,u.nickname,u.mobile')
+            ->join('user u', 'u.id = r.user_id')
+            ->where($where)
+            ->page($get['page'], $get['limit'])
+            ->order('r.id desc')
+            ->select();
+        foreach ($lists as $list) {
+            if (!empty($list['pay_time'])) {
+                $list['pay_time'] = date('Y-m-d H:i:s', $list['pay_time']);
+            }
+        }
+
+        $count = RechargeOrder::alias('r')
+            ->field('r.*,u.id,u.nickname,u.mobile')
+            ->join('user u', 'u.id = r.user_id')
+            ->where($where)
+            ->order('r.id desc')
+            ->count();
+
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 会员佣金提现详情
+     * @param $id
+     * @return array|\think\Model|null
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:01 上午
+     */
+    public static function detail($id)
+    {
+
+        $detail = WithdrawApply::alias('w')
+            ->field('w.*,u.sn as user_sn, u.nickname, u.mobile')
+            ->leftJoin('user u', 'u.id=w.user_id')
+            ->where('w.id', $id)
+            ->find();
+        $detail['money_qr_code'] = UrlServer::getFileUrl($detail['money_qr_code'] ?? '');
+        $detail['typeDesc'] = WithdrawEnum::getTypeDesc($detail['type']);
+        $detail['statusDesc'] = WithdrawEnum::getStatusDesc($detail['status']);
+        $detail['transfer_time'] = $detail['transfer_time'] ? date('Y-m-d H:i:s', $detail['transfer_time']) : '';
+        $detail['payment_time'] = $detail['payment_time'] ? date('Y-m-d H:i:s', $detail['payment_time']) : '';
+        return $detail;
+    }
+
+    /**
+     * @notes 审核通过
+     * @param $post
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @author suny
+     * @date 2021/7/14 10:02 上午
+     */
+    public static function confirm($post)
+    {
+        try {
+            $id = $post['id'];
+            $withdraw = WithdrawApply::where('id', $id)
+                ->find();
+            
+            // 判断提现单是否为待提现状态 1
+            if ($withdraw['status'] != 1) {
+                return [
+                    'code' => 0,
+                    'msg' => '不是待提现申请单'
+                ];
+            }
+            
+            //提现到钱包余额
+            if ($withdraw['type'] == WithdrawEnum::TYPE_BALANCE) {
+                $user = User::find($withdraw['user_id']);
+                $user->user_money = ['inc', $withdraw['left_money']];
+                $user->save();
+                AccountLogLogic::AccountRecord(
+                    $withdraw['user_id'],
+                    $withdraw['left_money'],
+                    1,
+                    AccountLog::withdraw_to_balance,
+                    '',
+                    $withdraw['id'],
+                    $withdraw['sn']
+                );
+                //更新提现申请单状态为提现成功
+                WithdrawApply::where('id', $id)
+                    ->update(['status' => WithdrawEnum::STATUS_SUCCESS, 'update_time' => time(), 'description' => $post['description']]);
+                
+                return [
+                    'code' => 1,
+                    'msg' => '提现至钱包余额成功'
+                ];
+            }
+            //提现到微信零钱
+            if ($withdraw['type'] == WithdrawEnum::TYPE_WECHAT_CHANGE) {
+                // 先更新审核备注
+                WithdrawApply::where('id', $id)
+                    ->update(['update_time' => time(), 'description' => $post['description']]);
+                
+                //微信零钱接口:1-企业付款到零钱;2-商家转账到零钱
+                $transfer_way = ConfigServer::get('withdraw', 'transfer_way',1);
+                if ($transfer_way == 1) {
+                    return WechatCorporatePaymentLogic::pay($withdraw);
+                }
+                if ($transfer_way == 2) {
+                    return WechatMerchantTransferLogic::transfer($withdraw);
+                }
+            }
+            
+            //提现到微信收款码、支付收款码
+            if ($withdraw['type'] == WithdrawEnum::TYPE_WECHAT_CODE || $withdraw['type'] == WithdrawEnum::TYPE_ALI_CODE || WithdrawEnum::TYPE_BANK) {
+                // 直接标识为提现中状态
+                WithdrawApply::where('id', $id)
+                    ->update(['status' => WithdrawEnum::STATUS_ING, 'update_time' => time(), 'description' => $post['description']]);
+                return [
+                    'code' => 1,
+                    'msg' => '审核通过,提现中'
+                ];
+            }
+            return [
+                'code' => 1,
+                'msg' => '审核通过,提现中'
+            ];
+        } catch(\Throwable $e) {
+            return [
+                'code' => 0,
+                'msg' => $e->getMessage(),
+            ];
+        }
+    }
+
+    /**
+     * @notes 审核拒绝
+     * @param $post
+     * @throws \think\exception\PDOException
+     * @author suny
+     * @date 2021/7/14 10:03 上午
+     */
+    public static function refuse($post)
+    {
+
+        Db::startTrans();
+        try {
+            $withdraw_apply = WithdrawApply::where('id', $post['id'])->find();
+            $withdraw_apply->status = WithdrawEnum::STATUS_FAIL; // 提现失败
+            $withdraw_apply->description = $post['description'];
+            $withdraw_apply->update_time = time();
+            $withdraw_apply->save();
+
+            //拒绝提现,回退佣金
+            $user = User::find($withdraw_apply['user_id']);
+            $user->earnings = ['inc', $withdraw_apply['money']];
+            $user->save();
+
+            //增加佣金变动记录
+            AccountLogLogic::AccountRecord(
+                $withdraw_apply['user_id'],
+                $withdraw_apply['money'],
+                1,
+                AccountLog::withdraw_back_earnings,
+                '',
+                $withdraw_apply['id'],
+                $withdraw_apply['sn']
+            );
+            Db::commit();
+        } catch (Exception $e) {
+            Db::rollback();
+        }
+    }
+
+    /**
+     * @notes 审核拒绝
+     * @param $post
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @author suny
+     * @date 2021/7/14 10:03 上午
+     */
+    public static function transferFail($post)
+    {
+
+        if (empty($post['transfer_description'])) {
+            return [
+                'code' => 0,
+                'msg' => '请填写转账说明'
+            ];
+        }
+        // 标识提现失败
+        WithdrawApply::where('id', $post['id'])->update([
+            'status' => 4, // 提现失败
+            'transfer_voucher' => $post['transfer_voucher'] ? $post['transfer_voucher'] : '',
+            'transfer_description' => $post['transfer_description'],
+            'update_time' => time()
+        ]);
+
+        $withdraw_apply = WithdrawApply::where('id', $post['id'])->find();
+        // 退回佣金
+        $user = User::find($withdraw_apply['user_id']);
+        $user->earnings = ['inc', $withdraw_apply['money']];
+        $user->save();
+
+        //增加佣金变动记录
+        AccountLogLogic::AccountRecord(
+            $withdraw_apply['user_id'],
+            $withdraw_apply['money'],
+            1,
+            AccountLog::withdraw_back_earnings,
+            '',
+            $withdraw_apply['id'],
+            $withdraw_apply['sn']
+        );
+        return [
+            'code' => 1,
+            'msg' => '转账失败,提现金额已退回佣金账户'
+        ];
+    }
+
+    /**
+     * @notes 转账成功
+     * @param $post
+     * @return array
+     * @author suny
+     * @date 2021/7/14 10:03 上午
+     */
+    public static function transferSuccess($post)
+    {
+
+        if (empty($post['transfer_voucher'])) {
+            return [
+                'code' => 0,
+                'msg' => '请上传转账凭证'
+            ];
+        }
+
+        $post['transfer_voucher'] = UrlServer::getFileUrl($post['transfer_voucher']);
+
+        if (empty($post['transfer_description'])) {
+            return [
+                'code' => 0,
+                'msg' => '请填写转账说明'
+            ];
+        }
+        // 标识提现成功
+        WithdrawApply::where('id', $post['id'])->update([
+            'status' => 3, // 提现成功
+            'transfer_voucher' => $post['transfer_voucher'],
+            'transfer_description' => $post['transfer_description'],
+            'update_time' => time(),
+            'transfer_time' => time()
+        ]);
+
+        return [
+            'code' => 1,
+            'msg' => '转账成功'
+        ];
+    }
+
+    /**
+     * @notes 提现失败
+     * @param $id
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @author suny
+     * @date 2021/7/14 10:03 上午
+     */
+    public static function withdrawFailed($id)
+    {
+
+        $withdraw_apply = WithdrawApply::where('id', $id)->find();
+        $withdraw_apply->status = WithdrawEnum::STATUS_FAIL; // 提现失败
+        $withdraw_apply->update_time = time();
+        $withdraw_apply->save();
+
+        //拒绝提现,回退佣金
+        $user = User::find($withdraw_apply['user_id']);
+        $user->earnings = ['inc', $withdraw_apply['money']];
+        $user->save();
+
+        //增加佣金变动记录
+        AccountLogLogic::AccountRecord(
+            $withdraw_apply['user_id'],
+            $withdraw_apply['money'],
+            1,
+            AccountLog::withdraw_back_earnings,
+            '',
+            $withdraw_apply['id'],
+            $withdraw_apply['sn']
+        );
+    }
+
+    /**
+     * @notes 搜索
+     * @param $id
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:03 上午
+     */
+    public static function search($id)
+    {
+
+        $withdraw = WithdrawApply::where('id', $id)
+            ->find();
+
+        // 判断提现单是否为提现中状态 2 且 提现方式为 微信零钱 2
+        if ($withdraw['status'] == 2 && $withdraw['type'] == 2) {
+            //微信零钱接口:1-企业付款到零钱;2-商家转账到零钱
+            $transfer_way = ConfigServer::get('withdraw', 'transfer_way',1);
+            if ($transfer_way == 1) {
+                return WechatCorporatePaymentLogic::search($withdraw);
+            }
+            if ($transfer_way == 2) {
+                $result = WechatMerchantTransferLogic::details($withdraw);
+                // 记录查询结果
+                WithdrawApply::update(['update_time'=>time(),'pay_search_desc'=>json_encode($result, JSON_UNESCAPED_UNICODE)],['id'=>$withdraw['id']]);
+                if(isset($result['state'])) {
+                    if ($result['state'] == 'SUCCESS') {
+                        // 转账成功,标记提现申请单为提现成功,记录支付信息
+                        WithdrawApply::update(['status'=>3,'payment_no'=>$result['transfer_bill_no'],'payment_time'=>strtotime($result['update_time'])],['id'=>$withdraw['id']]);
+                        return ['code' => 1, 'msg' => '提现成功'];
+                    }
+                    if ($result['state'] == 'FAIL') {
+                        // 转账失败
+                        WithdrawApply::update(['status'=>4],['id'=>$withdraw['id']]);
+                        //回退佣金
+                        $user = User::find($withdraw['user_id']);
+                        $user->earnings = ['inc', $withdraw['money']];
+                        $user->save();
+
+                        //增加佣金变动记录
+                        AccountLogLogic::AccountRecord(
+                            $withdraw['user_id'],
+                            $withdraw['money'],
+                            1,
+                            AccountLog::withdraw_back_earnings,
+                            '',
+                            $withdraw['id'],
+                            $withdraw['sn']
+                        );
+                        return ['code' => 1, 'msg' => '提现至微信零钱失败'];
+                    }
+                    if ($result['state'] == 'PROCESSING') {
+                        return ['code' => 0, 'msg' => '正在处理中'];
+                    }
+                }else{
+                    return ['code' => 0, 'msg' => $result['message'] ?? '商家转账到零钱查询失败'];
+                }
+            }
+        } else {
+            return [
+                'code' => 0,
+                'msg' => '不是提现中的微信零钱申请单,无法查询'
+            ];
+        }
+    }
+
+
+
+    /**
+     * @notes 导出Excel
+     * @param array $where
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function rechargeExport($where)
+    {
+        try {
+            $lists = RechargeOrder::alias('r')
+                ->field('r.*,u.id,u.nickname,u.mobile')
+                ->join('user u', 'u.id = r.user_id')
+                ->where($where)
+                ->order('r.id desc')
+                ->select()->toArray();
+
+            foreach ($lists as &$list) {
+                if (!empty($list['pay_time'])) {
+                    $list['pay_time'] = date('Y-m-d H:i:s', $list['pay_time']);
+                }
+            }
+
+            $excelFields = [
+                'order_sn' => '订单编号',
+                'nickname' => '用户昵称',
+                'mobile' => '用户手机号',
+                'order_amount' => '充值金额',
+                'give_money' => '赠送金额',
+                'give_growth' => '赠送成长值',
+                'pay_way' => '支付方式',
+                'pay_time' => '支付时间',
+                'pay_status' => '订单状态',
+                'create_time' => '下单时间',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('充值明细');
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 导出Excel
+     * @param array $where
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function accountExport($where)
+    {
+        try {
+            $lists = AccountLog::alias('a')
+                ->field('a.*,u.nickname,u.sn as user_sn,u.mobile')
+                ->join('user u', 'u.id = a.user_id')
+                ->where($where)
+                ->order('a.id desc')
+                ->select();
+
+            $excelFields = [
+                'nickname' => '会员昵称',
+                'user_sn' => '会员编号',
+                'mobile' => '手机号码',
+                'change_amount' => '变动金额',
+                'left_amount' => '剩余金额',
+                'source_type' => '明细类型',
+                'source_sn' => '来源单号',
+                'create_time' => '记录时间',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('账户明细');
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 导出Excel
+     * @param array $condition
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function commissionExport($where)
+    {
+        try {
+            $lists = AccountLog::alias('a')
+                ->field('a.*,u.nickname,u.sn as user_sn,u.mobile,w.sn as withdraw_sn')
+                ->join('user u', 'u.id = a.user_id')
+                ->leftjoin('withdraw_apply w', 'w.sn = a.source_sn')
+                ->where($where)
+                ->order('a.id desc')
+                ->select();
+
+            $excelFields = [
+                'nickname' => '会员昵称',
+                'user_sn' => '会员编号',
+                'mobile' => '手机号码',
+                'change_amount' => '变动金额',
+                'left_amount' => '剩余佣金',
+                'source_type' => '明细类型',
+                'withdraw_sn' => '来源单号',
+                'create_time' => '记录时间',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('佣金明细');
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 导出Excel
+     * @param array $condition
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function withdrawExport($where)
+    {
+        try {
+            $lists = WithdrawApply::alias('w')
+                ->field('w.*, u.nickname,u.avatar, u.sn as user_sn, u.mobile, ul.name as user_level_name')
+                ->with('user')
+                ->leftJoin('user u', 'u.id = w.user_id')
+                ->leftJoin('user_level ul', 'ul.id = u.level')
+                ->where($where)
+                ->order('w.id desc')
+                ->select();
+
+            foreach ($lists as &$item) {
+                $item['type_text'] = WithdrawEnum::getTypeDesc($item['type']);
+                $item['status_text'] = WithdrawEnum::getStatusDesc($item['status']);
+            }
+
+            $excelFields = [
+                'sn' => '提现单号',
+                'nickname' => '会员昵称',
+                'user_sn' => '会员编号',
+                'mobile' => '手机号码',
+                'left_money' => '提现金额',
+                'type_text' => '提现方式',
+                'status_text' => '提现状态',
+                'remark' => '提现说明',
+                'create_time' => '提现时间',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('佣金提现');
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+}

+ 199 - 0
app/admin/logic/integral/IntegralGoodsLogic.php

@@ -0,0 +1,199 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\logic\integral;
+
+use app\common\basics\Logic;
+use app\common\enum\IntegralGoodsEnum;
+use app\common\model\integral\IntegralGoods;
+use app\common\server\UrlServer;
+
+
+/**
+ * 积分商品
+ * Class IntegralGoodsLogic
+ * @package app\admin\logic\kefu
+ */
+class IntegralGoodsLogic extends Logic
+{
+
+    public static function getLists($get)
+    {
+        $where = [
+            ['del', '=', 0]
+        ];
+        if (isset($get['type']) && is_numeric($get['type'])) {
+            $where[] = ['type', '=', $get['type']];
+        }
+        if (isset($get['status']) && is_numeric($get['status'])) {
+            $where[] = ['status', '=', $get['status']];
+        }
+        if (isset($get['name']) && $get['name'] != '') {
+            $where[] = ['name', 'like', '%' . $get['name'] . '%'];
+        }
+
+        $model = new IntegralGoods();
+        $lists = $model->field(true)
+            ->where($where)
+            ->order(['sort' => 'desc','id'=>'desc'])
+            ->paginate([
+                'page' => $get['page'],
+                'list_rows' => $get['limit'],
+                'var_page' => 'page'
+            ])
+            ->toArray();
+
+        foreach ($lists['data'] as &$item) {
+            $item['need'] = $item['need_integral'] . '积分+' . $item['need_money'] . '元';
+            if ($item['type'] == IntegralGoodsEnum::TYPE_BALANCE || $item['exchange_way'] == IntegralGoodsEnum::EXCHANGE_WAY_INTEGRAL) {
+                $item['need'] = $item['need_integral'] . '积分';
+            }
+            $item['type'] = IntegralGoodsEnum::getTypeDesc($item['type']);
+            $item['market_price'] = empty($item['market_price']) ? '-' : '¥' . $item['market_price'];
+        }
+
+        return ['count' => $lists['total'], 'lists' => $lists['data']];
+    }
+
+
+    /**
+     * @notes 添加商品
+     * @param $post
+     * @return bool
+     * @author 段誉
+     * @date 2022/2/25 18:27
+     */
+    public static function add($post)
+    {
+        try {
+            $storageUrl = UrlServer::getFileUrl();
+            $content = str_replace($storageUrl, '/', $post['content']);
+            IntegralGoods::create([
+                'name' => $post['name'],
+                'code' => $post['code'] ?? '',
+                'image' => $post['image'],
+                'type' => $post['type'],
+                'market_price' => $post['market_price'] ?? '',
+                'stock' => $post['stock'],
+                'status' => $post['status'],
+                'exchange_way' => $post['exchange_way'] ?? 1,
+                'need_integral' => $post['need_integral'],
+                'need_money' => $post['need_money'] ?? 0,
+                'delivery_way' => $post['delivery_way'] ?? 0,
+                'balance' => $post['balance'] ?? 0,
+                'express_type' => $post['express_type'] ?? 0,
+                'express_money' => $post['express_money'] ?? 0,
+                'content' => $content,
+                'sort' => $post['sort'] ?? 0,
+            ]);
+            return true;
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 编辑积分商品
+     * @param $post
+     * @return bool
+     * @author 段誉
+     * @date 2022/3/1 15:57
+     */
+    public static function edit($post)
+    {
+        try {
+            $storageUrl = UrlServer::getFileUrl();
+            $content = str_replace($storageUrl, '/', $post['content']);
+
+            // 包邮或无需快递,运费重置为0
+            if ($post['delivery_way'] == IntegralGoodsEnum::DELIVERY_NO_EXPRESS
+                || $post['express_type'] == IntegralGoodsEnum::EXPRESS_TYPE_FREE) {
+                $post['express_money'] = 0;
+                $post['express_type'] = IntegralGoodsEnum::EXPRESS_TYPE_FREE;
+            }
+
+            IntegralGoods::update([
+                'id'=>$post['id'],
+                'name' => $post['name'],
+                'code' => $post['code'] ?? '',
+                'image' => $post['image'],
+                'market_price' => $post['market_price'] ?? '',
+                'stock' => $post['stock'],
+                'status' => $post['status'],
+                'exchange_way' => $post['exchange_way'] ?? 1,
+                'need_integral' => $post['need_integral'],
+                'need_money' => $post['need_money'] ?? 0,
+                'delivery_way' => $post['delivery_way'] ?? 0,
+                'balance' => $post['balance'] ?? 0,
+                'express_type' => $post['express_type'],
+                'express_money' => $post['express_money'],
+                'content' => $content,
+                'sort' => $post['sort'] ?? 0,
+            ]);
+            return true;
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    public static function detail($id)
+    {
+        $detail = IntegralGoods::where(['id' => $id])->findOrEmpty();
+        return $detail;
+    }
+
+
+    /**
+     * @notes 切换状态
+     * @param $post
+     * @return IntegralGoods
+     * @author 段誉
+     * @date 2022/2/25 18:25
+     */
+    public static function switchStatus($post)
+    {
+         return IntegralGoods::update([
+             'status' => $post['status'],
+             'id' => $post['id']
+         ]);
+    }
+
+
+    /**
+     * @notes 删除商品
+     * @param $post
+     * @return IntegralGoods
+     * @author 段誉
+     * @date 2022/2/25 18:26
+     */
+    public static function del($post)
+    {
+        return IntegralGoods::update([
+            'id' => $post['id'],
+            'del' => 1,
+            'update_time' => time()
+        ]);
+    }
+
+
+}

+ 362 - 0
app/admin/logic/integral/IntegralOrderLogic.php

@@ -0,0 +1,362 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\logic\integral;
+
+
+use app\common\basics\Logic;
+use app\common\enum\IntegralOrderEnum;
+use app\common\enum\NoticeEnum;
+use app\common\enum\OrderLogEnum;
+use app\common\enum\PayEnum;
+use app\common\logic\IntegralOrderRefundLogic;
+use app\common\logic\OrderLogLogic;
+use app\common\model\Express;
+use app\common\model\integral\IntegralDelivery;
+use app\common\model\integral\IntegralOrder;
+use app\common\model\order\Order;
+use app\common\server\ConfigServer;
+use app\common\server\UrlServer;
+use expressage\Kd100;
+use expressage\Kdniao;
+use think\facade\Db;
+
+class IntegralOrderLogic extends Logic
+{
+    /**
+     * @notes 兑换订单列表
+     * @param array $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author ljj
+     * @date 2022/3/3 10:38 上午
+     */
+    public static function lists($get = [])
+    {
+        $order = new IntegralOrder();
+
+        $where = [];
+        //列表状态
+        if (isset($get['status']) && $get['status'] != '') {
+            $where[] = ['order_status', '=', $get['status']];
+        }
+        //兑换单号
+        if (isset($get['order_sn']) && $get['order_sn'] != '') {
+            $where[] = ['order_sn', 'like', '%' . $get['order_sn'] . '%'];
+        }
+        //商品名称
+        if (isset($get['goods_name']) && $get['goods_name'] != '') {
+            $where[] = ['goods_snap->name', 'like', '%' . $get['goods_name'] . '%'];
+        }
+        //兑换类型
+        if (isset($get['type']) && $get['type'] != '') {
+            $where[] = ['exchange_type', '=', intval($get['type'])];
+        }
+        //订单状态
+        if (isset($get['order_status']) && $get['order_status'] != '') {
+            $where[] = ['order_status', '=', $get['order_status']];
+        }
+        //下单时间
+        if (isset($get['start_time']) && $get['start_time'] != '') {
+            $where[] = ['create_time', '>=', strtotime($get['start_time'])];
+        }
+        if (isset($get['end_time']) && $get['end_time'] != '') {
+            $where[] = ['create_time', '<=', strtotime($get['end_time'])];
+        }
+
+        $count = $order->where($where)->count();
+
+        $lists = $order
+            ->field('*')
+            ->with(['user'])
+            ->where($where)
+            ->append(['pay_status_text', 'delivery_address', 'order_status_desc', 'type_desc'])
+            ->page($get['page'], $get['limit'])
+            ->order('id', 'desc')
+            ->select()
+            ->toArray();
+
+        foreach ($lists as $key=>&$list) {
+            $list['pay_time'] = $list['pay_time'] == '0' ? '未支付' : date('Y-m-d H:i:s', $list['pay_time']);
+            $list['user']['avatar'] = UrlServer::getFileUrl($list['user']['avatar']);
+            $list['goods_snap']['image'] = UrlServer::getFileUrl($list['goods_snap']['image']);
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    /**
+     * @notes 兑换订单详情
+     * @param $id
+     * @return array
+     * @author ljj
+     * @date 2022/3/3 11:10 上午
+     */
+    public static function detail($id)
+    {
+        $result = (new IntegralOrder())
+            ->with(['user'])
+            ->where('id', $id)
+            ->append(['delivery_address', 'pay_status_desc', 'order_status_desc','type_desc','pay_way_desc'])
+            ->findOrEmpty()
+            ->toArray();
+
+        $result['pay_time'] = $result['pay_time'] == '0' ? '未支付' : date('Y-m-d H:i:s', $result['pay_time']);
+        $result['confirm_time'] = empty($result['confirm_time']) ? '-' : date('Y-m-d H:i:s', $result['confirm_time']);
+        $result['user']['avatar'] = UrlServer::getFileUrl($result['user']['avatar']);
+        $result['goods_snap']['image'] = UrlServer::getFileUrl($result['goods_snap']['image']);
+
+        return $result;
+    }
+
+    /**
+     * @notes 发货详情
+     * @param $id
+     * @return array
+     * @author ljj
+     * @date 2022/3/3 11:48 上午
+     */
+    public static function deliveryDetail($id)
+    {
+        $result = (new IntegralOrder())
+            ->where('id', $id)
+            ->append(['delivery_address'])
+            ->findOrEmpty()
+            ->toArray();
+
+        $result['goods_snap']['image'] = UrlServer::getFileUrl($result['goods_snap']['image']);
+
+        return $result;
+    }
+
+    /**
+     * @notes 快递公司列表
+     * @return array|\think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author ljj
+     * @date 2022/3/3 11:35 上午
+     */
+    public static function express()
+    {
+        return Express::where('del', 0)->field('id,name')->select()->toArray();
+    }
+
+    /**
+     * @notes 发货操作
+     * @param $post
+     * @param $admin_id
+     * @author ljj
+     * @date 2022/3/3 2:53 下午
+     */
+    public static function deliveryHandle($post, $admin_id)
+    {
+        Db::startTrans();
+        try {
+            $order = IntegralOrder::where(['del'=>0,'id'=>$post['id']])->findOrEmpty()->toArray();
+
+            $shipping = Express::where('id',$post['shipping_id'])->findOrEmpty()->toArray();
+
+            //添加发货单
+            $delivery_data = [
+                'order_id' => $order['id'],
+                'order_sn' => $order['order_sn'],
+                'user_id' => $order['user_id'],
+                'admin_id' => $admin_id,
+                'consignee' => $order['consignee'],
+                'mobile' => $order['mobile'],
+                'province' => $order['province'],
+                'city' => $order['city'],
+                'district' => $order['district'],
+                'address' => $order['address'],
+                'invoice_no' => $post['invoice_no'],
+                'send_type' => 1,
+                'shipping_id' => $post['shipping_id'],
+                'shipping_name' => $shipping['name'],
+                'shipping_status' => 1,
+                'create_time' => time(),
+            ];
+            $delivery = IntegralDelivery::create($delivery_data);
+
+            //更新订单信息
+            IntegralOrder::update([
+                'update_time' => time(),
+                'shipping_time' => time(),
+                'shipping_status' => 1,
+                'order_status' => IntegralOrderEnum::ORDER_STATUS_GOODS,
+                'delivery_id' => $delivery->id,
+            ],['id'=>$order['id']]);
+
+            //通知用户发货
+            if (!empty($order['mobile'])) {
+                event('Notice', [
+                    'scene' => NoticeEnum::ORDER_DELIVERY_NOTICE,
+                    'mobile' => $order['mobile'],
+                    'params' => [
+                        'order_id' => $order['id'],
+                        'user_id' => $order['user_id'],
+                        'shipping_name' => $delivery_data['shipping_name'],
+                        'invoice_no' => $post['invoice_no'],
+                    ]
+                ]);
+            }
+
+            // 提交事务
+            Db::commit();
+            return true;
+        } catch (\Exception $e) {
+            // 回滚事务
+            Db::rollback();
+            return $e->getMessage();
+        }
+
+    }
+
+    /**
+     * @notes 物流信息
+     * @param $order_id
+     * @return array
+     * @author ljj
+     * @date 2022/3/3 3:31 下午
+     */
+    public static function shippingInfo($order_id)
+    {
+        $shipping = IntegralDelivery::where('order_id', $order_id)->findOrEmpty()->toArray();
+        $shipping['traces'] = self::getShipping($order_id);
+        return $shipping;
+    }
+
+    /**
+     * @notes 物流轨迹
+     * @param $order_id
+     * @return bool|string[]
+     * @author ljj
+     * @date 2022/3/3 3:31 下午
+     */
+    public static function getShipping($order_id)
+    {
+        $order = IntegralOrder::alias('o')
+            ->field('invoice_no,shipping_name,shipping_id,o.shipping_status,o.mobile')
+            ->join('integral_delivery d', 'd.order_id = o.id')
+            ->where(['o.id' => $order_id])
+            ->findOrEmpty()
+            ->toArray();
+
+        $express = ConfigServer::get('express', 'way', '', '');
+        $key = ConfigServer::get($express, 'appkey');
+        $app = ConfigServer::get($express, 'appsecret');
+
+        if (empty($express) || $order['shipping_status'] != 1 || empty($app) || empty($key)) {
+            return $traces[] = ['暂无物流信息'];
+        }
+        //快递配置设置为快递鸟时
+        if ($express === 'kdniao') {
+            $expressage = (new Kdniao($app, $key, true));
+            $shipping_field = 'codebird';
+        } else {
+            $expressage = (new Kd100($app, $key, true));
+            $shipping_field = 'code100';
+        }
+
+        //快递编码
+        $shipping_code = Db::name('express')
+            ->where(['id' => $order['shipping_id']])
+            ->value($shipping_field);
+
+        //获取物流轨迹
+        if ($shipping_code === 'SF' && $express === 'kdniao') {
+            $expressage->logistics($shipping_code, $order['invoice_no'], substr($order['mobile'],-4));
+        }else {
+            $expressage->logistics($shipping_code, $order['invoice_no']);
+        }
+        $traces = $expressage->logisticsFormat();
+        if ($traces == false) {
+            $traces[] = [$expressage->getError()];
+        } else {
+            foreach ($traces as &$item) {
+                $item = array_values(array_unique($item));
+            }
+        }
+        return $traces;
+    }
+
+    /**
+     * @notes 确认收货
+     * @param $order_id
+     * @param $admin_id
+     * @return bool
+     * @author ljj
+     * @date 2022/3/3 3:39 下午
+     */
+    public static function confirm($order_id, $admin_id)
+    {
+        IntegralOrder::update([
+            'order_status' => IntegralOrderEnum::ORDER_STATUS_COMPLETE,
+            'update_time' => time(),
+            'confirm_time' => time(),
+        ],['id'=>$order_id]);
+
+        return true;
+    }
+
+
+    /**
+     * @notes 取消订单
+     * @param $id
+     * @return bool
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/3/3 18:49
+     */
+    public static function cancel($id)
+    {
+        Db::startTrans();
+        try {
+            $order = IntegralOrder::findOrEmpty($id);
+
+            // 更新订单状态, 退回库存, 扣减销量
+            IntegralOrderRefundLogic::cancelOrder($id);
+
+            // 退回已支付积分
+            IntegralOrderRefundLogic::refundOrderIntegral($id);
+
+            // 退回订单已支付积分或已支付金额
+            if ($order['pay_status'] == PayEnum::ISPAID) {
+                IntegralOrderRefundLogic::refundOrderAmount($id);
+            }
+
+            Db::commit();
+            return true;
+
+        } catch (\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+
+            IntegralOrderRefundLogic::addRefundLog(
+                $order, $order['order_amount'],
+                2, $e->getMessage()
+            );
+            return false;
+        }
+    }
+}

+ 102 - 0
app/admin/logic/kefu/KefuLangLogic.php

@@ -0,0 +1,102 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop100%开源免费商用商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | 商业版本务必购买商业授权,以免引起法律纠纷
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshopTeam
+// +----------------------------------------------------------------------
+namespace app\admin\logic\kefu;
+
+use app\common\model\kefu\KefuLang;
+
+/**
+ * 客服术语逻辑层
+ * Class KefuLangLogic
+ * @package app\admin\logic\kefu
+ */
+class KefuLangLogic
+{
+
+    /**
+     * @notes 获取列表
+     * @param $limit
+     * @param $page
+     * @return array
+     * @throws \think\db\exception\DbException
+     * @author cjhao
+     * @date 2021/11/29 15:11
+     */
+    public static function lists(int $limit,int $page)
+    {
+        $list = KefuLang::where(['shop_id' => 0])->order('sort asc')->paginate([
+                'list_rows' => $limit,
+                'page'      => $page,
+            ]);
+        return ['count' => $list->total(), 'lists' => $list->getCollection()];
+    }
+
+
+    /**
+     * @notes 新增话术
+     * @param $post
+     * @return bool
+     * @author cjhao
+     * @date 2021/11/29 15:54
+     */
+    public static function add(array $post)
+    {
+        $kefu_lang = new KefuLang();
+        $kefu_lang->title   = $post['title'];
+        $kefu_lang->content = $post['content'];
+        $kefu_lang->sort    = $post['sort'];
+        return $kefu_lang->save();
+    }
+
+    /**
+     * @notes 编辑话术
+     * @param $post
+     * @return bool
+     * @author cjhao
+     * @date 2021/11/29 15:59
+     */
+    public static function edit(array $post){
+        return KefuLang::update($post);
+    }
+
+
+    /**
+     * @notes 获取话术
+     * @param $id
+     * @return array|\think\Model|null
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author cjhao
+     * @date 2021/11/29 16:02
+     */
+    public static function detail(int $id){
+        return KefuLang::where(['id'=>$id])->find();
+    }
+
+    /**
+     * @notes 删除话术
+     * @param int $id
+     * @return bool
+     * @author cjhao
+     * @date 2021/11/29 16:11
+     */
+    public static function del(int $id){
+        return KefuLang::destroy($id);
+    }
+}

+ 231 - 0
app/admin/logic/kefu/KefuLogic.php

@@ -0,0 +1,231 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\logic\kefu;
+
+use app\common\basics\Logic;
+use app\common\logic\ChatLogic;
+use app\common\model\Admin;
+use app\common\model\Client_;
+use app\common\model\kefu\Kefu;
+use app\common\model\Role;
+use app\common\server\UrlServer;
+use app\kefuapi\logic\LoginLogic;
+
+/**
+ * 客服逻辑
+ * Class KefuLogic
+ * @package app\admin\logic\index
+ */
+class KefuLogic extends Logic
+{
+
+    /**
+     * @notes 客服列表
+     * @param $get
+     * @return array
+     * @author 段誉
+     * @date 2021/11/26 18:44
+     */
+    public static function getLists($get)
+    {
+        $result = (new Kefu())->alias('k')
+            ->field("k.*,a.account")
+            ->join('admin a', 'a.id = k.admin_id')
+            ->where(['a.del' => 0, 'k.del' => 0, 'shop_id' => 0])
+            ->order('sort asc')->paginate([
+                'list_rows' => $get['limit'],
+                'page' => $get['page'],
+            ]);
+
+        foreach ($result as $value) {
+            $value['avatar'] = empty($value['avatar']) ? "" : UrlServer::getFileUrl($value['avatar']);
+        }
+
+        return ['count' => $result->total(), 'lists' => $result->getCollection()];
+    }
+
+
+    /**
+     * @notes 添加客服
+     * @param $post
+     * @return Kefu|false|\think\Model
+     * @author 段誉
+     * @date 2021/11/27 10:43
+     */
+    public static function add($post)
+    {
+        try {
+            return (new Kefu())->insertKefu($post);
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 编辑客服
+     * @param $post
+     * @return Kefu|false
+     * @author 段誉
+     * @date 2021/11/27 10:44
+     */
+    public static function edit($post)
+    {
+        try {
+
+            if ($post['disable'] == 1) {
+                ChatLogic::setChatDisable(0, $post['id']);
+            }
+
+            return (new Kefu())->updateKefu($post['id'], $post);
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 详情
+     * @param $id
+     * @return mixed
+     * @author 段誉
+     * @date 2021/11/27 10:44
+     */
+    public static function detail($id)
+    {
+        $detail = (new Kefu())->alias('k')
+            ->field("k.*, a.account, a.name")
+            ->join('admin a', 'a.id = k.admin_id')
+            ->where(['k.id' => $id, 'k.shop_id' => 0])
+            ->findOrEmpty();
+
+        $detail['avatar'] = !empty($detail['avatar']) ? UrlServer::getFileUrl($detail['avatar']) : '';
+       return $detail;
+    }
+
+
+    /**
+     * @notes 删除客服
+     * @param $post
+     * @return Kefu
+     * @author 段誉
+     * @date 2021/11/27 10:48
+     */
+    public static function del($post)
+    {
+        return (new Kefu())->delKefu($post['id']);
+    }
+
+
+    /**
+     * @notes 管理员列表
+     * @param $get
+     * @return array
+     * @throws \think\db\exception\DbException
+     * @author 段誉
+     * @date 2021/11/26 18:00
+     */
+    public static function getAdminLists($get)
+    {
+        // 角色名称
+        $role_column = (new Role())->getNameColumn();
+
+        // 已有客服列表
+        $kefu = (new Kefu())->where(['del' => 0, 'shop_id' => 0])->column("admin_id");
+
+        // 查询条件
+        $where[] = ['del', '=', 0];
+        $where[] = ['id', 'not in', $kefu];
+        if (isset($get['role_id']) && $get['role_id'] != '') {
+            $where[] = ['role_id', '=', $get['role_id']];
+        }
+        if (isset($get['name']) && $get['name'] != '') {
+            $where[] = ['name', 'like', "%{$get['name']}%"];
+        }
+
+        $result = (new Admin())->where($where)
+            ->hidden(['password', 'salt'])
+            ->paginate([
+                'list_rows' => $get['limit'],
+                'page' => $get['page'],
+            ]);
+
+        foreach ($result as $k => $item) {
+            if ($item['root'] == 1) {
+                $role = '超级管理员';
+            } else {
+                $role = $role_column[$item['role_id']] ?? '';
+            }
+            $result[$k]['role'] = $role;
+        }
+        return ['count' => $result->total(), 'lists' => $result->getCollection()];
+    }
+
+
+    /**
+     * @notes 设置客服状态
+     * @param $post
+     * @return Kefu
+     * @author 段誉
+     * @date 2021/11/26 18:32
+     */
+    public static function setStatus($post)
+    {
+        if ($post['disable'] == 1) {
+            ChatLogic::setChatDisable(0, $post['id']);
+        }
+        return (new Kefu())->updateStatus($post['id'], $post['disable']);
+    }
+
+
+    /**
+     * @notes 返回登录链接
+     * @param $id
+     * @return bool|string
+     * @author 段誉
+     * @date 2021/12/15 19:52
+     */
+    public static function login($id)
+    {
+        try{
+            $kefu = (new Admin())->alias('a')
+                ->field(['k.id', 'k.nickname', 'k.avatar', 'k.shop_id', 'a.account'])
+                ->join('kefu k', 'a.id = k.admin_id')
+                ->where(['k.id' => $id, 'k.shop_id' => 0, 'k.del' => 0])
+                ->findOrEmpty()->toArray();
+
+            if(empty($kefu)) {
+                throw new \Exception('该客服信息缺失');
+            }
+
+            $token = LoginLogic::createSession($kefu['id'], $kefu['shop_id'], Client_::pc);
+
+            return request()->domain() . '/kefu?token='. $token;
+
+        } catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+}

+ 219 - 0
app/admin/logic/live/LiveGoodsLogic.php

@@ -0,0 +1,219 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop100%开源免费商用商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | 商业版本务必购买商业授权,以免引起法律纠纷
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshopTeam
+// +----------------------------------------------------------------------
+namespace app\admin\logic\live;
+
+use app\common\basics\Logic;
+use app\common\enum\LiveGoodsEnum;
+use app\common\model\live\LiveGoods;
+use app\common\server\UrlServer;
+use app\common\server\WxMnpLiveServer;
+use think\facade\Db;
+
+
+/**
+ * 直播商品逻辑层
+ * Class LiveGoodsLogic
+ * @package app\admin\logic\live
+ */
+class LiveGoodsLogic extends Logic
+{
+
+    /**
+     * @notes 查询条件
+     * @param $params
+     * @return array
+     * @author 段誉
+     * @date 2023/2/16 21:17
+     */
+    public static function listsQuery($params)
+    {
+        $where[] = ['del', '=', 0];
+        if (!empty($params['goods_name'])) {
+            $where[] = ['name', 'like', '%' . $params['goods_name'] . '%'];
+        }
+        if (!empty($params['shop_id'])) {
+            $where[] = ['shop_id', '=', $params['shop_id']];
+        }
+
+        if (!empty($params['status'])) {
+            if ($params['status'] == 'ing') {
+                $where[] = ['sys_audit_status', 'in', [
+                    LiveGoodsEnum::SYS_AUDIT_STATUS_WAIT_PLATFORM,
+                    LiveGoodsEnum::SYS_AUDIT_STATUS_WAIT_WECHAT
+                ]];
+            }
+            if ($params['status'] == 'success') {
+                $where[] = ['sys_audit_status', '=', LiveGoodsEnum::SYS_AUDIT_STATUS_SUCCESS];
+            }
+            if ($params['status'] == 'fail') {
+                $where[] = ['sys_audit_status', '=', LiveGoodsEnum::SYS_AUDIT_STATUS_FAIL];
+            }
+        }
+        return $where;
+    }
+
+
+    /**
+     * @notes 直播商品列表
+     * @param $params
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2023/2/15 19:00
+     */
+    public static function lists($params)
+    {
+        $where = self::listsQuery($params);
+
+        $count = LiveGoods::where($where)->count();
+        $lists = LiveGoods::with(['shop'])->where($where)
+            ->order(['id' => 'desc'])
+            ->page($params['page'], $params['limit'])
+            ->append(['audit_status_text', 'price_text'])
+            ->select()->toArray();
+
+        foreach ($lists as &$item) {
+            $item['cover_img'] = UrlServer::getFileUrl($item['cover_img']);
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+
+    /**
+     * @notes 添加直播商品
+     * @param array $params
+     * @return bool
+     * @throws \GuzzleHttp\Exception\GuzzleException
+     * @author 段誉
+     * @date 2023/2/15 18:26
+     */
+    public static function audit(array $params)
+    {
+        Db::startTrans();
+        try {
+            if ($params['status'] == LiveGoodsEnum::SYS_AUDIT_STATUS_FAIL && empty($params['audit_remark'])) {
+                throw new \Exception('审核不通过请填写审核原因');
+            }
+
+            $liveGoods = LiveGoods::findOrEmpty($params['id'])->toArray();
+            if ($liveGoods['sys_audit_status'] > LiveGoodsEnum::SYS_AUDIT_STATUS_WAIT_PLATFORM) {
+                throw new \Exception('当前商品待微信审核或已审核完成');
+            }
+
+            // 更新信息
+            $update_data = [
+                'sys_audit_status' => $params['status'],
+                'audit_remark' => $params['audit_remark'] ?? '',
+            ];
+
+            if ($params['status'] == LiveGoodsEnum::SYS_AUDIT_STATUS_WAIT_WECHAT) {
+                $goods_res = self::addWechatGoods($liveGoods);
+                $update_data['wx_goods_id'] = $goods_res['goodsId'];
+                $update_data['wx_audit_id'] = $goods_res['auditId'];
+            }
+
+            // 提交审核,通过则待微信审核
+            LiveGoods::where(['id' => $params['id']])->update($update_data);
+
+            Db::commit();
+            return true;
+        } catch (\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 提交微信审核
+     * @param $goods
+     * @return bool
+     * @author 段誉
+     * @date 2023/2/17 10:06
+     */
+    public static function addWechatGoods($goods)
+    {
+        $data = [
+            'coverImgUrl' => $goods['cover_img_url'],
+            'name' => $goods['name'],
+            'priceType' => $goods['price_type'],
+            'price' => $goods['price'],
+            'price2' => $goods['price2'],
+            'url' => $goods['url'],
+        ];
+        return (new WxMnpLiveServer())->handle('addAndAuditGoods', $data);
+    }
+
+
+    /**
+     * @notes 直播商品详情
+     * @param $id
+     * @return array
+     * @author 段誉
+     * @date 2023/2/16 10:42
+     */
+    public static function detail($id)
+    {
+        $detail = LiveGoods::where(['id' => $id])
+            ->append(['price_type_text', 'price_tips', 'source_type_text', 'audit_status_text'])
+            ->findOrEmpty()->toArray();
+        $detail['cover_img'] = UrlServer::getFileUrl($detail['cover_img']);
+        return $detail;
+    }
+
+
+    /**
+     * @notes 删除直播商品
+     * @param array $params
+     * @return bool|string
+     * @author 段誉
+     * @date 2023/2/16 10:37
+     */
+    public static function del(array $params)
+    {
+        Db::startTrans();
+        try {
+            $goods = LiveGoods::findOrEmpty($params['id'])->toArray();
+            if ($goods['sys_audit_status'] < LiveGoodsEnum::SYS_AUDIT_STATUS_WAIT_WECHAT) {
+                throw new \Exception('当前商品暂不可删除');
+            }
+
+            LiveGoods::where(['id' => $params['id']])->update([
+                'del' => 1,
+                'update_time' => time()
+            ]);
+
+            // 删除微信商品库
+            if (!empty($goods['wx_goods_id'])) {
+                (new WxMnpLiveServer())->handle('delGoods', $goods['wx_goods_id']);
+            }
+
+            Db::commit();
+            return true;
+        } catch (\Exception $e) {
+            Db::rollback();
+            return $e->getMessage();
+        }
+    }
+
+
+}

+ 240 - 0
app/admin/logic/live/LiveRoomLogic.php

@@ -0,0 +1,240 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop100%开源免费商用商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | 商业版本务必购买商业授权,以免引起法律纠纷
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshopTeam
+// +----------------------------------------------------------------------
+namespace app\admin\logic\live;
+
+use app\common\basics\Logic;
+use app\common\enum\LiveRoomEnum;
+use app\common\exception\WechatException;
+use app\common\model\live\LiveRoom;
+use app\common\model\shop\Shop;
+use app\common\server\UrlServer;
+use app\common\server\WxMnpLiveServer;
+use think\facade\Db;
+
+/**
+ * 直播间逻辑层
+ * Class LiveRoomLogic
+ * @package app\admin\logic\live
+ */
+class LiveRoomLogic extends Logic
+{
+
+    /**
+     * @notes 列表条件
+     * @param $params
+     * @return array
+     * @author 段誉
+     * @date 2023/2/16 16:42
+     */
+    public static function listsQuery($params)
+    {
+        $where[] = ['del', '=', 0];
+        if (!empty($params['shop_id'])) {
+            $where[] = ['shop_id', '=', $params['shop_id']];
+        }
+        if (isset($params['status'])
+            && $params['status'] != ''
+            && in_array($params['status'], LiveRoomEnum::AUDIT_STATUS)) {
+            $where[] = ['audit_status', '=', $params['status']];
+        }
+        if (!empty($params['live_info'])) {
+            $where[] = ['name|anchor_name', 'like', '%' . $params['live_info'] . '%'];
+        }
+        if (!empty($params['live_status'])) {
+            $where[] = ['live_status', '=', $params['live_status']];
+        }
+        // 创建时间
+        if (isset($params['start_time']) && !empty($params['start_time'])) {
+            $where[] = ['start_time', '>=', strtotime($params['start_time'])];
+        }
+        if (isset($params['end_time']) && !empty($params['end_time'])) {
+            $where[] = ['end_time', '<=', strtotime($params['end_time'])];
+        }
+        return $where;
+    }
+
+
+    /**
+     * @notes 直播间列表
+     * @param $params
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2023/2/15 19:00
+     */
+    public static function lists($params)
+    {
+        $where = self::listsQuery($params);
+
+        $count = LiveRoom::where($where)->count();
+        $lists = LiveRoom::with(['shop'])->where($where)
+            ->order(['id' => 'desc'])
+            ->page($params['page'], $params['limit'])
+            ->append(['live_time_text', 'live_status_text', 'audit_status_text'])
+            ->select()->toArray();
+
+        foreach ($lists as &$item) {
+            $item['share_img'] = UrlServer::getFileUrl($item['share_img']);
+            $item['feeds_img'] = UrlServer::getFileUrl($item['feeds_img']);
+            $item['cover_img'] = UrlServer::getFileUrl($item['cover_img']);
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+
+
+    /**
+     * @notes 编辑
+     * @param array $params
+     * @return bool
+     * @throws \GuzzleHttp\Exception\GuzzleException
+     * @author 段誉
+     * @date 2023/2/16 10:34
+     */
+    public static function audit($params)
+    {
+        Db::startTrans();
+        try {
+            $room = LiveRoom::findOrEmpty($params['id']);
+            if ($room['status'] > LiveRoomEnum::AUDIT_STATUS_WAIT) {
+                throw new \Exception('该记录已审核');
+            }
+
+            if ($params['status'] == LiveRoomEnum::AUDIT_STATUS_FAIL && empty($params['audit_remark'])) {
+                throw new \Exception('审核不通过请填写审核原因');
+            }
+
+            $update_data = [
+                'audit_remark' => $params['audit_remark'] ?? '',
+                'audit_status' => $params['status'],
+            ];
+
+            // 如果是审核通过,把直播间数据提交到微信并更新本地直播数据
+            if ($params['status'] == LiveRoomEnum::AUDIT_STATUS_SUCCESS) {
+                $room_id = self::createWxLiveRoom($room);
+                $update_data['wx_room_id'] = $room_id;
+            }
+
+            // 直播间数据
+            LiveRoom::where(['id' => $params['id']])->update($update_data);
+
+            Db::commit();
+            return true;
+        } catch (\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 创建直播间
+     * @param $room
+     * @return mixed
+     * @throws WechatException
+     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
+     * @throws \GuzzleHttp\Exception\GuzzleException
+     * @author 段誉
+     * @date 2023/2/16 16:25
+     */
+    public static function createWxLiveRoom($room)
+    {
+        $data = [
+            'name' => $room['name'],
+            'startTime' => $room['start_time'],
+            'endTime' => $room['end_time'],
+            'anchorName' => $room['anchor_name'],
+            'anchorWechat' => $room['anchor_wechat'],
+            'createrWechat' => $room['anchor_wechat'],
+            'shareImg' => $room['share_img_id'],
+            'feedsImg' => $room['feeds_img_id'],
+            'coverImg' => $room['cover_img_id'],
+            'type' => $room['type'],
+            'isFeedsPublic' => $room['is_feeds_public'],
+            'closeLike' => $room['close_like'],
+            'closeGoods' => $room['close_goods'],
+            'closeComment' => $room['close_comment'],
+            'closeReplay' => $room['close_replay'],
+            'closeShare' => $room['close_share'],
+            'closeKf' => $room['close_kf'],
+        ];
+        $result = (new WxMnpLiveServer())->handle('createLiveRoom', $data);
+        return $result['roomId'];
+    }
+
+
+    /**
+     * @notes 直播间详情
+     * @param $id
+     * @return array
+     * @author 段誉
+     * @date 2023/2/16 10:42
+     */
+    public static function detail($id)
+    {
+        $detail = LiveRoom::where(['id' => $id])
+            ->append(['audit_status_text'])
+            ->findOrEmpty()->toArray();
+        $detail['start_time'] = date('Y-m-d H:i:s', $detail['start_time']);
+        $detail['end_time'] = date('Y-m-d H:i:s', $detail['end_time']);
+        $detail['share_img'] = UrlServer::getFileUrl($detail['share_img']);
+        $detail['feeds_img'] = UrlServer::getFileUrl($detail['feeds_img']);
+        $detail['cover_img'] = UrlServer::getFileUrl($detail['cover_img']);
+        return $detail;
+    }
+
+
+    /**
+     * @notes 推荐值排序
+     * @param $params
+     * @return LiveRoom
+     * @author 段誉
+     * @date 2023/2/16 16:44
+     */
+    public static function recommend($params)
+    {
+        return LiveRoom::update([
+            'id' => $params['id'],
+            'sort' => $params['sort'],
+        ]);
+    }
+
+
+    /**
+     * @notes 商家信息
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2023/2/16 14:10
+     */
+    public static function shopLists()
+    {
+        return Shop::field(['id', 'name'])
+            ->where(['del' => 0])
+            ->select()
+            ->toArray();
+    }
+
+
+}

+ 172 - 0
app/admin/logic/order/InvoiceLogic.php

@@ -0,0 +1,172 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\logic\order;
+
+
+use app\common\basics\Logic;
+use app\common\enum\ShopEnum;
+use app\common\model\order\Order;
+use app\common\model\order\OrderInvoice;
+use app\common\server\ExportExcelServer;
+
+
+/**
+ * 发票管理-逻辑
+ * Class InvoiceLogic
+ * @package app\shop\logic\order
+ */
+class InvoiceLogic extends Logic
+{
+
+    /**
+     * @notes 发票列表
+     * @param $get
+     * @param $shop_id
+     * @return array
+     * @author 段誉
+     * @date 2022/4/12 17:56
+     */
+    public static function getInvoiceLists($get, $is_export = false)
+    {
+        $where = [];
+        if (isset($get['status']) && is_numeric($get['status']) && $get['status'] != '') {
+            $where[] = ['i.status', '=', (int)$get['status']];
+        }
+
+        if (!empty($get['order_sn']) && $get['order_sn'] != '') {
+            $where[] = ['order_sn', 'like', '%'.$get['order_sn'].'%'];
+        }
+
+        if (isset($get['order_status']) && $get['order_status'] != '') {
+            $where[] = ['order_status', '=', $get['order_status']];
+        }
+
+        // 创建时间
+        if(isset($get['start_time']) && !empty($get['start_time'])) {
+            $where[] = ['o.create_time', '>=', strtotime($get['start_time']) ];
+        }
+
+        if(isset($get['end_time']) && !empty($get['end_time'])) {
+            $where[] = ['o.create_time', '<=', strtotime($get['end_time']) ];
+        }
+
+        if (true === $is_export) {
+            return self::export($where);
+        }
+
+        $field = ['i.*', 'o.order_sn', 'o.order_amount', 'order_status','o.create_time' => 'order_create_time'];
+
+        $model = new OrderInvoice();
+        $lists = $model->alias('i')->field($field)
+            ->join('order o', 'o.id = i.order_id')
+            ->order('i.id desc')
+            ->where($where)
+            ->append(['type_text', 'header_type_text', 'status_text'])
+            ->paginate([
+                'page'      => $get['page'] ?? 1,
+                'list_rows' => $get['limit'] ?? 10,
+                'var_page'  => 'page'
+            ])->toArray();
+
+        foreach ($lists['data'] as &$item) {
+            $item['order_status'] = Order::getOrderStatus($item['order_status']);
+            $item['order_create_time'] = date('Y-m-d h:i:s', $item['order_create_time']);
+        }
+
+        return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+    }
+
+
+    /**
+     * @notes 发票详情
+     * @param $id
+     * @return array
+     * @author 段誉
+     * @date 2022/4/12 18:55
+     */
+    public static function detail($id)
+    {
+        $invoice = OrderInvoice::with(['order_data'])
+            ->append(['type_text', 'header_type_text', 'status_text'])
+            ->findOrEmpty($id)
+            ->toArray();
+        return $invoice;
+    }
+
+
+    /**
+     * @notes 导出Excel
+     * @param array $condition
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function export($where)
+    {
+        try {
+            $field = ['i.*', 'o.order_sn', 'o.order_amount', 'order_status','o.create_time' => 'order_create_time',
+            's.name' => 'shop_name', 's.type' => 'shop_type'];
+
+            $lists = (new OrderInvoice())->alias('i')
+                ->field($field)
+                ->join('order o', 'o.id = i.order_id')
+                ->join('shop s', 's.id = i.shop_id')
+                ->order('i.id desc')
+                ->where($where)
+                ->append(['type_text', 'header_type_text', 'status_text'])
+                ->select()->toArray();
+
+            foreach ($lists as &$item) {
+                $item['order_status'] = Order::getOrderStatus($item['order_status']);
+                $item['order_create_time'] = date('Y-m-d h:i:s', $item['order_create_time']);
+                $item['shop_type'] = ShopEnum::getShopTypeDesc($item['shop_type']);
+            }
+
+            $excelFields = [
+                'shop_name' => '商家名称',
+                'shop_type' => '商家类型',
+                'order_sn' => '订单编号',
+                'order_amount' => '订单金额',
+                'order_status' => '订单状态',
+                'order_create_time' => '下单时间',
+                'type_text' => '发票类型',
+                'header_type_text' => '抬头类型',
+                'name' => '发票抬头',
+                'duty_number' => '税号',
+                'email' => '邮箱',
+                'status_text' => '开票状态',
+                'invoice_number' => '发票编号',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('发票');
+            $export->setExportNumber(['invoice_number']);
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+}

+ 539 - 0
app/admin/logic/order/OrderLogic.php

@@ -0,0 +1,539 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\logic\order;
+
+
+use app\common\basics\Logic;
+use app\common\enum\OrderEnum;
+use app\common\enum\ShopEnum;
+use app\common\model\order\Order;
+use app\common\enum\OrderLogEnum;
+use app\common\enum\PayEnum;
+use app\common\logic\OrderRefundLogic;
+use app\common\model\Express;
+use app\common\model\user\UserLevel;
+use app\common\server\ExportExcelServer;
+use app\common\server\UrlServer;
+use expressage\Kd100;
+use expressage\Kdniao;
+use app\common\server\ConfigServer;
+use think\facade\Db;
+use think\facade\Validate;
+
+
+/**
+ * 订单管理-逻辑
+ * Class GoodsLogic
+ * @package app\shop\logic\goods
+ */
+class OrderLogic extends Logic
+{
+    /**
+     * @notes 订单统计
+     * @param array $get
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:04 上午
+     */
+    public static function statistics($get = [], $is_export = false)
+    {
+        $order  = new Order();
+        $where  = static::getWhere($get);
+        $page   = $get['page'] ?? 1;
+        $limit  = $get['limit'] ?? 10;
+
+        if (Validate::must($get['page'] ?? '')) {
+            $page = $get['page'];
+        }
+
+        if (Validate::must($get['limit'] ?? '')) {
+            $limit = $get['limit'];
+        }
+
+        // 导出excel
+        if (true === $is_export) {
+            return self::export($where);
+        }
+
+        $field = 'o.*,s.name as shop_name,u.level';
+
+        $count = $order
+            ->alias('o')
+            ->field($field)
+            ->join('shop s', 's.id = o.shop_id')
+            ->join('user u', 'u.id = o.user_id')
+            ->join('order_goods g', 'g.order_id = o.id')
+            ->with(['order_goods', 'user', 'shop'])
+            ->where($where)
+            ->group('o.id')
+            ->count();
+
+        $lists = $order
+            ->alias('o')
+            ->field($field)
+            ->join('shop s', 's.id = o.shop_id')
+            ->join('user u', 'u.id = o.user_id')
+            ->join('order_goods g', 'g.order_id = o.id')
+            ->with(['order_goods', 'user', 'shop'])
+            ->where($where)
+            ->append([
+                'delivery_address', 'pay_status_text', 'order_source_text',
+                'order_status_text', 'delivery_type_text','order_type_text',
+                'pay_way_text',
+            ])
+            ->page($page, $limit)
+            ->order('o.id desc')
+            ->group('o.id')
+            ->select();
+
+        $user_level = UserLevel::where(['del'=>0])->column('name','id');
+
+        foreach ($lists as &$list) {
+            $list['pay_time'] = $list['pay_time'] == '0' ? '未支付' : date('Y-m-d H:i:s', $list['pay_time']);
+            $list['user']['avatar'] = UrlServer::getFileUrl($list['user']['avatar']);
+            $list['shop']['logo'] = UrlServer::getFileUrl($list['shop']['logo']);
+            foreach ($list['order_goods'] as $order_good) {
+                $order_good['image'] = UrlServer::getFileUrl($order_good['image']);
+            }
+
+            // 会员等级
+            $list['user_level'] = '暂无等级';
+            if(isset($user_level[$list['level']])) {
+                $list['user_level'] = $user_level[$list['level']];
+            }
+
+            //会员优惠
+            $list['member_amount'] = $list['member_amount'] ?? 0.00;
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    static function getWhere($data)
+    {
+        $where = [];
+        $where[] = [ 'o.del', '=', 0 ];
+        $where[] = [ 'o.delete', '=', 0 ];
+        
+        //订单状态选项卡
+        if (Validate::must($data['type'] ?? '')) {
+            $where[] = [ 'order_status', '=', $data['type'] ];
+        }
+        
+        //订单搜素
+        if (! empty($data['search_key']) && ! empty($data['keyword'])) {
+            $keyword = $data['keyword'];
+            switch ($data['search_key']) {
+                case 'order_sn':
+                    $where[] = ['o.order_sn', '=', $keyword];
+                    break;
+                case 'user_sn':
+                    $where[] = ['u.sn', '=', $keyword];
+                    break;
+                case 'shop_name':
+                    $where[] = ['s.name', 'like', '%' . $keyword . '%'];
+                    break;
+                case 'goods_name':
+                    $where[] = ['g.goods_name', 'like', '%' . $keyword . '%'];
+                    break;
+                case 'user_id':
+                    $where[] = ['o.user_id', '=', $keyword];
+                    break;
+                case 'nickname':
+                    $where[] = ['u.nickname', 'like', '%' . $keyword . '%'];
+                    break;
+                case 'user_mobile':
+                    $where[] = ['u.mobile', '=', $keyword];
+                    break;
+                case 'consignee':
+                    $where[] = ['consignee', '=', $keyword];
+                    break;
+                case 'consignee_mobile':
+                    $where[] = ['o.mobile', '=', $keyword];
+                    break;
+            }
+        }
+        
+        //商家名称
+        if (Validate::must($data['shop_name'] ?? '')) {
+            $where[] = [ 's.name', 'like', '%' . $data['shop_name'] . '%' ];
+        }
+        
+        //商品名称
+        if (Validate::must($data['goods_name'] ?? '')) {
+            $where[] = ['g.goods_name', 'like', '%' . $data['goods_name'] . '%'];
+        }
+        
+        //配送方式
+        if (Validate::must($data['delivery_type'] ?? '')) {
+            $where[] = ['o.delivery_type', '=', $data['delivery_type']];
+        }
+        
+        //订单状态
+        if (Validate::must($data['order_status'] ?? '')) {
+            $where[] = [ 'o.order_status', '=', $data['order_status'] ];
+        }
+        
+        //订单类型
+        if (Validate::must($data['order_type'] ?? '')) {
+            $where[] = [ 'o.order_type', '=', $data['order_type'] ];
+        }
+        
+        //付款方式
+        if (Validate::must($data['pay_way'] ?? '')) {
+            $where[] = [ 'o.pay_way', '=', $data['pay_way'] ];
+        }
+        
+        //订单来源
+        if (Validate::must($data['order_source'] ?? '')) {
+            $where[] = ['o.order_source', '=', $data['order_source']];
+        }
+    
+        //下单时间
+        if (Validate::must($data['start_time'] ?? '')) {
+            $where[] = ['o.create_time', '>=', strtotime($data['start_time'])];
+        }
+    
+        if (Validate::must($data['end_time'] ?? '')) {
+            $where[] = ['o.create_time', '<=', strtotime($data['end_time'])];
+        }
+        
+        return $where;
+    }
+
+    /**
+     * @notes 订单详情
+     * @param $id
+     * @return array|\think\Model|null
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:04 上午
+     */
+
+    public static function getDetail($id)
+    {
+        $order = new Order();
+        $result = $order
+            ->with(['user', 'order_goods', 'invoice'])
+            ->where('id', $id)
+            ->append(['delivery_address', 'pay_status_text', 'order_status_text', 'pay_way_text', 'order_type_text'])
+            ->find();
+        $result['pay_time'] = $result['pay_time'] == '0' ? '未支付' : date('Y-m-d H:i:s', $result['pay_time']);
+        $result['user']['avatar'] = UrlServer::getFileUrl($result['user']['avatar']);
+        foreach ($result['order_goods'] as &$order_goods) {
+            $order_goods['goods_image'] = empty($order_goods['spec_image']) ?
+                UrlServer::getFileUrl($order_goods['image']) : UrlServer::getFileUrl($order_goods['spec_image']);
+        }
+
+        // 自提提货时间
+        if ($result['delivery_type'] == OrderEnum::DELIVERY_TYPE_SELF && $result['verification_status']) {
+            $result['confirm_take_time'] = date('Y-m-d H:i:s', $result['confirm_take_time']);
+        } else {
+            $result['confirm_take_time'] = '';
+        }
+
+        //会员优惠
+        $result['member_amount'] = $result['member_amount'] ?? 0.00;
+
+        return $result;
+    }
+
+    /**
+     * @notes 物流信息
+     * @param $order_id
+     * @return array|\PDOStatement|string|\think\Model|null
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @author suny
+     * @date 2021/7/14 10:05 上午
+     */
+    public static function shippingInfo($order_id)
+    {
+        $shipping = Db::name('delivery')->where('order_id', $order_id)->find();
+        $shipping['traces'] = [];
+        if ($shipping) {
+            $shipping['create_time_text'] = date('Y-m-d H:i:s', $shipping['create_time']);
+            if ($shipping['send_type'] == 1) {
+                $shipping['traces'] = self::getShipping($order_id);
+            }
+        }
+        
+        return $shipping;
+    }
+
+    /**
+     * @notes 物流轨迹
+     * @param $order_id
+     * @return bool|string[]
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:05 上午
+     */
+    public static function getShipping($order_id)
+    {
+        $orderModel = new Order();
+        $order = $orderModel->alias('o')
+            ->field('invoice_no,shipping_name,shipping_id,o.shipping_status,o.mobile')
+            ->join('delivery d', 'd.order_id = o.id')
+            ->where(['o.id' => $order_id])
+            ->find();
+        $express = ConfigServer::get('express', 'way', '', '');
+        $key = ConfigServer::get($express, 'appkey', '', '');
+        $app = ConfigServer::get($express, 'appsecret', '', '');
+
+        if (empty($express) || $order['shipping_status'] != 1 || empty($app) || empty($key)) {
+            return $traces[] = ['暂无物流信息'];
+        }
+        //快递配置设置为快递鸟时
+        if ($express === 'kdniao') {
+            $expressage = (new Kdniao($app, $key, true));
+            $shipping_field = 'codebird';
+        } else {
+            $expressage = (new Kd100($app, $key, true));
+            $shipping_field = 'code100';
+        }
+
+        //快递编码
+        $shipping_code = Db::name('express')
+            ->where(['id' => $order['shipping_id']])
+            ->value($shipping_field);
+
+        //获取物流轨迹
+        if (in_array(strtolower($shipping_code ), [ 'sf', 'shunfeng' ])) {
+            if ($express === 'kdniao') {
+                $expressage->logistics($shipping_code, $order['invoice_no'], substr($order['mobile'],-4));
+            } else {
+                $expressage->logistics($shipping_code, $order['invoice_no'], $order['mobile']);
+            }
+        }else {
+            $expressage->logistics($shipping_code, $order['invoice_no']);
+        }
+
+        $traces = $expressage->logisticsFormat();
+        if ($traces == false) {
+            $traces[] = [$expressage->getError()];
+        } else {
+            foreach ($traces as &$item) {
+                $item = array_values(array_unique($item));
+            }
+        }
+        return $traces;
+    }
+
+    /**
+     * @notes 获取物流
+     * @return \think\Collection
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author suny
+     * @date 2021/7/14 10:05 上午
+     */
+    public static function express()
+    {
+
+        return Express::where('del', 0)->select();
+    }
+
+
+    /**
+     * @notes 取消订单(返回商品规格表库存)
+     * @param $order_id
+     * @param $admin_id
+     * @return bool|string
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     * @throws \think\exception\PDOException
+     * @author suny
+     * @date 2021/7/14 10:07 上午
+     */
+    public static function cancel($order_id, $admin_id)
+    {
+
+        Db::startTrans();
+        try {
+            $order = Order::where(['id' => $order_id], ['orderGoods'])->find();
+            //取消订单
+            OrderRefundLogic::cancelOrder($order_id, OrderLogEnum::TYPE_SHOP, $admin_id);
+            //已支付的订单,取消,退款
+            if ($order['pay_status'] == PayEnum::ISPAID) {
+                //更新订单状态
+                OrderRefundLogic::cancelOrderRefundUpdate($order);
+                //订单退款
+                OrderRefundLogic::refund($order, $order['order_amount'], $order['order_amount']);
+            }
+            Db::commit();
+
+            return true;
+
+        } catch (\Exception $e) {
+            Db::rollback();
+            //增加退款失败记录
+            OrderRefundLogic::addErrorRefund($order, $e->getMessage());
+            return $e->getMessage();
+        }
+    }
+
+
+    /**
+     * @notes 获取各列表数量
+     * @return int
+     * @author suny
+     * @date 2021/7/14 10:08 上午
+     */
+    public static function getAll()
+    {
+        $data = input();
+        
+        unset($data['type']);
+        
+        return Order::alias('o')
+            ->join('shop s', 's.id = o.shop_id')
+            ->join('user u', 'u.id = o.user_id')
+            ->join('order_goods g', 'g.order_id = o.id')
+            ->with(['order_goods', 'user', 'shop'])
+            ->where(static::getWhere($data))
+            ->group('o.id')
+            ->count();
+    }
+
+    /**
+     * @notes 拼装统计信息
+     * @param $order_status
+     * @return array
+     * @author suny
+     * @date 2021/7/14 10:08 上午
+     */
+    public static function getStat($order_status)
+    {
+        $data   = input();
+        
+        unset($data['type']);
+        
+        $result = [];
+        
+        foreach ($order_status as $status => $title) {
+            $num = Order::alias('o')
+                ->join('shop s', 's.id = o.shop_id')
+                ->join('user u', 'u.id = o.user_id')
+                ->join('order_goods g', 'g.order_id = o.id')
+                ->with(['order_goods', 'user', 'shop'])
+                ->where(static::getWhere($data))
+                ->where('o.order_status', $status)
+                ->group('o.id')
+                ->count();
+            
+            $result[] = [
+                'title'     => $title,
+                'status'    => $status,
+                'count'     => $num,
+            ];
+        }
+        
+        return $result;
+    }
+
+
+    /**
+     * @notes 导出Excel
+     * @param array $condition
+     * @return array|false
+     * @author 段誉
+     * @date 2022/4/24 10:10
+     */
+    public static function export($condition = [])
+    {
+        try {
+            $field = 'o.*,order_status as order_status_text,pay_way as pay_way_text,
+            o.delivery_type as delivery_type_text,order_type as order_type_text,
+            u.nickname,s.name as shop_name,s.type as shop_type';
+
+            $lists = Order::alias('o')
+                ->join('shop s', 's.id = o.shop_id')
+                ->join('user u', 'u.id = o.user_id')
+                ->join('order_goods g', 'g.order_id = o.id')
+                ->with(['order_goods'])
+                ->field($field)
+                ->where($condition)
+                ->append(['delivery_address', 'pay_status_text', 'order_source_text'])
+                ->order('o.id desc')
+                ->group('o.id')
+                ->select()
+                ->toArray();
+
+            foreach ($lists as &$item) {
+                $orderGoodsList = [];
+                $goodsItemList = [];
+                $goodsPriceList = [];
+                $goodsNumList = [];
+                foreach ($item['order_goods'] as $good) {
+                    $orderGoodsList[] = $good['goods_name'];
+                    $goodsItemList[] = $good['spec_value'];
+                    $goodsPriceList[] = $good['goods_price'];
+                    $goodsNumList[] = $good['goods_num'];
+                }
+                $item['order_goods_list'] = implode(';', $orderGoodsList);
+                $item['goods_item_list'] = implode(';', $goodsItemList);
+                $item['goods_price_list'] = implode(';', $goodsPriceList);
+                $item['goods_num_list'] = implode(';', $goodsNumList);
+                $item['shop_type'] = ShopEnum::getShopTypeDesc($item['shop_type']);
+            }
+
+            $excelFields = [
+                'shop_name' => '商家名称',
+                'shop_type' => '商家类型',
+                'order_sn' => '订单编号',
+                'order_type_text' => '订单类型',
+                'nickname' => '用户名称',
+                'order_goods_list' => '商品信息',
+                'goods_item_list' => '规格',
+                'goods_price_list' => '商品价格',
+                'goods_num_list' => '商品数量',
+                'order_amount' => '实付金额',
+                'consignee' => '收货人',
+                'mobile' => '收货人手机',
+                'delivery_address' => '收货地址',
+                'pay_status_text' => '支付状态',
+                'order_status_text' => '订单状态',
+                'create_time' => '下单时间',
+            ];
+
+            $export = new ExportExcelServer();
+            $export->setFileName('订单');
+            $result = $export->createExcel($excelFields, $lists);
+
+            return ['url' => $result];
+
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+}

+ 266 - 0
app/admin/logic/seckill/SeckillGoodsLogic.php

@@ -0,0 +1,266 @@
+<?php
+namespace app\admin\logic\seckill;
+
+use app\common\basics\Logic;
+use app\common\model\seckill\SeckillGoods;
+use app\common\model\seckill\SeckillTime;
+use app\common\model\goods\Goods;
+use app\common\server\UrlServer;
+use think\facade\Db;
+
+class SeckillGoodsLogic extends Logic
+{
+    /**
+     * 统计
+     */
+    public static function statistics()
+    {
+        // 秒杀中商品
+        $where = [
+            ['sg.del', '=', 0],
+            ['sg.review_status', '=', 1],
+        ];
+        $lists = SeckillGoods::alias('sg')
+            ->leftJoin('seckill_time st', 'st.id=sg.seckill_id')
+            ->field('sg.goods_id,sg.start_date,sg.end_date,st.start_time,st.end_time')
+            ->where($where)
+            ->group('sg.goods_id,sg.start_date,sg.end_date,st.start_time,st.end_time')
+            ->select()
+            ->toArray();
+        $now = time();
+        $now_date = date('Y-m-d', $now);
+        $unSeckillCount = 0;
+        foreach($lists as $key => $item) { // 检验是否在秒杀中
+            $start_date_time = strtotime($item['start_date']. ' 00:00:00');
+            $end_date_time = strtotime($item['end_date']. ' 23:59:59');
+            // 日期校验
+            if($now >= $start_date_time && $now <= $end_date_time) {
+                $start_time = strtotime($now_date. ' '. $item['start_time']);
+                $end_time = strtotime($now_date. ' '. $item['end_time']);
+                if($now >= $start_time && $now <= $end_time) {
+                    // 秒杀中的时段,无需处理
+                }else{
+                    unset($lists[$key]); // 未在秒杀时段
+                    ++$unSeckillCount ;
+                }
+            }else{
+                unset($lists[$key]); // 未在秒杀时间日期
+                ++$unSeckillCount;
+            }
+        }
+        $seckillCount = count($lists);
+
+        // 待审核
+        $waitReview = SeckillGoods::where(['del'=>0, 'review_status'=>0])->group('seckill_id,goods_id,start_date,end_date')->count();
+        // 审核拒绝
+        $refuseReview = SeckillGoods::where(['del'=>0, 'review_status'=>2])->group('seckill_id,goods_id,start_date,end_date')->count();
+//
+        return [
+            'unSeckillCount'  => $unSeckillCount,
+            'seckillCount'  => $seckillCount,
+            'waitReview' => $waitReview,
+            'refuseReview' => $refuseReview,
+        ];
+    }
+
+    public static function getTimeAll(){
+        $time_list =  SeckillTime::where(['del'=>0])->order('start_time asc')->select()->toArray();
+        foreach ($time_list as &$item){
+            $item['time'] = $item['start_time'].' ~ '.$item['end_time'];
+        }
+        return $time_list;
+    }
+
+    public static function goodsList($get)
+    {
+        $where = [
+            ['sg.del', '=', 0],
+        ];
+
+        // 商品名称
+        if(isset($get['name']) && !($get['name'] == '')) {
+            $where[] = ['g.name', 'like', '%'.trim($get['name']).'%'];
+        }
+
+        // 参与日期
+        if(isset($get['start_end']) && !empty($get['start_end'])) {
+            $start_end = explode('~', $get['start_end']);
+            $where[] = ['sg.start_date', '=', trim($start_end[0])];
+            $where[] = ['sg.end_date', '=', trim($start_end[1])];
+        }
+        // 参与时段
+        if(isset($get['seckill_id']) && !empty($get['seckill_id'])) {
+            $where[] = ['sg.seckill_id', '=', $get['seckill_id']];
+        }
+
+        $lists = SeckillGoods::alias('sg')
+            ->leftJoin('seckill_time st', 'st.id=sg.seckill_id')
+            ->leftJoin('goods g', 'sg.goods_id=g.id')
+            ->leftJoin('shop s', 's.id=sg.shop_id')
+            ->field('sg.seckill_id,sg.goods_id,review_status,review_desc,start_date,end_date,start_time,end_time,g.name,g.image,g.min_price,g.max_price,s.id as shop_id,s.name as shop_name,s.type as shop_type,s.logo as shop_logo')
+            ->where($where)
+            ->group('sg.seckill_id,sg.goods_id,review_status,review_desc,start_date,end_date,start_time,end_time,g.name,g.image,g.min_price,g.max_price,s.id,s.name,s.type,s.logo')
+            ->order(['sg.id' => 'desc'])
+            ->select()
+            ->toArray();
+        // 按类型提取数据
+        $unSeckill = [];
+        $seckill = [];
+        $waitReview = [];
+        $refuseReview = [];
+        $now = time();
+        $now_date = date('Y-m-d', $now);
+        foreach($lists as $key => $item) {
+            if($item['review_status'] == 0) { // 待审核
+                $waitReview[] = $item;
+                continue;
+            }else if($item['review_status'] == 2){ // 审核拒绝
+                $refuseReview[] = $item;
+                continue;
+            }else if($item['review_status'] == 1) { // 审核通过
+                $start_date_time = strtotime($item['start_date']. ' 00:00:00');
+                $end_date_time = strtotime($item['end_date']. ' 23:59:59');
+                // 日期校验
+                if($now >= $start_date_time && $now <= $end_date_time) {
+                    $start_time = strtotime($now_date. ' '. $item['start_time']);
+                    $end_time = strtotime($now_date. ' '. $item['end_time']);
+                    if($now >= $start_time && $now <= $end_time) {
+                        $seckill[] = $item;
+                        continue;
+                    }else{
+                        // 未在秒杀时段
+                        $unSeckill[] = $item;
+                        continue;
+                    }
+                }else{
+                    // 未在秒杀时间日期
+                    $unSeckill[] = $item;
+                    continue;
+                }
+            }
+        }
+
+        switch($get['type']) {
+            case 'seckill':
+                $lists = $seckill;
+                break;
+            case 'un_seckill':
+                $lists = $unSeckill;
+                break;
+            case 'wait_review':
+                $lists = $waitReview;
+                break;
+            case 'refuse_review':
+                $lists = $refuseReview;
+                break;
+        }
+        // 组装信息
+        $review_status_desc = ['待审核','审核通过','审核拒绝'];
+        $shop_type_desc = [1=>'官方自营', 2=>'入驻商家'];
+        foreach($lists as &$item) {
+            $item['shop_logo'] = empty($item['shop_logo']) ? '' : UrlServer::getFileUrl($item['shop_logo']);
+            // 秒杀价格
+            $price = SeckillGoods::where([
+                'del' => 0,
+                'seckill_id' => $item['seckill_id'],
+                'goods_id' => $item['goods_id'],
+                'start_date' => $item['start_date'],
+                'end_date' => $item['end_date'],
+            ])->column('price', 'id');
+            $seckill_min_price = min($price);
+            $seckill_max_price = max($price);
+            $item['seckill_price'] = $seckill_min_price == $seckill_max_price ? '¥ ' .$seckill_min_price : '¥ '. $seckill_min_price . ' ~ ¥ ' . $seckill_max_price;
+            // 商品价格
+            $item['goods_price'] = $item['min_price'] == $item['max_price'] ? '¥ ' .$item['min_price'] : '¥ '. $item['min_price'] .' ~ ¥ '. $item['max_price'];
+            // 参与日期
+            $item['date'] = $item['start_date'] . ' ~ ' . $item['end_date'];
+            // 参与时段
+            $item['time'] = $item['start_time'] . ' ~ ' . $item['end_time'];
+            // 审核状态
+            $item['review_status_desc'] = $review_status_desc[$item['review_status']];
+            // 商家类型
+            $item['shop_type_desc'] = $shop_type_desc[$item['shop_type']];
+        }
+
+        // 分页
+        $count = count($lists);
+        $index = ($get['page'] -1) * $get['limit'];
+        $lists = array_slice($lists, $index, $get['limit']);
+
+        // 返回
+        return [
+            'count' => $count,
+            'lists' => $lists,
+        ];
+    }
+
+    public static function getSeckillGoods($id,$seckill_id, $start_date, $end_date){
+        $skill_goods = SeckillGoods::alias('sg')
+            ->join('goods_item gi','sg.item_id = gi.id')
+            ->join('shop s', 's.id=sg.shop_id')
+            ->where(['sg.del'=>0,'sg.goods_id'=>$id,'sg.seckill_id'=>$seckill_id, 'sg.start_date'=>$start_date,'sg.end_date'=>$end_date])
+            ->field('sg.*,gi.image,gi.spec_value_str,gi.price as goods_price,s.name as shop_name')
+            ->select()
+            ->toArray();
+
+        $goods_id = $skill_goods[0]['goods_id'];
+        $goods = Goods::where(['del'=>0,'id'=>$goods_id])->field('image,name')->find()->toArray();
+
+        foreach ($skill_goods as &$item){
+            $item['name'] = $goods['name'];
+            if(!$item['image']){
+                $item['image'] = $goods['image'];
+            }
+
+            $item['date'] = $item['start_date'] . ' ~ ' . $item['end_date'];
+        }
+
+        return $skill_goods;
+    }
+
+    public static function reAudit($post)
+    {
+        try{
+            $updateData = [
+                'review_status' => 2,
+                'review_desc' => $post['reason'],
+                'update_time' => time()
+            ];
+            $where = [
+                'del' => 0,
+                'goods_id' => $post['goods_id'],
+                'seckill_id' => $post['seckill_id'],
+                'start_date' => $post['start_date'],
+                'end_date' => $post['end_date'],
+            ];
+            SeckillGoods::where($where)->update($updateData);
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function audit($post)
+    {
+        try{
+            $updateData = [
+                'review_status' => $post['audit_status'],
+                'review_desc' => $post['audit_remark'],
+                'update_time' => time()
+            ];
+            $where = [
+                'del' => 0,
+                'goods_id' => $post['goods_id'],
+                'seckill_id' => $post['seckill_id'],
+                'start_date' => $post['start_date'],
+                'end_date' => $post['end_date'],
+            ];
+            SeckillGoods::where($where)->update($updateData);
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+}

+ 73 - 0
app/admin/logic/seckill/SeckillTimeLogic.php

@@ -0,0 +1,73 @@
+<?php
+namespace app\admin\logic\seckill;
+
+use app\common\basics\Logic;
+use app\common\model\seckill\SeckillTime;
+use app\common\model\seckill\SeckillGoods;
+use think\facade\Db;
+
+class SeckillTimeLogic extends Logic
+{
+    public static function addTime($post){
+        try{
+            $post['create_time'] = time();
+            $post['update_time'] = time();
+            SeckillTime::create($post);
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function timeList($get){
+        $where[] = ['del','=',0];
+        $count = SeckillTime::where($where)->count();
+        $list = SeckillTime::where($where)
+            ->order('start_time asc')
+            ->page($get['page'], $get['limit'])
+            ->select()
+            ->toArray();
+        foreach ($list as &$item){
+            $item['time'] = $item['start_time'].' ~ '.$item['end_time'];
+        }
+        return ['count' => $count, 'list' => $list];
+    }
+
+    public static function getTime($id){
+        $seckillTime = SeckillTime::where(['del'=>0, 'id'=>$id])->findOrEmpty();
+        if($seckillTime->isEmpty()) {
+            return [];
+        }
+        return $seckillTime->toArray();
+    }
+
+    public static function editTime($post){
+        try{
+            $post['update_time'] = time();
+            SeckillTime::where(['id'=>$post['id']])->update($post);
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function delTime($id){
+        Db::startTrans();
+        try{
+            $update_data = [
+                'update_time'   => time(),
+                'del'           => 1,
+            ];
+            SeckillTime::where(['id'=>$id])->update($update_data);
+            SeckillGoods::where(['del'=>0, 'seckill_id'=>$id])->update($update_data);
+            Db::commit();
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            Db::rollback();
+            return false;
+        }
+    }
+}

+ 219 - 0
app/admin/logic/sign_daily/SignDailyLogic.php

@@ -0,0 +1,219 @@
+<?php
+
+
+namespace app\admin\logic\sign_daily;
+
+
+use app\common\basics\Logic;
+use app\common\model\sign_daily\SignDaily;
+use app\common\model\sign_daily\UserSign;
+use app\common\server\ConfigServer;
+use app\common\server\UrlServer;
+
+/**
+ * 签到逻辑
+ * Class SignDailyLogic
+ * @package app\admin\logic\sign_daily
+ */
+class SignDailyLogic extends Logic
+{
+
+    /**
+     * @notes 连续签到列表
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/2/17 14:30
+     */
+    public static function lists()
+    {
+        $where[] = ['type', '=', 2];
+        $where[] = ['del', '=', 0];
+        $count = SignDaily::where($where)->count();
+        $lists = SignDaily::where($where)->select();
+        foreach ($lists as $key => $sign) {
+            $tips = '';
+            if (1 == $sign['integral_status'] && $sign['integral'] > 0) {
+                $tips .= '赠送' . $sign['integral'] . '积分;';
+            }
+            if (1 == $sign['growth_status'] && $sign['growth'] > 0) {
+                $tips .= '赠送' . $sign['growth'] . '成长值;';
+            }
+            $lists[$key]['award_tips'] = $tips;
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+
+    /**
+     * @notes 签到记录
+     * @param $get
+     * @return array
+     * @author 段誉
+     * @date 2022/2/17 14:31
+     */
+    public static function record($get)
+    {
+        $where = [];
+        $where[] = ['us.del', '=', 0];
+        $where[] = ['u.del', '=', 0];
+        if (isset($get['keyword']) && $get['keyword']) {
+            $where[] = [$get['type'], 'like', '%' . $get['keyword'] . '%'];
+        }
+
+        $field = 'us.user_id,sn,nickname,avatar,mobile,sex,u.create_time ,days,integral,growth,
+            continuous_integral, continuous_growth,sign_time,mobile,us.sign_time';
+
+        $count = UserSign::alias('us')
+            ->join('user u', 'u.id = us.user_id')
+            ->where($where)
+            ->count();
+
+        $lists = UserSign::alias('us')
+            ->join('user u', 'u.id = us.user_id')
+            ->where($where)
+            ->field($field)
+            ->order('us.id desc')
+            ->page($get['page'], $get['limit'])
+            ->select();
+
+        foreach ($lists as &$item) {
+            $item['sign_time'] = date('Y-m-d H:i:s', $item['sign_time']);
+            $item['avatar'] = UrlServer::getFileUrl($item['avatar']);
+            if ($item['sex'] == 1) {
+                $item['sex'] = '男';
+            } elseif ($item['sex'] == 2) {
+                $item['sex'] = '女';
+            } else {
+                $item['sex'] = '未知';
+            }
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+
+    /**
+     * @notes 获取每日签到规则
+     * @return array
+     * @author 段誉
+     * @date 2022/2/17 14:31
+     */
+    public static function getSignRule()
+    {
+        $data = SignDaily::where(['type' => 1])->findOrEmpty();
+        $config = [
+            'instructions' => ConfigServer::get('sign_rule', 'instructions'),
+            'dailySign' => $data
+        ];
+        return $config;
+    }
+
+
+    /**
+     * @notes 设置每日签到规则
+     * @param $post
+     * @return bool
+     * @author 段誉
+     * @date 2022/2/17 14:31
+     */
+    public static function setSignRule($post)
+    {
+        try {
+            $rule = SignDaily::where(['del' => 0, 'type' => 1])->findOrEmpty();
+
+            $data = [
+                'integral' => empty($post['integral']) ? 0 : $post['integral'],
+                'growth' => empty($post['growth']) ? 0 : $post['growth'],
+                'integral_status' => $post['integral_status'],
+                'growth_status' => $post['growth_status'],
+            ];
+
+            if ($rule->isEmpty()) {
+                $data['type'] = 1;
+                $data['days'] = 0;
+                SignDaily::create($data);
+            } else {
+                SignDaily::update($data, ['id' => $rule['id']]);
+            }
+
+            ConfigServer::set('sign_rule', 'instructions', $post['instructions']);
+
+            return true;
+        } catch (\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 添加连续签到奖励
+     * @param $post
+     * @return SignDaily|\think\Model
+     * @author 段誉
+     * @date 2022/2/17 14:31
+     */
+    public static function add($post)
+    {
+        return SignDaily::create(
+            [
+                'type' => '2',
+                'days' => $post['days'],
+                'integral' => $post['integral'],
+                'integral_status' => $post['integral_status'],
+                'growth' => $post['growth'],
+                'growth_status' => $post['growth_status'],
+            ]
+        );
+    }
+
+
+    /**
+     * @notes 编辑连续签到奖励
+     * @param $post
+     * @return SignDaily
+     * @author 段誉
+     * @date 2022/2/17 14:31
+     */
+    public static function edit($post)
+    {
+        return SignDaily::update([
+            'id' => $post['id'],
+            'days' => $post['days'],
+            'integral' => $post['integral'],
+            'integral_status' => $post['integral_status'],
+            'growth' => $post['growth'],
+            'growth_status' => $post['growth_status'],
+        ]);
+    }
+
+
+    /**
+     * @notes 删除连续签到奖励
+     * @param $id
+     * @return SignDaily
+     * @author 段誉
+     * @date 2022/2/17 14:32
+     */
+    public static function del($id)
+    {
+        return SignDaily::update(['del' => 1, 'id' => $id]);
+    }
+
+
+    /**
+     * @notes 获取连续签到奖励详情
+     * @param $id
+     * @return array|\think\Model
+     * @author 段誉
+     * @date 2022/2/17 14:32
+     */
+    public static function getSignDaily($id)
+    {
+        return SignDaily::findOrEmpty($id);
+    }
+
+
+}

+ 297 - 0
app/admin/logic/team/ActivityLogic.php

@@ -0,0 +1,297 @@
+<?php
+
+
+namespace app\admin\logic\team;
+
+
+use app\common\basics\Logic;
+use app\common\enum\OrderEnum;
+use app\common\enum\OrderLogEnum;
+use app\common\enum\TeamEnum;
+use app\common\logic\OrderRefundLogic;
+use app\common\model\order\Order;
+use app\common\model\team\TeamActivity;
+use app\common\model\team\TeamFound;
+use app\common\model\team\TeamJoin;
+use app\common\server\UrlServer;
+use Exception;
+use think\facade\Db;
+
+class ActivityLogic extends Logic
+{
+    /**
+     * @Notes: 获取拼团活动
+     * @Author: 张无忌
+     * @param $get
+     * @return array|bool
+     */
+    public static function lists($get)
+    {
+        try {
+            $where = [];
+            $where[] = ['T.del', '=', 0];
+            if (!empty($get['datetime']) and $get['datetime']) {
+                list($start, $end) = explode(' - ', $get['datetime']);
+                $where[] = ['T.create_time', '>=', strtotime($start.' 00:00:00')];
+                $where[] = ['T.create_time', '<=', strtotime($end.' 23:59:59')];
+            }
+
+            if (!empty($get['shop']) and $get['shop']) {
+                $where[] = ['S.name|S.id', 'like', '%'.$get['shop'].'%'];
+            }
+
+            if (!empty($get['name']) and $get['name']) {
+                $where[] = ['G.name', 'like', '%'.$get['name'].'%'];
+            }
+
+            if (!empty($get['status']) and $get['status']) {
+                $where[] = ['T.status', '=', $get['status']];
+            }
+
+            if (!empty($get['type']) and $get['type']) {
+                $where[] = ['T.audit', '=', $get['type']-1];
+            }
+
+            $model = new TeamActivity();
+            $lists = $model->alias('T')->field(['T.*', 'S.name as shop_name,S.type as shop_type,S.logo'])
+                ->where($where)
+                ->with(['goods'])
+                ->join('goods G', 'G.id = T.goods_id')
+                ->join('shop S', 'S.id = T.shop_id')
+                ->paginate([
+                    'page' => $get['page'] ?? 1,
+                    'list_rows' => $get['limit'] ?? 20,
+                    'var_page' => 'page'
+                ])->toArray();
+
+            $teamFoundModel = new TeamFound();
+            $teamJoinModel =  new TeamJoin();
+            foreach ($lists['data'] as &$item) {
+                $item['activity_start_time'] = date('Y-m-d H:i', $item['activity_start_time']);
+                $item['activity_end_time'] = date('Y-m-d H:i', $item['activity_end_time']);
+                $item['status_text'] = TeamEnum::getTeamStatusDesc($item['status']);
+                $item['audit_text'] = TeamEnum::getTeamAuditDesc($item['audit']);
+                $item['logo'] = UrlServer::getFileUrl($item['logo']);
+                $item['shop_type'] = $item['shop_type'] == 1 ? '商家自营' : '入驻商家';
+
+                $item['team_count'] = $teamFoundModel->where(['team_activity_id'=>$item['id']])->count();
+                $item['success_found'] = $teamFoundModel->where(['status'=>1, 'team_activity_id'=>$item['id']])->count();
+                $item['join_found'] = $teamJoinModel->where(['team_activity_id'=>$item['id']])->count();
+            }
+
+            return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+        } catch (Exception $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
+     * @notes 拼团商品的开团记录
+     * @param $get
+     * @return array|bool
+     * @author 张无忌
+     * @date 2021/7/19 11:02
+     */
+    public static function record($get)
+    {
+        try {
+            $where = [];
+            $where[] = ['TF.shop_id', '=', (int)$get['shop_id']];
+            $where[] = ['TF.team_activity_id', '=', (int)$get['team_activity_id']];
+            if (isset($get['type']) and is_numeric($get['type']) and $get['type'] != 100) {
+                $where[] = ['status', '=', (int)$get['type']];
+            }
+
+            if (!empty($get['team_sn']) and $get['team_sn']) {
+                $where[] = ['team_sn', 'like', '%'.$get['team_sn'].'%'];
+            }
+
+            if (!empty($get['goods']) and $get['goods']) {
+                $where[] = ['goods_snap->name', 'like', '%'.$get['goods'].'%'];
+            }
+
+            if (!empty($get['datetime']) and $get['datetime']) {
+                list($start, $end) = explode(' - ', $get['datetime']);
+                $where[] = ['kaituan_time', '>=', strtotime($start.' 00:00:00')];
+                $where[] = ['kaituan_time', '<=', strtotime($end.' 23:59:59')];
+            }
+
+            $model = new TeamFound();
+            $lists = $model->alias('TF')->field(['TF.*,U.nickname,U.sn,U.avatar'])
+                ->join('user U', 'U.id = TF.user_id')
+                ->order('id desc')
+                ->where($where)
+                ->paginate([
+                    'page'      => $get['page'] ?? 1,
+                    'list_rows' => $get['limit'] ?? 20,
+                    'var_page'  => 'page'
+                ])->toArray();
+
+            foreach ($lists['data'] as &$item) {
+                $item['peopleJoin'] = $item['people'] . '/' . $item['join'];
+                $item['kaituan_time'] = date('Y-m-d H:i:s', $item['kaituan_time']);
+                $item['invalid_time'] = date('Y-m-d H:i:s', $item['invalid_time']);
+                $item['goods_snap']   = json_decode($item['goods_snap'], true);
+                $item['status_text'] = TeamEnum::getStatusDesc($item['status']);
+            }
+
+            return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+        } catch (Exception $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @notes 开团活动的开团记录统计
+     * @param $get
+     * @return mixed
+     * @author 张无忌
+     * @date 2021/7/19 11:05
+     */
+    public static function recordStatistics($get)
+    {
+        $where[] = ['shop_id', '=', (int)$get['shop_id']];
+        $where[] = ['team_activity_id', '=', (int)$get['id']];
+
+        $model = new TeamFound();
+        $detail['total']         = $model->where($where)->count();
+        $detail['stayStatus']    = $model->where($where)->where(['status'=>0])->count();
+        $detail['successStatus'] = $model->where($where)->where(['status'=>1])->count();
+        $detail['failStatus']    = $model->where($where)->where(['status'=>2])->count();
+        return $detail;
+    }
+
+
+    /**
+     * @Notes: 数据统计
+     * @Author: 张无忌
+     * @return mixed
+     */
+    public static function statistics()
+    {
+        $where[] = ['del', '=', 0];
+
+        $model = new TeamActivity();
+        $detail['total']       = $model->where($where)->count();
+        $detail['stayAudit']   = $model->where($where)->where(['audit'=>0])->count();
+        $detail['adoptAudit']  = $model->where($where)->where(['audit'=>1])->count();
+        $detail['refuseAudit'] = $model->where($where)->where(['audit'=>2])->count();
+        return $detail;
+    }
+
+
+    /**
+     * @Notes: 审核拼团活动
+     * @Author: 张无忌
+     * @param $post
+     * @return bool
+     */
+    public static function audit($post)
+    {
+        try {
+            if (!$post['audit'] and empty($post['explain'])) {
+                throw new \think\Exception('拒绝时请填写拒绝理由');
+            }
+
+            TeamActivity::update([
+                'audit' => $post['audit'],
+                'update_time' => time()
+            ], ['id'=>$post['id']]);
+
+            return true;
+        } catch (\Exception $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @Notes: 违规重审核
+     * @Author: 张无忌
+     * @param $id
+     * @return bool
+     */
+    public static function violation($id)
+    {
+        try {
+            TeamActivity::update([
+                'audit'  => 2,
+                'status' => 0,
+                'update_time' => time()
+            ], ['id' => $id]);
+
+            $team_ids = (new TeamFound())->where(['team_activity_id' => $id, 'status' => 0])->column('id');
+
+            $teamJoin = (new TeamJoin())->alias('TJ')
+                ->field(['TJ.*,O.order_sn,O.order_status,O.pay_status,O.refund_status,O.order_amount'])
+                ->where('team_id', 'in', $team_ids)
+                ->join('order O', 'O.id=TJ.order_id')
+                ->select()->toArray();
+
+            self::teamFail($teamJoin, $team_ids, time());
+
+            return true;
+        } catch (\Exception $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @Notes: 拼团活动详细
+     * @Author: 张无忌
+     * @param $id
+     * @return array
+     */
+    public static function detail($id)
+    {
+        $model = new TeamActivity();
+        $detail = $model->field(true)
+            ->with(['goods', 'teamGoods'])
+            ->findOrEmpty($id)
+            ->toArray();
+
+        $detail['activity_start_time'] = date('Y-m-d H:i:s', $detail['activity_start_time']);
+        $detail['activity_end_time'] = date('Y-m-d H:i:s', $detail['activity_end_time']);
+        return $detail;
+    }
+
+    /**
+     * @Notes: 拼团失败
+     * @Author: 张无忌
+     * @param $teamJoin (参团列表数据)
+     * @param $found_ids
+     * @param $time (时间)
+     * @throws \think\Exception
+     */
+    private static function teamFail($teamJoin, $found_ids, $time)
+    {
+        Db::startTrans();
+        try {
+            (new TeamFound())->whereIn('id', $found_ids)
+                ->update(['status'=>TeamEnum::TEAM_STATUS_FAIL, 'team_end_time'=>$time]);
+
+            foreach ($teamJoin as $item) {
+                TeamJoin::update(['status' => TeamEnum::TEAM_STATUS_FAIL, 'update_time' => $time], ['id' => $item['id']]);
+                if ($item['order_status'] == OrderEnum::ORDER_STATUS_DOWN) continue;
+                if ($item['refund_status'] != OrderEnum::REFUND_STATUS_NO_REFUND) continue;
+                $order = (new Order())->findOrEmpty($item['order_id'])->toArray();
+                // 取消订单
+                OrderRefundLogic::cancelOrder($order['id'], OrderLogEnum::TYPE_SYSTEM);
+                if ($order['pay_status'] == OrderEnum::PAY_STATUS_PAID) {
+                    // 更新订单状态
+                    OrderRefundLogic::cancelOrderRefundUpdate($order);
+                    // 订单退款
+                    OrderRefundLogic::refund($order, $order['order_amount'], $order['order_amount']);
+                }
+            }
+            Db::commit();
+        } catch (Exception $e) {
+            Db::rollback();
+            throw new \think\Exception($e->getMessage());
+        }
+    }
+}

+ 154 - 0
app/admin/logic/team/FoundLogic.php

@@ -0,0 +1,154 @@
+<?php
+
+
+namespace app\admin\logic\team;
+
+
+use app\common\basics\Logic;
+use app\common\enum\OrderEnum;
+use app\common\enum\TeamEnum;
+use app\common\model\order\Order;
+use app\common\model\team\TeamFound;
+use app\common\model\team\TeamJoin;
+use app\common\server\FileServer;
+use app\common\server\UrlServer;
+use Exception;
+
+class FoundLogic extends Logic
+{
+    /**
+     * @Notes: 开团列表
+     * @Author: 张无忌
+     * @param $get
+     * @return array|bool
+     */
+    public static function lists($get)
+    {
+        try {
+            $where = [];
+            if (isset($get['type']) and is_numeric($get['type']) and $get['type'] != 100) {
+                $where[] = ['status', '=', (int)$get['type']];
+            }
+
+            if (!empty($get['team_sn']) and $get['team_sn']) {
+                $where[] = ['team_sn', 'like', '%'.$get['team_sn'].'%'];
+            }
+
+            if (!empty($get['goods']) and $get['goods']) {
+                $where[] = ['goods_snap->name', 'like', '%'.$get['goods'].'%'];
+            }
+
+            if (!empty($get['datetime']) and $get['datetime']) {
+                list($start, $end) = explode(' - ', $get['datetime']);
+                $where[] = ['kaituan_time', '>=', strtotime($start.' 00:00:00')];
+                $where[] = ['kaituan_time', '<=', strtotime($end.' 23:59:59')];
+            }
+
+            $model = new TeamFound();
+            $lists = $model->alias('TF')->field(['TF.*,U.nickname,U.sn,U.avatar'])
+                ->join('user U', 'U.id = TF.user_id')
+                ->order('id desc')
+                ->where($where)
+                ->paginate([
+                    'page'      => $get['page'] ?? 1,
+                    'list_rows' => $get['limit'] ?? 20,
+                    'var_page'  => 'page'
+                ])->toArray();
+
+            foreach ($lists['data'] as &$item) {
+                $item['peopleJoin'] = $item['people'] . '/' . $item['join'];
+                $item['kaituan_time'] = date('Y-m-d H:i:s', $item['kaituan_time']);
+                $item['invalid_time'] = date('Y-m-d H:i:s', $item['invalid_time']);
+                $item['goods_snap']   = json_decode($item['goods_snap'], true);
+                $item['status_text'] = TeamEnum::getStatusDesc($item['status']);
+                $item['avatar'] = UrlServer::getFileUrl($item['avatar']);
+            }
+
+            return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+        } catch (Exception $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @Notes: 数据统计
+     * @Author: 张无忌
+     * @return mixed
+     */
+    public static function statistics()
+    {
+        $model = new TeamFound();
+        $detail['total']       = $model->count();
+        $detail['stayStatus']   = $model->where(['status'=>0])->count();
+        $detail['successStatus']  = $model->where(['status'=>1])->count();
+        $detail['failStatus'] = $model->where(['status'=>2])->count();
+        return $detail;
+    }
+
+    /**
+     * @Notes: 拼团详细
+     * @Author: 张无忌
+     * @param $id
+     * @return array
+     */
+    public static function detail($id)
+    {
+        $teamFound = (new TeamFound())->alias('TF')
+            ->field(['TF.*,U.sn,U.nickname,U.mobile'])
+            ->join('user U', 'U.id = TF.user_id')
+            ->where('TF.id', '=', intval($id))
+            ->findOrEmpty()->toArray();
+        $teamFound['kaituan_time'] = date('Y-m-d H:i:s', $teamFound['kaituan_time']);
+        $teamFound['invalid_time'] = date('Y-m-d H:i:s', $teamFound['invalid_time']);
+        $teamFound['team_end_time'] = date('Y-m-d H:i:s', $teamFound['team_end_time']);
+        $teamFound['status_text'] = TeamEnum::getStatusDesc($teamFound['status']);
+
+        return ['teamFound'=>$teamFound];
+    }
+
+    /**
+     * @Notes: 参团列表
+     * @Author: 张无忌
+     * @param $get
+     * @return array|bool
+     */
+    public static function join($get)
+    {
+        try {
+            $where[] = ['TJ.team_id', '=', $get['team_id']];
+
+            $model = new TeamJoin();
+            $lists = $model->alias('TJ')->field(['TJ.*,U.sn,U.nickname,U.avatar'])
+                ->join('user U', 'U.id = TJ.user_id')
+                ->where($where)
+                ->paginate([
+                    'page'      => $get['page'] ?? 1,
+                    'list_rows' => $get['limit'] ?? 20,
+                    'var_page'  => 'page'
+                ])->toArray();
+
+            $orderModel = new Order();
+            foreach ($lists['data'] as &$item) {
+                $item['identity'] = $item['identity'] == 1 ? '团长' : '团员';
+
+                $item['order'] = $orderModel->field([
+                        'id,order_sn,order_type,order_status,
+                        refund_status,pay_status,order_amount,create_time'
+                    ])
+                    ->with(['orderGoods'])
+                    ->findOrEmpty($item['order_id'])->toArray();
+
+                $item['order']['order_status'] = OrderEnum::getOrderStatus($item['order']['order_status']);
+                $item['order']['pay_status'] = OrderEnum::getPayStatus($item['order']['pay_status']);
+                $item['order']['refund_status'] = OrderEnum::getRefundStatus($item['order']['refund_status']);
+                $item['avatar'] = UrlServer::getFileUrl($item['avatar']);
+            }
+
+            return ['count'=>$lists['total'], 'lists'=>$lists['data']];
+        } catch (Exception $e) {
+            static::$error = $e->getMessage();
+            return false;
+        }
+    }
+}

+ 210 - 0
app/admin/logic/user/LevelLogic.php

@@ -0,0 +1,210 @@
+<?php
+namespace app\admin\logic\user;
+
+use app\common\basics\Logic;
+use app\common\model\user\User;
+use app\common\model\user\UserLevel;
+use app\common\server\UrlServer;
+use think\facade\Db;
+
+class LevelLogic extends Logic
+{
+    public static function lists($get)
+    {
+        $count = UserLevel::where(['del'=>0])->count();
+        $lists = UserLevel::where(['del'=>0])->order('growth_value', 'asc')->page($get['page'], $get['limit'])->select()->toArray();
+
+        foreach ($lists as &$item){
+            $item['image'] = UrlServer::getFileUrl($item['image']);
+            $item['background_image'] = UrlServer::getFileUrl($item['background_image']);
+        }
+        return ['count' => $count, 'lists' => $lists];
+    }
+
+    public static function add($post)
+    {
+        Db::startTrans();
+        try{
+            $userLevel = UserLevel::where(['name'=>trim($post['name']), 'del'=>0])->findOrEmpty();
+            if(!$userLevel->isEmpty()) {
+                throw new \think\Exception('等级名称已被使用,请更换后重试');
+            }
+            $userLevel = UserLevel::where(['growth_value'=>intval($post['growth_value']), 'del'=>0])->findOrEmpty();
+            if(!$userLevel->isEmpty()) {
+                throw new \think\Exception('指定成长值的等级已存在');
+            }
+            $time = time();
+            $data = [
+                'name' => trim($post['name']),
+                'growth_value' => intval($post['growth_value']),
+                'image' => clearDomain($post['image']),
+                'background_image' => clearDomain($post['background_image']),
+                'remark' => trim($post['remark']),
+                'discount' => $post['discount'],
+                'create_time' => $time,
+                'update_time' => $time,
+                'del' => 0
+            ];
+            UserLevel::create($data);
+            // 更新会员等级
+            $userArr = User::field('id,level,user_growth')->where('del', 0)->select()->toArray();
+            self::updateUserLevel($userArr);
+            Db::commit();
+            return true;
+        }catch(\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function getUserLevel($id){
+        $detail = UserLevel::where(['id'=>$id,'del'=>0])->findOrEmpty();
+        if($detail->isEmpty()) {
+            return [];
+        }
+        $detail = $detail->toArray();
+        $detail['image'] = UrlServer::getFileUrl($detail['image']);
+        $detail['background_image'] = UrlServer::getFileUrl($detail['background_image']);
+        return $detail;
+    }
+
+    public static function edit($post)
+    {
+        if(empty($post['discount']) || $post['discount'] === ''){
+            $post['discount'] = 10;
+        }
+        Db::startTrans();
+        try{
+            $userLevel = UserLevel::where([
+                ['name', '=', trim($post['name'])],
+                ['del', '=', 0],
+                ['id', '<>', $post['id']]
+            ])->findOrEmpty();
+            if(!$userLevel->isEmpty()) {
+                throw new \think\Exception('等级名称已被使用,请更换后重试');
+            }
+            $userLevel = UserLevel::where([
+                ['growth_value', '=', intval($post['growth_value'])],
+                ['del', '=', 0],
+                ['id', '<>', $post['id']]
+            ])->findOrEmpty();
+            if(!$userLevel->isEmpty()) {
+                throw new \think\Exception('指定成长值的等级已存在');
+            }
+            $time = time();
+            $data = [
+                'id' => $post['id'],
+                'name' => trim($post['name']),
+                'growth_value' => intval($post['growth_value']),
+                'image' => clearDomain($post['image']),
+                'background_image' => clearDomain($post['background_image']),
+                'discount' => $post['discount'],
+                'remark' => trim($post['remark']),
+                'update_time' => $time,
+                'del' => 0
+            ];
+            UserLevel::update($data);
+            // 更新会员等级
+            $userArr = User::field('id,level,user_growth')->where('del', 0)->select()->toArray();
+            self::updateUserLevel($userArr);
+            Db::commit();
+            return true;
+        }catch(\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function del($id)
+    {
+        Db::startTrans();
+        try{
+            $data = [
+                'id' => $id,
+                'del' => 1,
+                'update_time' => time()
+            ];
+            UserLevel::update($data);
+            // 更新会员等级
+            $userArr = User::field('id,level,user_growth')->where('del', 0)->select()->toArray();
+            self::updateUserLevel($userArr);
+            Db::commit();
+            return true;
+        }catch(\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * 更新会员等级
+     * 原则:只升不降
+     * $userArr 需要更新会员等级的用户数组,必须的字段:id,level,user_growth
+     */
+    public static function updateUserLevel($userArr)
+    {
+        // 所有会员等级
+        $userLevelArr = UserLevel::field('id,growth_value')->where('del', 0)
+            ->order('growth_value', 'desc')
+            ->select()
+            ->toArray();
+        if(empty($userLevelArr)) { // 未设置会员等级
+            // 全部会员等级统一更新为0
+            User::where('del', 0)->update([
+                'level' => 0,
+                'update_time' => time()
+            ]);
+        }
+        // 转格式,变为id为数组下标
+        $levelArr = [];
+        foreach($userLevelArr as $item) {
+            $levelArr[$item['id']] = $item;
+        }
+
+        $updateData = [];
+        foreach($levelArr as $level) {
+            $filterIds = []; // 本轮结束已处理的会员id
+            foreach($userArr as $user) {
+                if($user['user_growth'] >= $level['growth_value']) {
+                    $targetLevelGrwothValue = $level['growth_value']; // 目标会员等级成长值
+                    // 原会员等级成长值
+                    $originLevelGrowthValue = isset($levelArr[$user['level']]) ? $levelArr[$user['level']]['growth_value'] : 0;
+                    // 降级或等级一样,不处理直接下一轮循环
+                    if($originLevelGrowthValue > $targetLevelGrwothValue) {
+                        $filterIds[] = $user['id'];
+                        continue;
+                    }
+                    $updateData[] = ['id'=>$user['id'], 'level'=>$level['id']];
+                    $filterIds[] = $user['id'];
+                }
+            }
+            // 过滤已处理过的用户,避免重复更新
+            $userArr = array_filter($userArr, function($item) use ($filterIds){
+                return !in_array($item['id'], $filterIds);
+            });
+        }
+
+        // 剩余未处理的会员,若原有等级已被删除掉,直接置为0
+        foreach($userArr as $user) {
+            if(!isset($levelArr[$user['level']])) {
+                $updateData[] = ['id'=>$user['id'], 'level'=>0];
+            }
+        }
+        $userModel = new User();
+        $userModel->saveAll($updateData);
+    }
+
+    public static function getLevelList()
+    {
+        $levelArr = UserLevel::field('id,name')
+            ->where('del', 0)
+            ->order('growth_value', 'asc')
+            ->select()
+            ->toArray();
+        $levelArr[0] = ['id'=>0, 'name'=>'暂无等级'];
+        return $levelArr;
+    }
+}

+ 108 - 0
app/admin/logic/user/TagLogic.php

@@ -0,0 +1,108 @@
+<?php
+namespace app\admin\logic\user;
+
+use app\common\basics\Logic;
+use app\common\model\user\UserTag;
+use app\common\model\user\User;
+
+class TagLogic extends Logic
+{
+    public static function lists($get)
+    {
+        $lists = UserTag::where(['del'=>0])->page($get['page'], $get['limit'])->select()->toArray();
+        $count = UserTag::where(['del'=>0])->count();
+        return [
+            'lists' => $lists,
+            'count' => $count
+        ];
+    }
+
+    public static function add($post)
+    {
+        try{
+            // 判断新标签名称是否已被占用
+            $userTag = UserTag::where(['name'=>trim($post['name']), 'del'=>0])->findOrEmpty();
+            if(!$userTag->isEmpty()) {
+                throw new \think\Exception('标签名称已被使用,请换个名称重试');
+            }
+            $time = time();
+            $data = [
+                'name' => trim($post['name']),
+                'remark' => trim($post['remark']),
+                'create_time' => $time,
+                'update_time' => $time,
+                'del' => 0
+            ];
+            UserTag::create($data);
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function detail($id)
+    {
+       $userTag =  UserTag::where(['id'=>$id])->findOrEmpty();
+       if($userTag->isEmpty()) {
+           return [];
+       }
+       return $userTag->toArray();
+    }
+
+    public static function edit($post)
+    {
+        try{
+            $userTag = UserTag::where([
+                ['name', '=', trim($post['name'])],
+                ['id', '<>', trim($post['id'])],
+            ])->findOrEmpty();
+            if(!$userTag->isEmpty()){
+                throw new \think\Exception('标签名称已被使用,请换个名称重试');
+            }
+            $data = [
+                'id' => $post['id'],
+                'name' => trim($post['name']),
+                'remark' => trim($post['remark']),
+                'update_time' => time()
+            ];
+            UserTag::update($data);
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function del($id)
+    {
+        try{
+            // 查看是否有会员正在使用该标签,若有则不允许删除
+            $users = User::whereFindInSet('tag_ids',$id)->where('del',0)->count();
+            if($users) {
+                throw new \think\Exception('有会员正在使用该标签,无法删除');
+            }
+            $data = [
+                'id' => $id,
+                'update_time' => time(),
+                'del' => 1
+            ];
+            UserTag::update($data);
+            return true;
+        }catch(\Exception $e){
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function getTagList()
+    {
+        $tagArr = UserTag::field('id,name')
+            ->where('del', 0)
+            ->order('id', 'desc')
+            ->select()
+            ->toArray();
+
+        return $tagArr;
+    }
+}

+ 549 - 0
app/admin/logic/user/UserLogic.php

@@ -0,0 +1,549 @@
+<?php
+namespace app\admin\logic\user;
+
+use app\admin\validate\user\UserValidate;
+use app\api\cache\TokenCache;
+use app\common\basics\Logic;
+use app\common\enum\ClientEnum;
+use app\common\enum\OrderEnum;
+use app\common\logic\AccountLogLogic;
+use app\common\model\AccountLog;
+use app\common\model\Session;
+use app\common\model\user\User;
+use app\common\model\user\UserLevel;
+use app\common\model\user\UserTag;
+use app\common\server\UrlServer;
+use app\common\model\order\Order;
+use think\facade\Db;
+
+class UserLogic extends Logic
+{
+    public static function lists($get)
+    {
+        $where[] = ['del','=', '0'];
+
+        //查询
+        if(isset($get['keyword']) && $get['keyword']){
+            $where[] = [$get['keyword_type'],'like', '%'. trim($get['keyword']) . '%'];
+        }
+
+        //用户状态
+        if(isset($get['disable']) && $get['disable'] !== ''){
+            $where[] = ['disable', '=', $get['disable']];
+        }
+
+        //等级查询
+        if(isset($get['level']) && $get['level'] !== ''){
+            $where[] = ['level','=',$get['level']];
+        }
+
+        // 标签查询
+        if(isset($get['tag']) && $get['tag']){
+            $where[] = ['tag_ids','find in set',$get['tag']];
+        }
+
+        //注册来源
+        if(isset($get['client']) && $get['client']){
+            $where[] = ['client','=',$get['client']];
+        }
+
+        //消费金额
+        if(isset($get['total_amount_start']) && $get['total_amount_start']){
+            $where[] = ['total_order_amount','>=',$get['total_amount_start']];
+        }
+        if(isset($get['total_amount_end']) && $get['total_amount_end']){
+            $where[] = ['total_order_amount','<=',$get['total_amount_end']];
+        }
+
+        //注册时间
+        if(isset($get['start_time']) && $get['start_time']!=''){
+            $where[] = ['create_time','>=',strtotime($get['start_time'])];
+        }
+        if(isset($get['end_time']) && $get['end_time']!=''){
+            $where[] = ['create_time','<=',strtotime($get['end_time'])];
+        }
+
+        $user_count = User::where($where)->count();
+
+        $user_list = User::where($where)
+            ->field('id,sn,nickname,avatar,level,total_order_amount,tag_ids,client,login_time,create_time,user_growth,user_money,earnings,first_leader,disable,user_delete')
+            ->page($get['page'],$get['limit'])
+            ->order('id desc')
+            ->select()
+            ->toArray();
+
+        //会员等级
+        $user_level = UserLevel::where(['del'=>0])->column('name','id');
+        // 会员标签
+        $user_tag = UserTag::where(['del'=>0])->column('name', 'id');
+        // 注册来源
+        $client_list = ClientEnum::getClient(true);
+
+        foreach ($user_list as &$item){
+            // $item['nickname'] = htmlspecialchars($item['nickname']);
+            // 可提现金额
+            $item['earnings'] = empty($item['earnings']) ? 0 :  $item['earnings'];
+            // 总资产
+            $item['total_amount'] = $item['user_money'] + $item['earnings'];
+            // 会员等级
+            $item['level_name'] = '暂无等级';
+            if(isset($user_level[$item['level']])){
+                $item['level_name'] = $user_level[$item['level']];
+            }
+            // 头像
+            if ($item['avatar'] != '/static/common/image/default/user.png') {
+                $item['abs_avatar'] = $item['avatar'] ? UrlServer::getFileUrl($item['avatar']) : '';
+            } else {
+                $item['abs_avatar'] = '/static/common/image/default/user.png';
+            }
+            // 会员标签
+            $item['tag_str'] = '';
+            if(!empty($item['tag_ids'])) {
+                $tempArr = explode(',',$item['tag_ids']);
+                foreach($tempArr as $v) {
+                    $item['tag_str'] .= $user_tag[$v] . ',';
+                }
+                $item['tag_str'] = trim( $item['tag_str'], ',');
+            }
+            // 注册来源
+            $item['client_desc'] = $client_list[$item['client']];
+
+            // 上级推荐人
+            $item['first_leader_info'] = User::getUserInfo($item['first_leader']);
+
+            //推荐下级人数
+            $item['fans'] = User::where([
+                ['first_leader|second_leader', '=', $item['id']],
+                ['del', '=', 0]
+            ])->count();
+        }
+
+        return ['count'=>$user_count , 'lists'=>$user_list];
+    }
+
+    public static function setTag($post)
+    {
+        try{
+            User::where([
+                ['id', 'in', $post['user_ids']]
+            ])->update([
+                'tag_ids' => $post['tag_ids'],
+                'update_time' => time()
+            ]);
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function getUser($id)
+    {
+        $field = [
+            'id', 'sn','nickname','avatar','mobile','sex','birthday','tag_ids',
+            'remark','user_money','user_growth','user_integral','earnings', 'disable'
+        ];
+        $user = User::field($field)->where(['del' => 0, 'id' => $id])->findOrEmpty();
+
+        if($user->isEmpty()) {
+            return [];
+        }
+        // 头像
+        if($user['avatar']) {
+            $user['avatar'] = UrlServer::getFileUrl($user['avatar']);
+        }
+        // 会员标签
+        $user['tag_ids'] = json_encode(explode(',', $user['tag_ids']));
+
+        return $user->toArray();
+    }
+
+    public static function edit($post)
+    {
+        try{
+            $data = [
+                'id' => $post['id'],
+                'nickname' => $post['nickname'],
+                'avatar' => clearDomain($post['avatar']),
+                'mobile' => $post['mobile'],
+                'birthday' => strtotime($post['birthday']),
+                'tag_ids' => $post['select'],
+                'remark' => $post['remark'],
+                'disable' => $post['disable'],
+                'update_time' => time()
+            ];
+            User::update($data);
+
+            if ($post['disable']) {
+                $tokens = Session::where(['user_id' => $post['id']])->select()->toArray();
+                if(count($tokens) > 0) {
+                    foreach ($tokens as $item) {
+                        (new TokenCache($item['token']))->del();
+                    }
+                    Session::where(['user_id' => $post['id']])->update([
+                        'expire_time' => time(),
+                        'update_time' => time(),
+                    ]);
+                }
+            }
+
+            return true;
+        }catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function getInfo($id)
+    {
+        $field = [
+            'id', 'sn', 'nickname', 'avatar', 'birthday', 'sex', 'mobile', 'client',
+            'create_time','login_time', 'user_money', 'tag_ids', 'user_growth', 'earnings',
+            'first_leader', 'disable', 'user_delete'
+        ];
+        $user =  User::field($field)->findOrEmpty($id);
+
+        if($user->isEmpty()) {
+            return [];
+        }
+        $user =$user->toArray();
+        $orderWhere = [
+            'user_id' => $id,
+            'del' => 0,
+            'pay_status' => OrderEnum::PAY_STATUS_PAID
+        ];
+        // 上级推荐人
+        $user['first_leader_info'] = User::getUserInfo($user['first_leader']);
+        // 推荐下级人数
+        $user['fans'] = User::where([
+            ['first_leader|second_leader', '=', $user['id']],
+            ['del', '=', 0],
+        ])->count();
+        // 总资产
+        $user['assets'] = $user['user_money'] + $user['earnings'];
+        // 总订单数
+        $user['order_num'] = Order::where($orderWhere)->count();
+        // 总消费金额
+        $user['total_amount'] = Order::where($orderWhere)->sum('order_amount');
+        $user['total_amount'] = round($user['total_amount'] ,2);
+        // 平均消费单价
+        $user['avg_amount'] = Order::where($orderWhere)->avg('order_amount');
+        $user['avg_amount'] = round($user['avg_amount'], 2);
+        // 头像
+        $user['avatar'] = UrlServer::getFileUrl($user['avatar']);
+        // 客户端
+        $user['client_desc'] = ClientEnum::getClient($user['client']);
+        // 会员标签
+        $user_tag = UserTag::where(['del'=>0])->column('name', 'id');
+        $user['tag_str'] = '';
+        if(!empty($user['tag_ids'])) {
+            $tempArr = explode(',',$user['tag_ids']);
+            foreach($tempArr as $v) {
+                $user['tag_str'] .= $user_tag[$v] . ',';
+            }
+            $user['tag_str'] = trim( $user['tag_str'], ',');
+        }
+
+        return $user;
+    }
+
+    public static function adjustAccount($post)
+    {
+        Db::startTrans();
+        try{
+            $user = User::findOrEmpty($post['id']);
+            if($user->isEmpty()) {
+                throw new \Exception('用户不存在');
+            }
+            // 余额调整
+            if($post['type'] == 'money') {
+                if(empty($post['money'])) {
+                    throw new \Exception('请输入调整的余额');
+                }
+                if(empty($post['money_remark'])) {
+                    throw new \Exception('请输入余额备注');
+                }
+                if($post['money_handle'] == 1) { // 增加
+                    $user->user_money = $user->user_money + $post['money'];
+                    $user->save();
+                    AccountLogLogic::AccountRecord($user['id'], $post['money'],1,AccountLog::admin_add_money, $post['money_remark']);
+                }else{
+                    $user->user_money = $user->user_money - $post['money'];
+                    $user->save();
+                    AccountLogLogic::AccountRecord($user['id'], $post['money'],0,AccountLog::admin_reduce_money, $post['money_remark']);
+                }
+            }
+
+            // 成长值调整
+            if($post['type'] == 'growth') {
+                if(empty($post['growth'])) {
+                    throw new \Exception('请输入调整的成长值');
+                }
+                if(empty($post['growth_remark'])) {
+                    throw new \Exception('请输入成长值备注');
+                }
+                if($post['growth_handle'] == 1) { // 增加
+                    $user->user_growth = $user->user_growth + $post['growth'];
+                    $user->save();
+                    AccountLogLogic::AccountRecord($user['id'], $post['growth'],1,AccountLog::admin_add_growth, $post['growth_remark']);
+                }else{
+                    $user->user_growth = $user->user_growth - $post['growth'];
+                    $user->save();
+                    AccountLogLogic::AccountRecord($user['id'], $post['growth'],0,AccountLog::admin_reduce_growth, $post['growth_remark']);
+                }
+            }
+
+            // 积分调整
+            if($post['type'] == 'integral') {
+                if(empty($post['integral'])) {
+                    throw new \Exception('请输入调整的积分');
+                }
+                if(empty($post['integral_remark'])) {
+                    throw new \Exception('请输入积分调整备注');
+                }
+                if($post['integral_handle'] == 1) { // 增加
+                    $user->user_integral = $user->user_integral + $post['integral'];
+                    $user->save();
+                    AccountLogLogic::AccountRecord($user['id'], $post['integral'],1,AccountLog::admin_add_integral, $post['integral_remark']);
+                }else{
+                    $user->user_integral = $user->user_integral - $post['integral'];
+                    $user->save();
+                    AccountLogLogic::AccountRecord($user['id'], $post['integral'],0,AccountLog::admin_reduce_integral, $post['integral_remark']);
+                }
+            }
+
+
+            // 佣金调整
+            if($post['type'] == 'earnings') {
+                if(empty($post['earnings'])) {
+                    throw new \Exception('请输入调整的佣金');
+                }
+                if(empty($post['earnings_remark'])) {
+                    throw new \Exception('请输入佣金调整备注');
+                }
+                if($post['earnings_handle'] == 1) { // 增加
+                    $user->earnings = $user->earnings + $post['earnings'];
+                    $user->save();
+                    AccountLogLogic::AccountRecord($user['id'], $post['earnings'],1,AccountLog::admin_inc_earnings, $post['earnings_remark']);
+                }else{
+                    $user->earnings = $user->earnings - $post['earnings'];
+                    $user->save();
+                    AccountLogLogic::AccountRecord($user['id'], $post['earnings'],0,AccountLog::admin_reduce_earnings, $post['earnings_remark']);
+                }
+            }
+
+
+            Db::commit();
+            return true;
+        }catch(\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function  fans($params)
+    {
+        $where = [];
+        // 一级
+        if ($params['type'] == 'one') {
+            $where[] = ['first_leader', '=', $params['id']];
+        }
+        // 二级粉丝
+        if ($params['type'] == 'two') {
+            $where[] = ['second_leader', '=', $params['id']];
+        }
+        if(isset($params['keyword']) && !empty($params['keyword'])) {
+            $where[] = [$params['field'], 'like', '%'. $params['keyword'] . '%'];
+        }
+        $lists = User::field('id,sn,nickname,avatar,first_leader')
+            ->where($where)
+            ->page($params['page'], $params['limit'])
+            ->select()
+            ->toArray();
+
+        $count = User::field('id,sn,nickname,avatar,first_leader')
+            ->where($where)
+            ->count();
+
+        foreach($lists as &$item) {
+            $item['avatar'] = empty($item['avatar']) ? '' : UrlServer::getFileUrl($item['avatar']);
+            $item['first_leader_info'] = User::getUserInfo($item['first_leader']);
+            $item['fans'] = User::where([
+                ['first_leader|second_leader', '=', $item['id']],
+                ['del', '=', 0]
+            ])->count();
+        }
+        return [
+            'lists' => $lists,
+            'count' => $count,
+        ];
+    }
+
+    public static function adjustLevel($params)
+    {
+       try {
+            $user = User::findOrEmpty($params['id']);
+            if ($user->isEmpty()) {
+                throw new \Exception('用户不存在');
+            }
+           if (User::UserIsDelete($params['id'])) {
+               throw new \Exception('用户已注销');
+           }
+            $user->level = $params['level'];
+            $user->remark = $params['remark'];
+            $user->save();
+
+           return true;
+       } catch(\Exception $e) {
+            self::$error = $e->getMessage();
+            return false;
+       }
+    }
+
+    public static function adjustFirstLeader($params)
+    {
+        Db::startTrans();
+        try {
+            if (User::UserIsDelete($params['id'])) {
+                throw new \Exception('用户已注销');
+            }
+            switch($params['type']) {
+                // 指定推荐人
+                case 'assign':
+                    $formatData = self::assignFirstLeader($params);
+                    break;
+                // 设置推荐人为系统,即清空上级
+                case 'system':
+                    $formatData = self::clearFirstLeader($params);
+                    break;
+            }
+
+            $user = User::findOrEmpty($params['id']);
+            // 旧关系链
+            if (!empty($user->ancestor_relation)) {
+                $old_ancestor_relation = $user->id . ',' .$user->ancestor_relation;
+            } else {
+                $old_ancestor_relation = $user->id;
+            }
+
+
+            // 更新当前用户的分销关系
+            User::where(['id' => $params['id']])->update($formatData);
+
+            //更新当前用户下级的分销关系
+            $data = [
+                'second_leader' => $formatData['first_leader'],
+                'third_leader' => $formatData['second_leader'],
+                'update_time'  => time()
+            ];
+            User::where(['first_leader' => $params['id']])->update($data);
+
+            //更新当前用户下下级的分销关系
+            $data = [
+                'third_leader' => $formatData['first_leader'],
+                'update_time'  => time()
+            ];
+            User::where(['second_leader' => $params['id']])->update($data);
+
+            //更新当前用户所有后代的关系链
+            $posterityArr = User::field('id,ancestor_relation')
+                ->whereFindInSet('ancestor_relation', $params['id'])
+                ->select()
+                ->toArray();
+            $updateData = [];
+            $replace_ancestor_relation = $params['id'] . ','. $formatData['ancestor_relation'];
+            foreach($posterityArr as $item) {
+                $updateData[] = [
+                    'id' => $item['id'],
+                    'ancestor_relation' => trim(str_replace($old_ancestor_relation, $replace_ancestor_relation, $item['ancestor_relation']), ',')
+                ];
+            }
+            // 批量更新
+            (new User())->saveAll($updateData);
+
+            Db::commit();
+            return true;
+        } catch(\Exception $e) {
+            Db::rollback();
+            self::$error = $e->getMessage();
+            return false;
+        }
+    }
+
+    public static function assignFirstLeader($params)
+    {
+        if (empty($params['first_id'])) {
+            throw new \think\Exception('请选择推荐人');
+        }
+        $firstLeader = User::field(['id', 'first_leader', 'second_leader', 'third_leader', 'ancestor_relation'])
+            ->where('id', $params['first_id'])
+            ->findOrEmpty()
+            ->toArray();
+        if(empty($firstLeader)) {
+            throw new \think\Exception('推荐人不存在');
+        }
+
+        if ($params['first_id'] == $params['id']) {
+            throw new \think\Exception('不能指定上级是自己');
+        }
+        $ancestorArr = explode(',', trim($firstLeader['ancestor_relation']));
+        if(!empty($ancestorArr) && in_array($params['id'], $ancestorArr)) {
+            throw new \think\Exception('不能指定推荐人为自己的下级');
+        }
+
+        // 上级
+        $first_leader_id = $firstLeader['id'];
+        // 上上级
+        $second_leader_id = $firstLeader['first_leader'];
+        // 上上上级
+        $third_leader_id = $firstLeader['second_leader'];
+        // 拼接关系链
+        $firstLeader['ancestor_relation'] = $firstLeader['ancestor_relation'] ?? ''; // 清空null值及0
+        $my_ancestor_relation = $first_leader_id. ',' . $firstLeader['ancestor_relation'];
+        // 去除两端逗号
+        $my_ancestor_relation = trim($my_ancestor_relation, ',');
+        $data = [
+            'first_leader' => $first_leader_id,
+            'second_leader' => $second_leader_id,
+            'third_leader' => $third_leader_id,
+            'ancestor_relation' => $my_ancestor_relation,
+            'update_time'  => time()
+        ];
+        return $data;
+    }
+
+    public static function clearFirstLeader($params)
+    {
+        $data = [
+            'first_leader' => 0,
+            'second_leader' => 0,
+            'third_leader' => 0,
+            'ancestor_relation' => '',
+            'update_time'  => time()
+        ];
+        return $data;
+    }
+
+    public static function userLists()
+    {
+        $where[] = ['del', '=', 0];
+        $where[] = ['user_delete', '=', 0];
+        // 用户信息
+        if (isset($params['keyword']) && !empty($params['keyword'])) {
+            $where[] = ['sn|nickname', 'like', '%'. $params['keyword'] .'%'];
+        }
+
+        $lists = User::field('id,sn,nickname,id as distribution,user_delete')
+            ->where($where)
+            ->page($params['page'], $params['limit'])
+            ->select()
+            ->toArray();
+        $count = User::where($where)->count();
+
+        return [
+            'count' => $count,
+            'lists' => $lists,
+        ];
+    }
+}

+ 99 - 0
app/admin/validate/BargainValidate.php

@@ -0,0 +1,99 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+
+namespace app\admin\validate;
+
+use app\common\basics\Validate;
+
+/**
+ * 砍价活动 数据校验
+ * Class BargainValidate
+ * @Author 张无忌
+ * @package app\admin\validate
+ */
+class BargainValidate extends Validate
+{
+    protected $rule = [
+        'id'                  => 'require|number',
+        'description'         => [ 'requireCallback' => 'checkRequireDescription' ],
+        'goods_id'            => 'require|number',
+        'time_limit'          => 'require',
+        'activity_start_time' => 'require',
+        'activity_end_time'   => 'require|endTime',
+        'payment_where'       => 'require|in:1,2',
+        'knife_type'          => 'require|in:1,2',
+        'status'              => 'require|in:0,1'
+    ];
+
+    protected $message = [
+        'id'         => 'ID不可为空',
+        'description'         => '请填写审核备注',
+        'id.number'  => 'ID必须为数字',
+        'goods_id.require'   => '未选择砍价商品',
+        'goods_id.number'    => '选择砍价商品异常',
+        'time_limit.require' => '请填写砍价活动有效期',
+        'time_limit.number'  => '砍价活动有效期必须为数字',
+        'activity_start_time.require' => '请选择活动开始时间',
+        'activity_end_time.require'   => '请选择活动结束时间',
+        'payment_where.require' => '请选择购买方式',
+        'payment_where.number'  => '选择的购买方式异常',
+        'knife_type.require'    => '请选择砍价金额方式',
+        'knife_type.number'     => '选择的砍价方式异常',
+        'status.require'        => '请选择砍价活动状态',
+        'status.in'             => '砍价状态选择异常',
+    ];
+
+    protected $scene = [
+        'add' => ['goods_id','time_limit','activity_start_time','activity_end_time','payment_where','knife_type','status'],
+        'edit' => ['id','goods_id','time_limit','activity_start_time','activity_end_time','payment_where','knife_type','status'],
+        'audit' => ['id','description'],
+        'violation' => ['id','description'],
+    ];
+
+    /**
+     * @notes 验证起始时间
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author suny
+     * @date 2021/7/14 10:11 上午
+     */
+    public function endTime($value, $rule, $data)
+    {
+        if (strtotime($value) <= time()) {
+            return '结束时间不能少于当前时间';
+        }
+        if (strtotime($value) <= strtotime($data['activity_start_time'])) {
+            return '结束时间不能少于或等于开始时间';
+        }
+
+        return true;
+    }
+    
+    function checkRequireDescription($value, $data)
+    {
+        if ($this->currentScene == 'audit' && $data['review_status'] == 1) {
+            return false;
+        }
+        
+        return true;
+    }
+}

+ 19 - 0
app/admin/validate/ExpressValidate.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace app\admin\validate;
+
+use app\common\basics\Validate;
+
+class ExpressValidate extends Validate
+{
+    protected $rule = [
+        'name' => 'require|unique:Express,name^del',
+        'poster' => 'require',
+    ];
+
+    protected $message = [
+        'name.unique' => '该名称已存在',
+        'poster.require' => '图标不能为空',
+    ];
+
+}

+ 85 - 0
app/admin/validate/FreightValidate.php

@@ -0,0 +1,85 @@
+<?php
+namespace app\admin\validate;
+
+use app\common\basics\Validate;
+use think\facade\Db;
+
+class FreightValidate extends Validate
+{
+
+    protected $rule = [
+        'id' => 'require',
+        'charge_way' => 'require',
+        'name' => 'require|unique:freight',
+        'region' => 'require|checkTypeData',
+    ];
+
+    protected $message = [
+        'id.require' => '参数缺失',
+        'charge_way.require' => '请选择计费方式',
+        'name.require' => '请输入模板名称',
+        'name.unique' => '该模板名称已存在',
+    ];
+
+    protected function sceneAdd()
+    {
+        $this->only(['name', 'charge_way', 'region']);
+    }
+
+    protected function sceneEdit()
+    {
+        $this->only(['id', 'name', 'charge_way', 'region']);
+    }
+
+    public function sceneDel()
+    {
+        $this->only(['id'])->append('id', 'checkIsAbleDel');
+    }
+
+    //添加时验证全国模板或指定地区模板的数据
+    protected function checkTypeData($value, $reule, $data)
+    {
+        foreach ($data as &$item) {
+            if (is_array($item)) {
+                $item = array_values($item);
+            }
+        }
+
+        $configs = form_to_linear($data);
+
+        foreach ($configs as $config) {
+            if (
+                !isset($config['first_unit']) ||
+                !isset($config['first_money']) ||
+                !isset($config['continue_unit']) ||
+                !isset($config['continue_money'])
+            ) {
+                return '请填写完整设置参数';
+            }
+
+            if (
+                ($config['first_unit'] < 0) ||
+                ($config['first_money'] < 0) ||
+                ($config['continue_unit'] < 0) ||
+                ($config['continue_money'] < 0)
+            ){
+                return '所填设置参数不能小于0';
+            }
+        }
+        return true;
+    }
+
+
+    //验证模板是否可以删除
+    protected function checkIsAbleDel($value, $reule, $data)
+    {
+        $freight = Db::name('goods')
+            ->where('express_template_id', $value)
+            ->find();
+
+        if ($freight) {
+            return '此模板已有商品使用!';
+        }
+        return true;
+    }
+}

+ 35 - 0
app/admin/validate/RechargeTemplateValidate.php

@@ -0,0 +1,35 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+namespace app\admin\validate;
+use think\Validate;
+
+class RechargeTemplateValidate extends Validate{
+    protected $rule = [
+        'money'          => 'require|gt:0',
+        'give_money'     => 'egt:0',
+        'sort'         => 'integer|egt:0',
+    ];
+    protected $message = [
+        'money.require'     => '请输入充值金额',
+        'money.gt'          => '充值金额须为大于0',
+        'give_money.egt'     => '赠送金额须为大于0',
+        'sort.integer'    => '排序值须为整数',
+        'sort.egt'        => '排序值须大于或等于0',
+    ];
+}

+ 40 - 0
app/admin/validate/activity_area/ActivityGoods.php

@@ -0,0 +1,40 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+namespace app\admin\validate\activity_area;
+
+use think\facade\Db;
+use app\common\basics\Validate;
+
+
+class ActivityGoods extends Validate
+{
+    protected $rule = [
+        'review_status' => 'require',
+        'description' => 'require',
+    ];
+    protected $message = [
+        'review_status.require' => '请选择审核状态',
+        'description.require' => '请填写审核说明',
+
+    ];
+    protected $scene = [
+        'audit' => ['review_status', 'description'],
+        'violation' => ['description'],
+    ];
+}

+ 55 - 0
app/admin/validate/activity_area/AreaValidate.php

@@ -0,0 +1,55 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+namespace app\admin\validate\activity_area;
+use app\common\basics\Validate;
+use think\facade\Db;
+
+class AreaValidate extends Validate{
+    protected $rule = [
+        'id'        => 'require',
+        'name'      => 'require|unique:activity_area,name^del',
+        'synopsis'  => 'require',
+        'image'     => 'require',
+     ];
+
+    protected $message = [
+        'name.require'      => '请输入专区名称',
+        'name.unique'       => '专区名称重复',
+        'image.require'       => '封面图不能为空',
+        'synopsis.require'  => '请专区简介',
+    ];
+    protected $scene = [
+        'add' => ['name','synopsis','image'],
+        'edit' => [['id','checkArea'],'name','synopsis','image'],
+        'del' => ['id']
+    ];
+    //验证活动专区(多商户)
+//    public function checkArea($value,$rule,$data){
+//
+//        $goods = Db::name('activity_area_goods')
+//                ->where(['del'=>0,'activity_area_id'=>$value])
+//                ->find();
+//        halt($goods);
+//        if($goods){
+//            return '该活动专区已被使用,无法删除';
+//        }
+//        return true;
+//
+//    }
+}

+ 151 - 0
app/admin/validate/distribution/DistributionLevelValidate.php

@@ -0,0 +1,151 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\validate\distribution;
+
+use app\common\basics\Validate;
+use app\common\model\distribution\DistributionLevel;
+
+class DistributionLevelValidate extends  Validate
+{
+    protected $rule = [
+        'name' => 'require|checkName',
+        'weights' => 'require|integer|gt:1|checkWeights',
+        'first_ratio' => 'require|between:0,100',
+        'second_ratio' => 'require|between:0,100',
+        'update_relation' => 'require|in:1,2',
+        'update_condition' => 'require|array|checkCondition',
+        'singleConsumptionAmount' => 'gt:0',
+        'cumulativeConsumptionAmount' => 'gt:0',
+        'cumulativeConsumptionTimes' => 'integer|gt:0',
+        'returnedCommission' => 'gt:0',
+        'id' => 'require'
+    ];
+
+
+    protected  $message = [
+        'name.require' => '请填写等级名称',
+        'weights.require' => '请输入级别',
+        'weights.integer' => '级别须为整型',
+        'weights.gt' => '级别须大于1',
+        'first_ratio.require' => '请输入一级佣金比例',
+        'first_ratio.between' => '一级佣金比例须在0-100之间',
+        'second_ratio.require' => '请输入二级佣金比例',
+        'second_ratio.between' => '二级佣金比例须在0-100之间',
+        'update_relation.require' => '请选择升级关系',
+        'update_relation.in' => '升级关系状态值错误',
+        'update_condition.require' => '请选择升级条件',
+        'update_condition.array' => '升级条件数据格式错误',
+        'singleConsumptionAmount.gt' => '单笔消费金额须大于0',
+        'cumulativeConsumptionAmount.gt' => '累计消费金额须大于0',
+        'cumulativeConsumptionTimes.gt' => '累计消费次数须大于0',
+        'cumulativeConsumptionTimes.integer' => '累计消费次数须为整数',
+        'returnedCommission.gt' => '已结算佣金收入须大于0',
+        'id.require' => '参数缺失',
+    ];
+
+    /**
+     * @notes 添加分销等级
+     * @return DistributionLevelValidate
+     * @author Tab
+     * @date 2021/9/1 14:45
+     */
+    public function sceneAdd()
+    {
+        return $this->only(['name', 'weights', 'self_ratio', 'first_ratio', 'second_ratio', 'update_condition', 'update_relation', 'singleConsumptionAmount', 'cumulativeConsumptionAmount', 'cumulativeConsumptionTimes', 'returnedCommission']);
+    }
+
+    /**
+     * @notes 编辑分销等级
+     * @return DistributionLevelValidate
+     * @author Tab
+     * @date 2021/9/1 15:49
+     */
+    public function sceneEdit()
+    {
+        return $this->only(['id', 'name', 'weights', 'first_ratio', 'second_ratio'])
+            ->remove('weights', 'gt');
+    }
+
+    /**
+     * @notes 校验等级名称
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author Tab
+     * @date 2021/9/1 14:42
+     */
+    public function checkName($value, $rule, $data)
+    {
+        $where = [['name', '=', $value]];
+        if(isset($data['id'])) {
+            // 编辑的场景
+            $where[] = ['id', '<>', $data['id']];
+        }
+        $level = DistributionLevel::where($where)->findOrEmpty();
+        if(!$level->isEmpty()) {
+            return '等级名称已存在';
+        }
+        return true;
+    }
+
+    /**
+     * @notes 校验等级级别
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author Tab
+     * @date 2021/9/1 14:42
+     */
+    public function checkWeights($value, $rule, $data)
+    {
+        $where = [['weights', '=', $value]];
+        if(isset($data['id'])) {
+            // 编辑的场景
+            $where[] = ['id', '<>', $data['id']];
+        }
+        $level = DistributionLevel::where($where)->findOrEmpty();
+        if(!$level->isEmpty()) {
+            return '等级级别已存在';
+        }
+        return true;
+    }
+
+    /**
+     * @notes 校验升级条件
+     * @param $value
+     * @return bool|string
+     * @author Tab
+     * @date 2021/9/1 14:43
+     */
+    public function checkCondition($value, $rule, $data)
+    {
+        if(!count($value)) {
+            return '请选择升级条件';
+        }
+        foreach($value as $v) {
+            if(!isset($data[$v]) || empty($data[$v])) {
+                return '升级条件数据未填写';
+            }
+        }
+        return true;
+    }
+}

+ 101 - 0
app/admin/validate/distribution/MemberValidate.php

@@ -0,0 +1,101 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\validate\distribution;
+
+use think\Validate;
+use app\common\model\user\User;
+
+class MemberValidate extends Validate
+{
+    protected $rule = [
+        // 添加分销会员
+        'sn' => 'require|max:10',
+        'remarks' => 'max:100',
+        // 更新上级
+        'user_id' => 'require',
+        'change_type' => 'require',
+        'referrer_sn' => 'requireIf:change_type,appoint|checkReferrer',
+        // 冻结、解冻资格/ 审核分销会员
+        'id' => 'require',
+        'type' => 'require',
+    ];
+
+
+    protected  $message = [
+        'sn.require' => '请输入会员编号',
+        'sn.max' => '会员编号不能超过10个字符',
+        'remarks.max' => '备注不能超过100个字符',
+        'user_id.require' => '会员id不能为空',
+        'change_type.require' => '调整方式不能为空',
+        'referrer_sn.requireIf' => '指定上级不能为空',
+        'id.require' => '请输入会员id',
+        'type.require' => '请输入类型',
+    ];
+
+    public function sceneAdd()
+    {
+        return $this->only(['sn', 'remarks']);
+    }
+
+    public function sceneUpdateLeader()
+    {
+        return $this->only(['user_id', 'change_type', 'referrer_sn']);
+    }
+
+    public function sceneFreeze()
+    {
+        return $this->only(['id', 'type']);
+    }
+
+    public function sceneAudit()
+    {
+        return $this->only(['id', 'type']);
+    }
+
+    public function checkReferrer($value, $rule, $data)
+    {
+        if (empty($value) && $data['change_type'] == 'clear'){
+            return true;
+        }
+
+        $referrer = User::where('sn', $value)->findOrEmpty();
+
+        if ($referrer->isEmpty()){
+            return '推荐人不存在';
+        }
+
+        $referrer = $referrer->toArray();
+
+        if ($referrer['id'] == $data['user_id']){
+            return '上级推荐人不能是自己';
+        }
+
+        if ($referrer['is_distribution'] == 0){
+            return '对方不是分销会员';
+        }
+
+        $ancestor_relation = explode(',', $referrer['ancestor_relation']);
+        if (!empty($ancestor_relation) && in_array($data['user_id'], $ancestor_relation)) {
+            return '推荐人不能是自己的任意下级';
+        }
+
+        return true;
+    }
+}

+ 137 - 0
app/admin/validate/integral/IntegralGoodsValidate.php

@@ -0,0 +1,137 @@
+<?php
+
+namespace app\admin\validate\integral;
+
+use app\common\basics\Validate;
+use app\common\enum\IntegralGoodsEnum;
+use app\common\model\integral\IntegralGoods;
+
+/**
+ * 积分商品验证
+ * Class IntegralGoodsValidate
+ * @package app\admin\validate\kefu
+ */
+class IntegralGoodsValidate extends Validate
+{
+    protected $rule = [
+        'id'=>'require|checkGoods',
+        'type' => 'require|in:1,2',
+        'name' => 'require',
+        'image' => 'require',
+        'market_price' => 'checkMarketPrice',
+        'stock' => 'require|integer',
+        'exchange_way' => 'requireIf:type,1',
+        'need_integral' => 'require|integer|checkNeedIntegral',
+        'need_money' => 'requireIf:exchange_way,2|checkNeedMoney',
+        'delivery_way' => 'requireIf:type,1',
+        'express_type' => 'requireIf:delivery_way,1',
+        'express_money' => 'requireIf:express_type,2|checkExpressMoney',
+        'balance' => 'requireIf:type,2|checkBalance',
+        'status' => 'require|in:0,1',
+    ];
+
+    protected $message = [
+        'id.require' => '参数缺失',
+        'type.require' => '请选择兑换类型',
+        'type.in' => '兑换类型错误',
+        'name.require' => '请填写商品名称',
+        'image.require' => '请上传商品封面',
+        'stock.require' => '请填写发放库存',
+        'stock.integer' => '请填写整数发放库存',
+        'exchange_way.requireIf' => '请选择兑换方式',
+        'need_integral.require' => '请填写兑换积分',
+        'need_integral.integer' => '请填写整数兑换积分',
+        'need_money.requireIf' => '请填写兑换金额',
+        'delivery_way.requireIf' => '请选择物流配送方式',
+        'express_type.requireIf' => '请选择物流方式',
+        'express_money.requireIf' => '请填写运费',
+        'balance.requireIf' => '请填写红包面值',
+        'status.require' => '请选择商品状态',
+        'status.in' => '商品状态参数错误',
+    ];
+
+
+    public function sceneAdd()
+    {
+        $this->remove('id', true);
+    }
+
+    public function sceneEdit()
+    {
+    }
+
+    public function sceneDel()
+    {
+        $this->only(['id']);
+    }
+
+    public function sceneDetail()
+    {
+        $this->only(['id']);
+    }
+
+
+    protected function checkGoods($value, $rule, $data)
+    {
+        $goods = IntegralGoods::where(['id' => $value])->findOrEmpty();
+        if ($goods->isEmpty()) {
+            return '积分商品不存在';
+        }
+        if ($goods['del'] == 1) {
+            return '积分商品已被删除';
+        }
+        return true;
+    }
+
+
+    // 验证统一运费时,运费不小于0
+    protected function checkExpressMoney($value, $rule, $data)
+    {
+        // 快递配送  统一运费 运费须大于0
+        if ($data['delivery_way'] == IntegralGoodsEnum::DELIVERY_EXPRESS
+            && $data['express_type'] == IntegralGoodsEnum::EXPRESS_TYPE_UNIFIED
+            && $value <= 0
+        ) {
+            return '请输入大于0的运费';
+        }
+        return true;
+    }
+
+
+    // 验证兑换积分需大于0
+    protected function checkNeedIntegral($value, $rule, $data)
+    {
+        if ($value <= 0) {
+            return '请输入大于0的兑换积分';
+        }
+        return true;
+    }
+
+    // 验证兑换方式为 积分+金额 时,金额不小于0
+    protected function checkNeedMoney($value, $rule, $data)
+    {
+        if ($data['exchange_way'] == IntegralGoodsEnum::EXCHANGE_WAY_HYBRID && $value <= 0) {
+            return '请输入大于0的兑换金额';
+        }
+        return true;
+    }
+
+    // 验证兑换类型为 红包时,红包面额不小于0
+    protected function checkBalance($value, $rule, $data)
+    {
+        if ($data['type'] == IntegralGoodsEnum::TYPE_BALANCE && $value <= 0) {
+            return '请输入大于0的红包面值';
+        }
+        return true;
+    }
+
+
+    protected function checkMarketPrice($value)
+    {
+        if (!empty($value) && $value < 0) {
+            return '请输入正确市场价';
+        }
+        return true;
+    }
+
+}

+ 144 - 0
app/admin/validate/integral/IntegralOrderValidate.php

@@ -0,0 +1,144 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop开源商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
+// |  likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | likeshop团队版权所有并拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshop.cn.team
+// +----------------------------------------------------------------------
+
+namespace app\admin\validate\integral;
+
+
+use app\common\basics\Validate;
+use app\common\enum\IntegralGoodsEnum;
+use app\common\enum\IntegralOrderEnum;
+use app\common\model\integral\IntegralOrder;
+
+class IntegralOrderValidate extends Validate
+{
+    protected $rule = [
+        'id' => 'require',
+    ];
+
+    protected $message = [
+        'id.require' => '参数错误',
+    ];
+
+    public function sceneDeliveryHandle()
+    {
+        return $this->only(['id'])
+            ->append('id','checkDeliveryHandle');
+    }
+
+    public function sceneConfirm()
+    {
+        return $this->only(['id'])
+            ->append('id','checkConfirm');
+    }
+
+    public function sceneCancel()
+    {
+        return $this->only(['id'])
+            ->append('id','checkCancel');
+    }
+
+
+    /**
+     * @notes 检验订单能否发货
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author ljj
+     * @date 2022/3/3 12:06 下午
+     */
+    public function checkDeliveryHandle($value,$rule,$data)
+    {
+        $result = IntegralOrder::where(['id'=>$value,'del'=>0])->findOrEmpty()->toArray();
+        if (!$result) {
+            return '订单不存在';
+        }
+        if ($result['delivery_way'] == 0) {
+            return '订单无需快递';
+        }
+        if (!isset($data['shipping_id']) || $data['shipping_id'] == '') {
+            return '请选择快递';
+        }
+        if (!isset($data['invoice_no']) || $data['invoice_no'] == '') {
+            return '请输入快递单号';
+        }
+        if ($result['shipping_status'] == 1) {
+            return '订单已发货';
+        }
+        if ($result['order_status'] != IntegralOrderEnum::ORDER_STATUS_DELIVERY) {
+            return '订单状态不正确,无法发货';
+        }
+        return true;
+    }
+
+    /**
+     * @notes 检验订单能否确认收货
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author ljj
+     * @date 2022/3/3 3:37 下午
+     */
+    public function checkConfirm($value,$rule,$data)
+    {
+        $result = IntegralOrder::where(['id'=>$value,'del'=>0])->findOrEmpty()->toArray();
+        if (!$result) {
+            return '订单不存在';
+        }
+        if ($result['order_status'] != IntegralOrderEnum::ORDER_STATUS_GOODS) {
+            return '订单状态不正确,无法确认收货';
+        }
+        return true;
+    }
+
+
+
+
+    /**
+     * @notes 取消订单验证
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author 段誉
+     * @date 2022/3/3 17:58
+     */
+    public function checkCancel($value, $rule, $data)
+    {
+        $order = IntegralOrder::findOrEmpty($value);
+        $goods_snap = $order['goods_snap'];
+
+        if ($order->isEmpty()) {
+            return '订单不存在';
+        }
+
+        // 商品类型为红包的不可取消
+        if ($goods_snap['type'] == IntegralGoodsEnum::TYPE_BALANCE) {
+            return '类型为红包的订单不可取消';
+        }
+
+        if ($order['order_status'] >= IntegralOrderEnum::ORDER_STATUS_GOODS) {
+            return '已发货订单不可取消';
+        }
+
+        return true;
+    }
+
+}

+ 68 - 0
app/admin/validate/kefu/KefuLangValidate.php

@@ -0,0 +1,68 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop100%开源免费商用商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | 商业版本务必购买商业授权,以免引起法律纠纷
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshopTeam
+// +----------------------------------------------------------------------
+namespace app\admin\validate\kefu;
+use app\common\basics\Validate;
+use app\common\model\kefu\KefuLang;
+
+/**
+ *
+ * Class KefuLangValidate
+ * @package app\admin\validate\kefu
+ */
+class KefuLangValidate extends Validate
+{
+    protected $rule = [
+        'id'            => 'require|checkLang',
+        'title'         => 'require|unique:'.KefuLang::class.',title',
+        'content'       => 'require|unique:'.KefuLang::class.',content',
+        'sort'          => 'gt:0',
+    ];
+
+    protected $message = [
+        'title.require'     => '请输入标题',
+        'title.unique'      => '标题已存在',
+        'content.require'   => '请输入内容',
+        'content.unique'    => '内容已存在',
+        'sort.gt'           => '排序不能小于零',
+
+    ];
+
+
+    public function sceneAdd()
+    {
+        $this->remove('id', true);
+    }
+
+    public function sceneDel()
+    {
+        $this->only(['id']);
+    }
+
+    public function checkLang($value,$rule,$data){
+        $lang = KefuLang::where(['id'=>$value])->find();
+        if($lang){
+            return true;
+        }
+        return '话术不存在';
+    }
+
+
+
+
+}

+ 98 - 0
app/admin/validate/kefu/KefuValidate.php

@@ -0,0 +1,98 @@
+<?php
+
+namespace app\admin\validate\kefu;
+
+use app\common\basics\Validate;
+use app\common\model\kefu\Kefu;
+
+/**
+ * 客服验证逻辑
+ * Class KefuValidate
+ * @package app\admin\validate\content
+ */
+class KefuValidate extends Validate
+{
+    protected $rule = [
+        'id' => 'require|number',
+        'admin_id' => 'require|number|checkIsKefu',
+        'avatar' => 'require',
+        'nickname' => 'require',
+        'disable' => 'require|in:0,1',
+        'sort' => 'gt:0'
+    ];
+
+    protected $message = [
+        'id.require' => 'id不可为空',
+        'id.number' => 'id必须为数字',
+        'admin_id.require' => '请选择管理员',
+        'admin_id.number' => '管理员选择异常',
+        'avatar.require' => '请选择头像',
+        'nickname.require' => '请填写客服昵称',
+        'disable.require' => '请选择状态',
+        'disable.in' => '状态错误',
+        'sort.gt' => '排序需大于0',
+    ];
+
+
+    public function sceneAdd()
+    {
+        $this->remove('id', true);
+    }
+
+    public function sceneEdit()
+    {
+        $this->remove('admin_id',true);
+    }
+
+    public function sceneDel()
+    {
+        $this->only(['id'])->append('id', 'checkIsDel');
+    }
+
+
+    /**
+     * @notes 选中管理员是否已为客服
+     * @param $value
+     * @param $rule
+     * @param array $data
+     * @return bool|string
+     * @author 段誉
+     * @date 2021/11/26 18:56
+     */
+    protected function checkIsKefu($value, $rule, $data = [])
+    {
+        $check = Kefu::where([
+            'admin_id' => $value,
+            'shop_id' => 0,
+            'del' => 0
+        ])->findOrEmpty();
+
+        if (!$check->isEmpty()) {
+            return "该管理员已是客服";
+        }
+
+        return true;
+    }
+
+
+    /**
+     * @notes 客服是否存在
+     * @param $value
+     * @param $rule
+     * @param array $data
+     * @return bool|string
+     * @author 段誉
+     * @date 2021/11/26 18:57
+     */
+    protected function checkIsDel($value, $rule, $data = [])
+    {
+        $check = Kefu::where(['id' => $value, 'del' => 0])->findOrEmpty();
+
+        if ($check->isEmpty()) {
+            return "该客服数据错误";
+        }
+
+        return true;
+    }
+
+}

+ 30 - 0
app/admin/validate/kefu/LoginValidate.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace app\admin\validate\kefu;
+
+use app\common\basics\Validate;
+use app\common\logic\ChatLogic;
+
+
+class LoginValidate extends Validate
+{
+    protected $rule = [
+        'id' => 'require|number|checkConfig',
+    ];
+
+    protected $message = [
+        'id.require' => 'id不可为空',
+        'id.number' => 'id必须为数字',
+    ];
+
+
+    protected function checkConfig($value, $rule, $data = [])
+    {
+        if (false === ChatLogic::checkConfig()) {
+            return ChatLogic::getError() ?: '请联系管理员设置后台配置';
+        }
+        return true;
+    }
+
+
+}

+ 86 - 0
app/admin/validate/live/LiveGoodsValidate.php

@@ -0,0 +1,86 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop100%开源免费商用商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | 商业版本务必购买商业授权,以免引起法律纠纷
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshopTeam
+// +----------------------------------------------------------------------
+namespace app\admin\validate\live;
+
+use app\common\basics\Validate;
+use app\common\enum\LiveGoodsEnum;
+use app\common\model\live\LiveGoods;
+
+/**
+ * 直播商品验证器
+ * Class LiveGoodsValidate
+ * @package app\admin\validate\live
+ */
+class LiveGoodsValidate extends Validate
+{
+
+    protected $rule = [
+        'id' => 'require|checkLiveGoods',
+        'status' => 'require|in:' . LiveGoodsEnum::SYS_AUDIT_STATUS_WAIT_WECHAT . ',' . LiveGoodsEnum::SYS_AUDIT_STATUS_FAIL,
+    ];
+
+
+    protected $message = [
+        'id.require' => '参数缺失',
+        'status.require' => '状态参数缺失',
+        'status.in' => '状态参数异常',
+    ];
+
+
+    protected function sceneAudit()
+    {
+        return $this->only(['id', 'status']);
+    }
+
+
+    protected function sceneDel()
+    {
+        return $this->only(['id']);
+    }
+
+
+    protected function sceneDetail()
+    {
+        return $this->only(['id']);
+    }
+    
+
+    /**
+     * @notes 校验直播商品
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author 段誉
+     * @date 2023/2/16 11:10
+     */
+    protected function checkLiveGoods($value, $rule, $data)
+    {
+        $room = LiveGoods::where([
+            'id' => $value,
+            'del' => 0
+        ])->findOrEmpty();
+
+        if ($room->isEmpty()) {
+            return '直播商品不存在';
+        }
+        return true;
+    }
+
+}

+ 83 - 0
app/admin/validate/live/LiveRoomValidate.php

@@ -0,0 +1,83 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeshop100%开源免费商用商城系统
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | 商业版本务必购买商业授权,以免引起法律纠纷
+// | 禁止对系统程序代码以任何目的,任何形式的再发布
+// | gitee下载:https://gitee.com/likeshop_gitee
+// | github下载:https://github.com/likeshop-github
+// | 访问官网:https://www.likeshop.cn
+// | 访问社区:https://home.likeshop.cn
+// | 访问手册:http://doc.likeshop.cn
+// | 微信公众号:likeshop技术社区
+// | likeshop团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeshopTeam
+// +----------------------------------------------------------------------
+namespace app\admin\validate\live;
+
+use app\common\basics\Validate;
+use app\common\enum\LiveRoomEnum;
+use app\common\model\live\LiveRoom;
+
+/**
+ * 直播间验证器
+ * Class LiveRoomValidate
+ * @package app\admin\validate\live
+ */
+class LiveRoomValidate extends Validate
+{
+
+    protected $rule = [
+        'id' => 'require|checkLiveRoom',
+        'status' => 'require|in:' . LiveRoomEnum::AUDIT_STATUS_SUCCESS . ',' . LiveRoomEnum::AUDIT_STATUS_FAIL,
+        'sort' => 'require|integer|egt:0',
+    ];
+
+
+    protected $message = [
+        'id.require' => '参数缺失',
+        'status.require' => '审核参数缺失',
+        'status.in' => '审核参数异常',
+        'sort.require' => '请填写推荐值',
+        'sort.integer' => '推荐值需为整数',
+        'sort.egt' => '推荐值需大于或等于0',
+    ];
+
+
+    protected function sceneAudit()
+    {
+        return $this->only(['id', 'status']);
+    }
+
+    protected function sceneRecommend()
+    {
+        return $this->only(['id', 'sort']);
+    }
+
+
+    /**
+     * @notes 校验直播间
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author 段誉
+     * @date 2023/2/16 11:10
+     */
+    protected function checkLiveRoom($value, $rule, $data)
+    {
+        $room = LiveRoom::where([
+            'id' => $value,
+            'del' => 0
+        ])->findOrEmpty();
+
+        if ($room->isEmpty()) {
+            return '直播间信息不存在';
+        }
+        return true;
+    }
+
+}

+ 50 - 0
app/admin/validate/order/OrderValidate.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace app\admin\validate\order;
+
+use app\common\enum\OrderEnum;
+use app\common\model\team\TeamJoin;
+use think\Validate;
+use app\common\model\order\Order;
+use app\common\model\team\Team;
+
+class OrderValidate extends Validate
+{
+    /**
+     * @notes 发货操作验证
+     * @param $post
+     * @return bool|string
+     * @author suny
+     * @date 2021/7/14 10:10 上午
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\db\exception\DataNotFoundException
+     */
+    protected function checkDelivery($post)
+    {
+
+        $id = $post['id'];
+        $order = Order::where(['id' => $id])->find();
+
+        if (!$order) {
+            return '订单失效';
+        }
+
+        if ($order['del'] == 1) {
+            return '订单已删除';
+        }
+
+        if ($order['shipping_status'] == 1) {
+            return '此订单已发货';
+        }
+
+        if ($order['order_type'] == OrderEnum::TEAM_ORDER) {
+            $join = TeamJoin::where(['order_id' => $order['id']])->findOrEmpty();
+            if ($join['status'] != Team::STATUS_SUCCESS) {
+                return '已支付的拼团订单需要等待拼团成功后才能发货';
+            }
+        }
+
+        return true;
+    }
+}

+ 42 - 0
app/admin/validate/seckill/SeckillTimeValidate.php

@@ -0,0 +1,42 @@
+<?php
+namespace app\admin\validate\seckill;
+
+use think\Validate;
+use app\common\model\seckill\SeckillTime;
+
+class SeckillTimeValidate extends Validate
+{
+    protected $rule = [
+        'start_time'        => 'require',
+        'end_time'          => 'require|checkTime',
+    ];
+    protected $message = [
+        'start_time.require'        => '请选择开始时间',
+        'end_time.require'          => '请选择结束时间',
+    ];
+
+    public function checkTime($value,$rule,$data){
+        $start_time = strtotime(date('Y-m-d'.$data['start_time']));
+        $end_time = strtotime(date('Y-m-d'.$value));
+        if($start_time >= $end_time){
+            return '开始时间不能大于结束时间';
+        }
+        $where[] = ['del','=',0];
+        if(isset($data['id'])){
+            $where[] = ['id','<>',$data['id']];
+        }
+        $time_list = SeckillTime::where($where)->select()->toArray();
+        foreach ($time_list as $item){
+            $item_start_time = strtotime(date('Y-m-d'.$item['start_time']));
+            $item_end_time = strtotime(date('Y-m-d'.$item['end_time']));
+            if($start_time >= $item_start_time && $start_time < $item_end_time ){
+                return '秒杀时间段冲突';
+            }
+            if($end_time >= $item_start_time && $end_time < $item_end_time ){
+                return '秒杀时间段冲突';
+            }
+
+        }
+        return true;
+    }
+}

+ 121 - 0
app/admin/validate/sign_daily/SignDailyValidate.php

@@ -0,0 +1,121 @@
+<?php
+
+namespace app\admin\validate\sign_daily;
+
+use app\common\basics\Validate;
+use app\common\model\sign_daily\SignDaily;
+
+/**
+ * 签到验证
+ * Class SignDailyValidate
+ * @package app\admin\validate
+ */
+class SignDailyValidate extends Validate
+{
+    protected $rule = [
+        'integral' => 'requireIf:integral_status,1|integer|checkIntegral',   //积分
+        'growth' => 'requireIf:growth_status,1|integer|checkGrowth',   //成长值
+        'days' => 'require|integer|gt:0|checkDays',   //连续签到天数
+        'instructions' => 'require'
+    ];
+
+    protected $message = [
+        'integral.requireIf' => '积分不能为空',
+        'integral.integer' => '积分必须为整数',
+
+        'growth.requireIf' => '成长值不能为空',
+        'growth.integer' => '成长值必须为整数',
+
+        'days.require' => '连续签到天数不能为空',
+        'days.integer' => '连续签到天数必须为整数',
+        'days.gt' => '连续签到天数必须大于0',
+        'instructions' => '签到规则说明不能为空'
+    ];
+
+    public function sceneAdd()
+    {
+        $this->only(['integral', 'days', 'growth'])
+            ->remove('instructions');
+
+    }
+
+    public function sceneEdit()
+    {
+        $this->only(['integral', 'days', 'growth'])
+            ->remove('instructions');
+
+    }
+
+    public function sceneSign()
+    {
+        $this->only(['integral', 'growth', 'instructions'])
+            ->remove('days');
+    }
+
+
+    /**
+     * @notes 验证积分
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author 段誉
+     * @date 2022/3/17 14:45
+     */
+    public function checkIntegral($value, $rule, $data)
+    {
+        if (isset($data['integral_status']) && $data['integral_status'] && $value <= 0) {
+            return '积分必须大于0';
+        }
+        return true;
+    }
+
+
+    /**
+     * @notes 验证成长值
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author 段誉
+     * @date 2022/3/17 14:45
+     */
+    public function checkGrowth($value, $rule, $data)
+    {
+        if (isset($data['growth_status']) && $data['growth_status'] && $value <= 0) {
+            return '成长值必须大于0';
+        }
+        return true;
+    }
+
+
+    /**
+     * @notes 判断连续签到天数是否存在
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @author 段誉
+     * @date 2022/2/17 10:46
+     */
+    public function checkDays($value, $rule, $data)
+    {
+        if (!isset($data['integral_status']) && !isset($data['growth_status'])) {
+            return '请选择积分奖励或成才值奖励';
+        }
+
+        if (isset($data['id'])) {
+            $where[] = ['id', '<>', $data['id']];
+        }
+        $where[] = ['days', '=', $value];
+        $where[] = ['del', '=', 0];
+        $sign_daily = SignDaily::where($where)->findOrEmpty();
+
+        if (!$sign_daily->isEmpty()) {
+            return '该连续签到天数已存在';
+        }
+        return true;
+    }
+
+
+}

+ 35 - 0
app/admin/validate/user/LevelValidate.php

@@ -0,0 +1,35 @@
+<?php
+namespace app\admin\validate\user;
+
+use think\Validate;
+
+class LevelValidate extends Validate
+{
+    protected $rule = [
+        'id' => 'require',
+        'name' => 'require',
+        'growth_value' => 'require|integer|egt:0',
+        'image' => 'require',
+        'background_image' => 'require',
+        'discount' => 'between:0,10'
+    ];
+
+    protected $message = [
+        'id.require' => '参数缺失',
+        'name.require' => '请输入等级名称',
+        'growth_value.require' => '请输入成长值',
+        'growth_value.integer' => '成长值必须为整数',
+        'growth_value.egt' => '成长值必须大于或等于0',
+        'image.require' => '请选择等级图标',
+        'background_image.require' => '请选择等级背景图',
+        'discount.between' => '会员折扣必须在0-10之前',
+    ];
+
+    public function sceneAdd() {
+        return $this->only(['name', 'growth_value', 'image', 'background_image', 'discount']);
+    }
+
+    public function sceneEdit() {
+        return $this->only(['id', 'name', 'growth_value', 'image', 'background_image', 'discount']);
+    }
+}

+ 30 - 0
app/admin/validate/user/TagValidate.php

@@ -0,0 +1,30 @@
+<?php
+namespace app\admin\validate\user;
+
+use think\Validate;
+
+class TagValidate extends Validate
+{
+    protected  $rule = [
+        'name' => 'require|max:16',
+        'remark' => 'max:6',
+        'id'     => 'require'
+    ];
+
+    protected  $message = [
+        'name.require' => '请输入标签名称',
+        'name.max' => '标签长度不能超过16个字符',
+        'remark.max' => '备注长度不能超过64个字符',
+        'id.require' => '标签id不能为空',
+    ];
+
+    public function sceneAdd()
+    {
+        return $this->only(['name', 'remark']);
+    }
+
+    public function sceneEdit()
+    {
+        return $this->only(['name', 'remark', 'id']);
+    }
+}

+ 242 - 0
app/admin/validate/user/UserValidate.php

@@ -0,0 +1,242 @@
+<?php
+namespace app\admin\validate\user;
+
+use app\common\model\user\User;
+use think\Validate;
+
+class UserValidate extends Validate
+{
+    protected $rule = [
+        'tag_ids' => 'require',
+        'user_ids' => 'require|checkIds',
+        'nickname' => 'require',
+        'avatar' => 'require',
+        'mobile' => 'mobile',
+        'id' => 'require|checkId',
+        'type' => 'require|checkData',
+        'integral_remark' => 'max:100',
+        'earnings_remark' => 'max:100',
+        'money_remark' => 'max:100',
+        'growth_remark' => 'max:100',
+        'disable'=> 'require|in:0,1'
+    ];
+
+    protected $message = [
+        'tag_ids.require' => '请选择会员标签',
+        'user_ids.require' => '请先选择用户',
+        'nickname.require' => '请填写用户昵称',
+        'avatar.require' => '请选择用户头像',
+        'mobile.mobile' => '手机号码格式错误',
+        'id.require' => '请选择要调整的用户',
+        'type.require' => '调整类型参数缺失',
+        'integral_remark.max' => '备注不能超过100个字符',
+        'earnings_remark.max' => '备注不能超过100个字符',
+        'money_remark.max' => '备注不能超过100个字符',
+        'growth_remark.max' => '备注不能超过100个字符',
+        'disable.require'  => '请选择禁用状态',
+        'disable.in'       => '禁用状态参数错误',
+    ];
+
+    public function sceneSetTag()
+    {
+        return $this->only(['tag_ids', 'user_ids']);
+    }
+
+    public function sceneEdit()
+    {
+        return $this->only(['id','nickname', 'avatar', 'mobile', 'disable']);
+    }
+
+    public function sceneAdjustAccount()
+    {
+        return $this->only([
+             'type','id', 'money_remark', 'growth_remark', 'integral_remark', 'earnings_remark',
+        ]);
+    }
+    
+    function checkId($value, $rule, $data)
+    {
+        if (User::UserIsDelete($value) && (request()->isAjax() || request()->isPost())) {
+            return '用户已注销,不能操作';
+        }
+        
+        return true;
+    }
+    
+    function checkIds($ids, $rule, $data)
+    {
+        foreach ($ids as $id) {
+            if (User::UserIsDelete($id) && (request()->isAjax() || request()->isPost())) {
+                return '用户已注销,不能操作';
+            }
+        }
+        
+        return true;
+    }
+
+
+    /**
+     * @notes 验证调整数据
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/3/16 10:49
+     */
+    protected function checkData($value, $rule, $data)
+    {
+        $user = User::where(['del' => 0, 'id' => $data['id']])->find();
+        if (empty($user)) {
+            return '该用户不存在';
+        }
+
+        if (!isset($data['money_handle']) && !isset($data['integral_handle'])
+            && !isset($data['growth_handle']) && !isset($data['earnings_handle'])) {
+            return '请选择调整的类型';
+        }
+
+        switch ($value) {
+            case 'money':
+                $result = $this->checkMoney($data, $user);
+                break;
+            case 'integral':
+                $result = $this->checkIntegral($data, $user);
+                break;
+            case 'growth':
+                $result = $this->checkGrowth($data, $user);
+                break;
+            case 'earnings':
+                $result = $this->checkEarnings($data, $user);
+                break;
+            default:
+                $result = '账户调整类型错误';
+        }
+        return $result;
+    }
+
+
+
+
+    /**
+     * @notes 验证金额
+     * @param $data
+     * @param $user
+     * @return bool|string
+     * @author 段誉
+     * @date 2022/3/16 10:49
+     */
+    protected function checkMoney($data, $user)
+    {
+        if (empty($data['money'])) {
+            return '请输入大于0的调整余额';
+        }
+        if ($data['money'] < 0) {
+            return '调整余额必须大于零';
+        }
+        //验证扣减余额操作
+        if ($data['money_handle'] == 0) {
+            //用户余额不足
+            if ($data['money'] > $user['user_money']) {
+                return '用户余额仅剩下' . $user['user_money'] . '元';
+            }
+        }
+        if (empty($data['money_remark'])) {
+            return '请输入调整余额备注';
+        }
+        return true;
+    }
+
+    /**
+     * @notes 验证积分
+     * @param $data
+     * @param $user
+     * @return bool|string
+     * @author 段誉
+     * @date 2022/3/16 10:49
+     */
+    protected function checkIntegral($data, $user)
+    {
+        if (empty($data['integral'])) {
+            return '请输入大于0的调整积分';
+        }
+        if ($data['integral'] < 0) {
+            return '调整积分必须大于零';
+        }
+        //验证扣减积分操作
+        if ($data['integral_handle'] == 0) {
+            //用户积分不足
+            if ($data['integral'] > $user['user_integral']) {
+                return '用户积分仅剩下' . $user['user_integral'] . '分';
+            }
+        }
+
+        if (empty($data['integral_remark'])) {
+            return '请输入调整积分备注';
+        }
+        return true;
+    }
+
+    /**
+     * @notes 验证成长值
+     * @param $data
+     * @param $user
+     * @return bool|string
+     * @author 段誉
+     * @date 2022/3/16 10:50
+     */
+    protected function checkGrowth($data, $user)
+    {
+        if (empty($data['growth'])) {
+            return '请输入大于0的调整成长值';
+        }
+        if ($data['growth'] < 0) {
+            return '成长值必须大于零';
+        }
+        //验证扣减成长值操作
+        if ($data['growth_handle'] == 0) {
+            //用户成长值不足
+            if ($data['growth'] > $user['user_growth']) {
+                return '用户成长值仅剩下' . $user['user_growth'];
+            }
+        }
+        if (empty($data['growth_remark'])) {
+            return '请输入调整成长值备注';
+        }
+        return true;
+    }
+
+    /**
+     * @notes 验证佣金
+     * @param $data
+     * @param $user
+     * @return bool|string
+     * @author 段誉
+     * @date 2022/3/16 10:50
+     */
+    protected function checkEarnings($data, $user)
+    {
+        if (empty($data['earnings'])) {
+            return '请输入大于0的调整佣金';
+        }
+        if ($data['earnings'] < 0) {
+            return '调整佣金必须大于零';
+        }
+        if (empty($user['earnings'])) {
+            $user['earnings'] = 0;
+        }
+        //验证扣减余额操作
+        if ($data['earnings_handle'] == 0) {
+            if ($data['earnings'] > $user['earnings']) {
+                return '用户佣金仅剩下' . $user['earnings'] . '元';
+            }
+        }
+        if (empty($data['earnings_remark'])) {
+            return '请输入调整佣金备注';
+        }
+        return true;
+    }
+}

+ 217 - 0
app/admin/view/account_log/account_log/growth_lists.html

@@ -0,0 +1,217 @@
+{layout name="layout1" /}
+<div class="wrapper">
+    <div class="layui-card">
+        <div class="layui-card-body">
+            <div class="layui-collapse like-layui-collapse" lay-accordion="" style="border:1px dashed #c4c4c4">
+                <div class="layui-colla-item">
+                    <h2 class="layui-colla-title like-layui-colla-title" style="background-color: #fff">操作提示</h2>
+                    <div class="layui-colla-content layui-show">
+                        <p>*会员成长值变动记录。</p>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="layui-form">
+            <div class="layui-form-item">
+                <div class="layui-inline">
+                    <label class="layui-form-label">会员信息:</label>
+                    <div class="layui-input-inline" style="width: 200px;">
+                        <select name="keyword_type" id="keyword_type">
+                            <option value="sn">会员编号</option>
+                            <option value="nickname">会员昵称</option>
+                            <option value="mobile">会员手机号码</option>
+                        </select>
+                    </div>
+                    <div class="layui-input-inline" style="width: 200px;">
+                        <input type="text" id="keyword" name="keyword" autocomplete="off" class="layui-input">
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <label class="layui-form-label">变动类型:</label>
+                    <div class="layui-input-inline">
+                        <select name="order_source" id="order_source">
+                            <option value="0">全部</option>
+                            {foreach $typeDescArr as $item}
+                            <option value={$item.id}>{$item.name}</option>
+                            {/foreach}
+                        </select>
+                    </div>
+                </div>
+            </div>
+            <div class="layui-form-item">
+                <div class="layui-inline">
+                    <label class="layui-form-label">记录时间:</label>
+                    <div class="layui-input-inline">
+                        <input type="text" class="layui-input time" id="start_time" name="start_time"  autocomplete="off">
+                    </div>
+                    <div class="layui-input-inline" style="margin-right: 5px;width: 10px;">
+                        <label class="layui-form-mid">-</label>
+                    </div>
+                    <div class="layui-input-inline">
+                        <input type="text" class="layui-input time" id="end_time" name="end_time"  autocomplete="off">
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <div class="layui-btn-group">
+                        <button type="button" id="today" day="1" class="layui-btn layui-btn-sm layui-btn-primary day">今天</button>
+                        <button type="button"  day="-1" class="layui-btn layui-btn-sm layui-btn-primary day">昨天</button>
+                        <button type="button"  day="7" class="layui-btn layui-btn-sm layui-btn-primary day">近7天</button>
+                        <button type="button"  day="30" class="layui-btn layui-btn-sm layui-btn-primary day">近30天</button>
+                    </div>
+                </div>
+                <div class="layui-inline">
+                    <button class="layui-btn layui-btn-sm layuiadmin-btn-account {$view_theme_color}" lay-submit lay-filter="account-search">查询</button>
+                    <button class="layui-btn layui-btn-sm layuiadmin-btn-account layui-btn-primary }" lay-submit lay-filter="account-clear-search">清空查询</button>
+                </div>
+            </div>
+
+        </div>
+
+        <div class="layui-card-body">
+            <table id="account-lists" lay-filter="account-lists"></table>
+        </div>
+    </div>
+</div>
+<style>
+    .layui-table-cell {
+        height: auto;
+    }
+</style>
+<script>
+    layui.config({
+        version:"{$front_version}",
+        base: '/static/lib/' //静态资源所在路径
+    }).use(['table','laydate'], function(){
+        var $ = layui.$
+            ,form = layui.form
+            ,table = layui.table
+            ,laydate = layui.laydate;
+
+        //日期时间范围
+        laydate.render({
+            elem: '#start_time'
+            , type: 'datetime'
+            ,theme: '#1E9FFF'
+            // , value: "{$time.today[0]}"
+        });
+
+        laydate.render({
+            elem: '#end_time'
+            , type: 'datetime'
+            ,theme: '#1E9FFF'
+            // ,value: "{$time.today[1]}"
+        });
+
+        //监听搜索
+        form.on('submit(account-search)', function(data){
+            var field = data.field;
+            //执行重载
+            table.reload('account-lists', {
+                where: field,
+                page: {
+                    curr: 1 //重新从第 1 页开始
+                }
+            });
+        });
+
+        //清空查询
+        form.on('submit(account-clear-search)', function(){
+            $('.day').removeClass('layui-btn-normal');
+            $('.day').removeClass('layui-btn-primary');
+            $('.day').addClass('layui-btn-primary');
+            $('#keyword').val('');
+            $('#keyword_type').val('sn');
+            $('#order_source').val(0);
+            $('#start_time').val('');
+            $('#end_time').val('');
+            form.render('select');
+            //刷新列表
+            table.reload('account-lists', {
+                where: [],
+                page: {
+                    curr: 1 //重新从第 1 页开始
+                }
+            });
+        });
+    });
+
+
+
+    layui.define(['table', 'form'], function(exports){
+        var $ = layui.$
+            ,table = layui.table
+            ,form = layui.form;
+
+        table.render({
+            id:'account-lists'
+            ,elem: '#account-lists'
+            ,url: '{:url("account_log.account_log/growthLists")}'
+            ,cols: [[
+                {field: 'nickname',title: '会员昵称'}
+                ,{field: 'sn', title: '会员编号'}
+                ,{field: 'mobile', title: '手机号码'}
+                ,{field: 'change_amount', title: '变动成长值'}
+                ,{field: 'left_amount', title: '剩余成长值 '}
+                ,{field: 'source_type', title: '变动类型'}
+                ,{field: 'source_sn', title: '来源单号'}
+                ,{field: 'create_time', title: '记录时间'}
+
+            ]]
+            ,page:true
+            ,text: {none: '暂无数据!'}
+            ,parseData: function(res){ //将原始数据解析成 table 组件所规定的数据
+                return {
+                    "code":res.code,
+                    "msg":res.msg,
+                    "count": res.data.count, //解析数据长度
+                    "data": res.data.lists, //解析数据列表
+                };
+            },
+            response: {
+                statusCode: 1
+            }
+            , done: function fix() {
+                $(".layui-table-main tr").each(function (index, val) {
+                    $(".layui-table-fixed").each(function () {
+                        $($(this).find(".layui-table-body tbody tr")[index]).height($(val).height());
+                    });
+                });
+                $(".layui-table-header tr").each(function (index, val) {
+                    $(".layui-table-fixed").each(function () {
+                        $($(this).find(".layui-table-header thead tr")[index]).height($(val).height());
+                    });
+                });
+                window.onresize = function () {
+                    fix()
+                }
+            }
+        });
+
+        $('.day').click(function(){
+            $('.day').removeClass('layui-btn-normal');
+            $('.day').removeClass('layui-btn-primary');
+            $('.day').addClass('layui-btn-primary');
+            $(this).removeClass('layui-btn-primary');
+            $(this).addClass('layui-btn-normal');
+            var day = $(this).attr('day');
+            switch (day) {
+                case '-1':
+                    $('#start_time').val('{$time.yesterday[0]}');
+                    $('#end_time').val('{$time.yesterday[1]}');
+                    break;
+                case '1':
+                    $('#start_time').val('{$time.today[0]}');
+                    $('#end_time').val('{$time.today[1]}');
+                    break;
+                case '7':
+                    $('#start_time').val('{$time.days_ago7[0]}');
+                    $('#end_time').val('{$time.days_ago7[1]}');
+                    break;
+                case '30':
+                    $('#start_time').val('{$time.days_ago30[0]}');
+                    $('#end_time').val('{$time.days_ago30[1]}');
+                    break;
+            }
+        });
+    });
+</script>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor