wesmiler 10 months ago
parent
commit
6f0694bc4d

File diff suppressed because it is too large
+ 2 - 2
addons/admin/dist/static/js/17.js


File diff suppressed because it is too large
+ 1 - 1
addons/admin/dist/static/js/19.js


File diff suppressed because it is too large
+ 1 - 1
addons/admin/dist/static/js/4.js


File diff suppressed because it is too large
+ 2 - 2
addons/admin/dist/static/js/7.js


File diff suppressed because it is too large
+ 1 - 1
addons/dapp/dist/js/user.js


+ 49 - 0
app/Console/Commands/SwooleTask.php

@@ -2,6 +2,7 @@
 
 namespace App\Console\Commands;
 
+use App\Services\Api\FinanceService;
 use App\Services\Api\MemberService;
 use App\Services\Api\PledgeOrderService;
 use App\Services\Api\PriceLogService;
@@ -379,6 +380,41 @@ class SwooleTask extends Command
             }
 
         });
+
+        // 开发者维护收益结算
+        \swoole_timer_tick(180000, function ($timer) use ($serv, &$time) { // 启用定时器,每3分钟执行一次
+            $date = date('Y-m-d H:i:s');
+            if ($time > 3600 && file_exists($this->options['log_file'])) {
+                $time = 0;
+                file_put_contents($this->options['log_file'], "Task {$date}:清空日志\n");
+            }
+            $time++;
+            $userList = MemberService::make()->getDeveloperList();
+            if ($userList) {
+                if (!RedisService::get('caches:task:lock:developer_loaded')) {
+                    foreach ($userList as $item) {
+                        $id = $item['id'];
+                        $walletUrl = $item['wallet_url'];
+                        if ($walletUrl) {
+                            $taskData = [
+                                'taskName' => 'DeveloperSettle',
+                                'name' => "开发者维护收益结算",
+                                'params' => $item,
+                                'date' => date('Y-m-d'),
+                            ];
+                            $taskId = $serv->task($taskData);
+                            echo "[Task DeveloperSettle-{$taskId} {$date}] 开发者[{$id}]用户维护收益结算处理\n";
+                        }
+                    }
+                    RedisService::set('caches:task:lock:developer_loaded', true, rand(5, 10));
+                } else {
+                    echo "[Task DeveloperSettle {$date}] 间隔时间调用\n";
+                }
+            } else {
+                echo "[Task DeveloperSettle {$date}] 暂无需要结算收益开发者\n";
+            }
+
+        });
     }
 
     //监听连接进入事件
@@ -481,6 +517,19 @@ class SwooleTask extends Command
                         echo "[Task {$taskName}-{$task_id} {$date}] 用户[{$userId}]等级更新处理结果:{$error}\n";
                     }
                     break;
+                case 'DeveloperSettle': // 维护收益结算
+                    // 调用处理
+                    $id = isset($params['id'])? $params['id'] : 0;
+                    $walletUrl = isset($params['wallet_url'])? $params['wallet_url'] : '';
+                    if ($res = FinanceService::make()->dveloperSettle($id, $walletUrl)) {
+                        $res = is_array($res) && $res ? json_encode($res, 256) : '处理成功';
+                        echo "[Task {$taskName}-{$task_id} {$date}] 开发者[{$id}]维护收益结算处理结果:{$res}\n";
+                    } else {
+                        $error = MemberService::make()->getError();
+                        $error = $error ? lang($error) : '处理失败';
+                        echo "[Task {$taskName}-{$task_id} {$date}] 开发者[{$id}]维护收益结算处理结果:{$error}\n";
+                    }
+                    break;
             }
         } catch (\Exception $exception) {
             return $exception->getMessage();

+ 24 - 0
app/Models/DeveloperModel.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 开发者-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class DeveloperModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'developer';
+}

+ 101 - 0
app/Services/Api/FinanceService.php

@@ -12,6 +12,7 @@
 namespace App\Services\Api;
 
 use App\Models\AccountLogModel;
