model = new UserModel(); } /** * 静态化入口 * @return static|null */ public static function make() { if(!self::$instance){ self::$instance = new static(); } return self::$instance; } /** * 用户缓存信息 * @param int $uid * @return array|mixed */ public function getCacheInfo($uid, $field='', $cache=false) { $cacheKey = "caches:users:info:u{$uid}".($field?'_'.md5($field):''); $data = RedisCache::get($cacheKey); if($data && $cache){ return $data; } $where = ['id'=> $uid]; $field = $field? $field : 'id,user_name,mobile,level,code,pid,money,score,profit_money,level_type,status,is_auth,is_reward,user_type,store_type,has_fd'; $data = $this->model->where($where)->field($field)->findOrEmpty(); $data = $data? $data->toArray():[]; if($data && $cache){ RedisCache::set($cacheKey, $data, rand(3,5)); } return $data; } /** * 结算利润到余额 * @param $uid * @throws Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function switchProfitToMoney($uid) { $userInfo = UserModel::where('id', $uid)->field('id,mobile,money,profit_money,status')->find(); $profitMoney = isset($userInfo['profit_money'])? intval($userInfo['profit_money']): 0; $userMoney = isset($userInfo['money'])? floatval($userInfo['money']): 0; $userStatus = isset($userInfo['status'])? $userInfo['status'] : 0; if(empty($userInfo) || $userStatus != 1){ sr_throw('用户参数错误或已被冻结'); } if ($profitMoney < 100){ sr_throw('利润小于100,结算失败'); }else{ $profitMoney = $profitMoney - $profitMoney % 100; $updateAccount = UserModel::where('id', $uid) ->inc('money',$profitMoney) ->inc('total_profit_money', $profitMoney) ->dec('profit_money', $profitMoney) ->update(); if(!$updateAccount){ sr_throw('利润结算失败'); } $data = [ 'uid'=>$uid, 'type'=> 8, 'money'=> $profitMoney, 'status'=> 1, 'state'=> 2, 'before_money'=> $userMoney, 'after_money'=> floatval($userMoney+$profitMoney), 'remark'=> '利润结算到余额', 'create_time'=>date('Y-m-d H:i:s') ]; if(!UserUnmoneyModel::insertGetId($data)){ sr_throw('利润结算处理失败'); } } } /** * 批量用户升级 * @return array|string */ public function updateLevel() { $cacheKey = "caches:users:updateLevel:".date('YmdHi'); if(RedisCache::get($cacheKey.'_lock')){ return '请不要频繁提交处理'; } Db::startTrans(); try { RedisCache::setnx($cacheKey . 'lock', date('Y-m-d H:i:s'), rand(5, 10)); $list = $this->model->where('has_update_level', '>', 0) ->field('id,level,nickname,pid,path') ->select(); $list = $list? $list->toArray() : []; if (empty($list)) { return '暂无用户需要升级'; } // 等级配置 $levelConfig = LevelSettingService::make()->getConfigData(0, 1); if (empty($levelConfig)) { return '请先配置等级升级参数'; } // 处理升级 $noCatchUids = []; // 未升级的用户 $levelIds = []; // 升级了的用户 foreach ($list as $item) { $uid = isset($item['id']) ? $item['id'] : 0; $path = isset($item['path']) ? $item['path'] : 0; $nickname = isset($item['nickname']) ? $item['nickname'] : ''; $userLevel = isset($item['level']) ? intval($item['level']) : 0; // 判断团队人数获取可升等级 $updateLevel = 0; $teamCount = $this->getTeamCount($uid, $path); // 团队人数 foreach ($levelConfig as $val) { $needTeamCount = isset($val['team_num']) ? $val['team_num'] : 0; $level = isset($val['level']) ? $val['level'] : 0; // 如果团队人数满足当前等级要求(排除) if ($level > 0 && $needTeamCount && $teamCount >= $needTeamCount) { $updateLevel = $level; } } // 如果当前用户需要升级 $ztCount = 0; if ($updateLevel > $userLevel) { // 所需直推等级 $nextLevelData = isset($levelConfig[$updateLevel])?$levelConfig[$updateLevel] : []; $ztLevel = isset($nextLevelData['zt_level']) ? intval($nextLevelData['zt_level']) : 0; $ztCount = $this->getZtCount($uid, $ztLevel); // 可升级的等级所需直推人数 $needZtCount = isset($nextLevelData['zt_num']) ? intval($nextLevelData['zt_num']) : 0; if ($needZtCount <= $ztCount) { // 当前用户升级,且去掉可升级状态 $this->model->where('id', $uid)->update(['level' => $updateLevel, 'has_update_level' => 0, 'update_time' => date('Y-m-d H:i:s')]); UpgradeLogModel::insert(['uid' => $uid, 'nickname' => $nickname, 'original_level' => $userLevel, 'level' => $updateLevel, 'condition' => json_encode($nextLevelData), 'type' => 2, 'state' => 1]); $levelIds[] = $uid; }else{ $noCatchUids[] = $uid; } }else{ $noCatchUids[] = $uid; } // 用户升级后,处理上层用户升级(设置为可升级状态) if ($path && $updateLevel>$userLevel) { $this->model->whereIn('id', explode(',', $path))->update(['has_update_level' => 1, 'update_time' => date('Y-m-d H:i:s')]); } // 处理缓存 RedisCache::set("caches:users:updateLevel:user_{$uid}:".date('YmdHi'), ['msg'=>'升级处理成功','data'=> $val,'team'=>$teamCount,'zt'=>$ztCount,'updateLevel'=> $updateLevel,'config'=>$levelConfig,'date'=>date('Y-m-d H:i:s')], 3600); } // 如果存在未升级用户清除升级状态 if($noCatchUids){ $this->model->whereIn('id', $noCatchUids)->update(['has_update_level' => 0, 'update_time' => date('Y-m-d H:i:s')]); } Db::commit(); RedisCache::set($cacheKey.'_success', ['msg'=>'升级处理成功','total'=> count($list),'level'=>count($levelIds),'date'=>date('Y-m-d H:i:s')], 7200); return ['code'=>200, 'msg'=>"处理升级成功,累计处理用户".count($list)."个,升级用户".count($levelIds).'个']; } catch (\Exception $exception){ Db::rollback(); RedisCache::set($cacheKey.'_fail', ['msg'=> $exception->getMessage(),'trace'=> $exception->getTrace(),'date'=>date('Y-m-d H:i:s')], 7200); return ['code'=>500, 'msg'=>"处理升级失败:".$exception->getMessage()]; } } /** * 用户升级 * @param $uid * @param int $type * @return array * @throws \think\Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function upgradeLevel($uid, $type=2) { $cacheKey = "caches:users:updateLevel:{$uid}_".date('YmdHi'); if(RedisCache::get($cacheKey.'_lock')){ sr_throw('暂不需要升级'); } RedisCache::setnx($cacheKey . 'lock', date('Y-m-d H:i:s'), rand(5, 10)); $info = $this->model->where('id', $uid) ->field('id,level,nickname,pid,path') ->findOrEmpty(); $path = isset($info['path']) ? $info['path'] : 0; $nickname = isset($info['nickname']) ? $info['nickname'] : ''; $userLevel = isset($info['level']) ? intval($info['level']) : 0; // 等级配置 $levelConfig = LevelSettingService::make()->getConfigData(0, 1); if (empty($levelConfig)) { sr_throw('请先配置等级升级参数'); } // 判断团队人数获取可升等级 $updateLevel = 0; $teamCount = $this->getTeamCount($uid, $path); // 团队人数 foreach ($levelConfig as $val) { $needTeamCount = isset($val['team_num']) ? $val['team_num'] : 0; $level = isset($val['level']) ? $val['level'] : 0; // 如果团队人数满足当前等级要求(排除) if ($level > 0 && $needTeamCount && $teamCount >= $needTeamCount) { $updateLevel = $level; } } // 如果当前用户需要升级 $canUpgrade = false; if ($updateLevel > $userLevel) { // 所需直推等级 $nextLevelData = isset($levelConfig[$updateLevel])?$levelConfig[$updateLevel] : []; $ztLevel = isset($nextLevelData['zt_level']) ? intval($nextLevelData['zt_level']) : 0; $ztCount = $this->getZtCount($uid, $ztLevel); // 可升级的等级所需直推人数 $needZtCount = isset($nextLevelData['zt_num']) ? intval($nextLevelData['zt_num']) : 0; if ($needZtCount <= $ztCount) { $canUpgrade == true; } } if($type == 2){ if($canUpgrade){ return ['code'=>206, 'msg'=>'当前可以升级']; }else{ throw new Exception('未达到升级条件', 205); } } if($type == 1 && $canUpgrade){ // 当前用户升级,且去掉可升级状态 $this->model->where('id', $uid)->update(['level' => $updateLevel, 'has_update_level' => 0, 'update_time' => date('Y-m-d H:i:s')]); UpgradeLogModel::insert(['uid' => $uid, 'nickname' => $nickname, 'original_level' => $userLevel, 'level' => $updateLevel, 'condition' => json_encode($nextLevelData), 'type' => 2, 'state' => 1]); // 用户升级后,处理上层用户升级(设置为可升级状态) if ($path) { $this->model->whereIn('id', explode(',', $path))->update(['has_update_level' => 1, 'update_time' => date('Y-m-d H:i:s')]); } return ['msg' => '升级成功,当前等级为:' . $nextLevelData['name'], 'data'=>['level_name' => $nextLevelData['name']]]; } sr_throw('未达到升级条件'); } /** * 统计有效直推人数 * @param $uid * @param int $level 等级 * @return array|int|mixed * @throws \think\db\exception\DbException */ public function getZtCount($uid, $level = 0) { $cacheKey = "caches:users:counts:zt_num_{$uid}_{$level}"; $data = RedisCache::get($cacheKey); if($data){ return $data; } $where = ['pid'=> $uid,'has_fd'=>1]; if($level>0){ $where['level'] = $level; } $data = $this->model->where($where)->count('id'); if($data){ RedisCache::set($cacheKey, $data, rand(10,20)); } return $data; } /** * 统计有效团队人数 * @param $uid 用户ID * @param $path * @return array|int|mixed * @throws \think\db\exception\DbException */ public function getTeamCount($uid, $path) { $cacheKey = "caches:users:counts:team_num_{$uid}"; $data = RedisCache::get($cacheKey); if($data){ return $data; } $data = $this->model->where('path','like',"%{$path}") ->where('has_fd',1) ->count('id'); if($data){ RedisCache::set($cacheKey, $data, rand(10,20)); } return $data; } }