+use App\Models\DeveloperModel;
 use App\Models\FinanceModel;
 use App\Models\MemberModel;
 use App\Models\PledgeOrderModel;
@@ -1001,4 +1002,104 @@ class FinanceService extends BaseService
             return false;
         }
     }
+
+    /**
+     * 开发者维护收益结算
+     * @param $developerId 开发者ID
+     * @param $walletUrl 开发者地址
+     * @return false
+     */
+    public function dveloperSettle($developerId, $walletUrl)
+    {
+        if(empty($developerId) || empty($walletUrl)){
+            $this->error = 2014;
+            return false;
+        }
+
+        $info = DeveloperModel::from('developer as a')
+                ->leftJoin('member as b','b.wallet_url','=','a.wallet_url')
+                ->where(['id'=> $developerId])
+                ->select(['a.*','b.id as user_id','b.profit'])
+                ->first();
+        $info = $info? $info->toArray() : [];
+        $userId = isset($info['user_id'])? intval($info['user_id']) : 0;
+        $userProfit = isset($info['profit'])? floatval($info['profit']) : 0;
+        if(empty($info) || $userId<=0){
+            $this->error = 2001;
+            return false;
+        }
+
+        $lastSettleAt = isset($info['last_settle_at'])? $info['last_settle_at'] : '';
+        if($lastSettleAt && $lastSettleAt >= date('Y-m-d', time() - 7 * 86400)){
+            $this->error = 1044;
+            return false;
+        }
+
+        $cacheKey = "caches:developer:lock_{$developerId}";
+        if(RedisService::get($cacheKey)){
+            $this->error = 1044;
+            return false;
+        }
+
+        DB::beginTransaction();
+        try {
+            // 全网流水
+            $pledgeTotal = PledgeOrderService::make()->getGlobalTotal();
+
+            // 结算比例
+            $settleRate = ConfigService::make()->getConfigByCode('developer_settle_rate', 3);
+            $settleRate = $settleRate>0 && $settleRate <= 20? $settleRate : 3;
+
+            $settleMoney = round($pledgeTotal * $settleRate/100, 2);
+            if($settleMoney>0){
+                $updateData = [
+                    'profit'=> DB::raw("profit + {$settleMoney}"),
+                    'profit_total'=> DB::raw("profit_total + {$settleMoney}"),
+                    'update_time'=>time()
+                ];
+                if(!MemberModel::where(['id'=> $userId])->update($updateData)){
+                    DB::rollBack();
+                    $this->error = 1045;
+                    return false;
+                }
+
+                $updateData = [
+                    'total'=> DB::raw("total + {$settleMoney}"),
+                    'last_settle_at'=>date('Y-m-d H:i:s')
+                ];
+                if(!DeveloperModel::where(['id'=> $developerId])->update($updateData)){
+                    DB::rollBack();
+                    $this->error = 1045;
+                    return false;
+                }
+
+                // 收益账单
+                $data = [
+                    'user_id' => $userId,
+                    'order_no' => get_order_num('DP'),
+                    'source_uid' => 0,
+                    'type' => 98,
+                    'user_type' => 1,
+                    'coin_type' => 3,
+                    'money' => $settleMoney,
+                    'before_money' => $userProfit,
+                    'create_time' => time(),
+                    'action_ip' => get_client_ip(),
+                    'remark' => "工作室分红",
+                    'status' => 1,
+                    'mark' => 1,
+                ];
+
+                if (!AccountLogModel::insertGetId($data)) {
+                    DB::rollBack();
+                    $this->error = 1045;
+                    return false;
+                }
+            }
+
+        }catch (\Exception $exception){
+            $this->error = $exception->getMessage();
+            return false;
+        }
+    }
 }

+ 60 - 1
app/Services/Api/MemberService.php

@@ -14,6 +14,7 @@ namespace App\Services\Api;
 use App\Helpers\Jwt;
 use App\Models\AccountLogModel;
 use App\Models\BalanceLogModel;
+use App\Models\DeveloperModel;
 use App\Models\MemberLevelModel;
 use App\Models\MemberModel;
 use App\Services\BaseService;
@@ -367,7 +368,7 @@ class MemberService extends BaseService
         $maxBonusRate = $this->getUpBonusRate($uid, $parentIds);
         if ($maxBonusRate > 0 && $bonusRate > $maxBonusRate) {
             $this->errorData = ['rate' => $maxBonusRate];
-            $this->error = 1043;
+            $this->error = 2036;
             return false;
         }
 
@@ -422,6 +423,41 @@ class MemberService extends BaseService
     }
 
     /**
+     * 获取上级团队设置的最近的工作室分红比例
+     * @param $userId
+     * @param $parentIds
+     * @return false|int|mixed
+     */
+    public function getUpRoomBonusRate($userId, $parentIds)
+    {
+        $cacheKey = "caches:member:upRoomRate_{$userId}";
+        $data = RedisService::get($cacheKey);
+        if ($data) {
+            return isset($data['bonus_rate']) ? $data['bonus_rate'] : 0;
+        }
+
+        $parentIds = $parentIds ? explode(',', $parentIds) : [];
+        $parentIds = array_filter($parentIds);
+        krsort($parentIds);
+        if (empty($parentIds) || !is_array($parentIds)) {
+            return 0;
+        }
+
+        $data = $this->model->whereIn('id', $parentIds)
+            ->where('room_bonus_rate', '>', 0)
+            ->where(['mark' => 1])
+            ->select(['id', 'room_bonus_rate'])
+            ->orderByRaw('FIELD(id, "' . implode(',', $parentIds) . '")')
+            ->first();
+        $data = $data ? $data->toArray() : [];
+        if ($data) {
+            RedisService::set($cacheKey, $data, rand(3, 5));
+        }
+
+        return isset($data['room_bonus_rate']) ? $data['room_bonus_rate'] : 0;
+    }
+
+    /**
      * 设置自动质押状态
      * @param int $userId 用户ID
      * @param array $params 参数,status-状态(1-开启,0-关闭,必选)
@@ -1073,4 +1109,27 @@ class MemberService extends BaseService
         }
 
     }
+
+    /**
+     * 有效开发者列表
+     * @return array|mixed
+     */
+    public function getDeveloperList()
+    {
+        $cacheKey = "caches:developer:list";
+        $datas = RedisService::get($cacheKey);
+        if($datas){
+            return $datas;
+        }
+
+        $datas = DeveloperModel::where(['status'=>1])
+            ->where('last_settle_at','<',date('Y-m-d', time() - 7 * 86400))
+            ->limit(200)
+            ->get();
+        $datas = $datas? $datas->toArray() : [];
+        if($datas){
+            RedisService::set($cacheKey, $datas, rand(3600, 7200));
+        }
+        return $datas;
+    }
 }

+ 69 - 1
app/Services/Common/MemberService.php

@@ -155,7 +155,76 @@ class MemberService extends BaseService
         DB::beginTransaction();
         try {
             // 判断团队分红比例
+            $uid = isset($data['id'])? $data['id'] : 0;
+            $info = $this->model->where(['id'=> $uid,'mark'=>1])->select(['id','parent_ids','bonus_rate','room_bonus_rate'])->first();
+            $info = $info? $info->toArray() : [];
+            $userParentId = isset($info['parent_id'])? $info['parent_id'] : 0;
+            $parentIds = isset($info['parent_ids'])? $info['parent_ids'] : '';
 
+            // 最大设置比例
+            $bonusRate = isset($data['bonus_rate'])? floatval($data['bonus_rate']) : 0;
+            if($bonusRate){
+                $maxBonusRate = \App\Services\Api\MemberService::make()->getUpBonusRate($uid, $parentIds);
+                if ($maxBonusRate > 0 && $bonusRate > $maxBonusRate) {
+                    DB::rollBack();
+                    $this->error = lang(2037,['rate'=>$maxBonusRate]);
+                    return false;
+                }
+            }
+
+            // 工作室分红
+            $roomBonusRate = isset($data['room_bonus_rate'])? floatval($data['room_bonus_rate']) : 0;
+            if($roomBonusRate){
+                $maxBonusRate = \App\Services\Api\MemberService::make()->getUpRoomBonusRate($uid, $parentIds);
+                if ($maxBonusRate > 0 && $roomBonusRate > $maxBonusRate) {
+                    DB::rollBack();
+                    $this->error = lang(2038,['rate'=>$maxBonusRate]);
+                    return false;
+                }
+            }
+
+            // 判断是否修改了上级
+            $parentId = isset($data['parent_id'])? intval($data['parent_id']) : 0;
+            if($parentId>0 && $userParentId != $parentId){
+                // 上级是否存在
+                $parentInfo = $this->model->where(['id'=> $parentId,'mark'=>1])->select(['id','parent_ids'])->first();
+                $parentInfo = $parentInfo? $parentInfo->toArray() : [];
+                $parentIds = isset($parentInfo['parent_ids'])? trim($parentInfo['parent_ids']) : '';
+                // 判断该推荐人是否为团队下级
+                $parents = get_parents($parentIds);
+                if(in_array($uid, $parents)){
+                    DB::rollBack();
+                    $this->error = 2039;
+                    return false;
+                }
+
+                // 更新自己推荐关系
+                $data['parent_id'] = $parentId;
+                $data['parent_ids'] = $parentIds? trim($parentIds,',').",{$parentId}," : "{$parentId},";
+                $userParentIds = $data['parent_ids'];
+
+                // 更新下级团队用户推荐关系
+                $updateArr = [];
+                $users = $this->model->whereRaw("FIND_IN_SET({$uid},parent_ids)")->select(['id','parent_id','parent_ids'])->get();
+                foreach($users as $item){
+                    $parentIds = $item['parent_ids'];
+                    if($parentIds){
+                        $newParentIds = $userParentIds? trim($userParentIds,',').",{$uid}," : "{$uid},";
+                        $newParentIds = $parentIds? preg_replace("/*{$uid},/","{$newParentIds}", $newParentIds) : '';
+                        if($newParentIds){
+                            $updateArr[] = [
+                                'parent_ids'=> $newParentIds,
+                                'update_time'=> time(),
+                            ];
+                        }
+                    }
+                }
+
+                // 批量更新
+                if($updateArr){
+                    $this->model->whereRaw("FIND_IN_SET({$uid},parent_ids)")->update($updateArr);
+                }
+            }
 
             $result = parent::edit($data);
             $success = isset($result['success']) ? $result['success'] : false;
@@ -164,7 +233,6 @@ class MemberService extends BaseService
                 return $result;
             }
 
-            // 判断是否修改了上级
 
             ActionLogModel::setTitle("修改会员信息");
             ActionLogModel::record();

+ 1 - 0
config/dapp.php

@@ -19,6 +19,7 @@ return [
         16=>"工作室分红",
         17=>"提现退还",
         18=>"闪兑手续费",
+        98=>"开发者收益",
         99=>"其他"
     ]
 ];

+ 6 - 0
resources/lang/zh-cn/api.php

@@ -43,6 +43,8 @@ return [
     '1041' => '请求失败',
     '1042' => '数据不存在',
     '1043' => '无权操作',
+    '1044' => '已结算过',
+    '1045' => '结算失败',
 
     '1071' => '审核成功',
     '1072' => '审核失败',
@@ -72,6 +74,10 @@ return [
     '2033' => '提现处理失败',
     '2034' => '提现回调处理失败',
     '2035' => ':name账户余额不足扣除',
+    '2036' => '分红比例限制',
+    '2037' => '团队分红比例不能超过上级:rate',
+    '2038' => '工作室分红比例不能超过上级:rate',
+    '2039' => '不能设置推荐人为自己团队下级用户',
 
     '2101'=> '请填写闪兑金额',
     '2102'=> 'SBT账户余额不足',