UserService.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. <?php
  2. namespace app\common\service;
  3. use app\common\model\UserModel;
  4. use app\common\model\UserUnmoneyModel;
  5. use think\facade\Db;
  6. use utils\RedisCache;
  7. /**
  8. * 用户服务 by wes
  9. * Class UserService
  10. * @package app\common\service
  11. */
  12. class UserService
  13. {
  14. protected static $instance = null;
  15. protected $model = null;
  16. public function __construct()
  17. {
  18. $this->model = new UserModel();
  19. }
  20. /**
  21. * 静态化入口
  22. * @return static|null
  23. */
  24. public static function make()
  25. {
  26. if(!self::$instance){
  27. self::$instance = new static();
  28. }
  29. return self::$instance;
  30. }
  31. /**
  32. * 用户缓存信息
  33. * @param int $uid
  34. * @return array|mixed
  35. */
  36. public function getCacheInfo($uid, $field='', $cache=false)
  37. {
  38. $cacheKey = "caches:users:info:u{$uid}".($field?'_'.md5($field):'');
  39. $data = RedisCache::get($cacheKey);
  40. if($data && $cache){
  41. return $data;
  42. }
  43. $where = ['id'=> $uid];
  44. $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';
  45. $data = $this->model->where($where)->field($field)->findOrEmpty();
  46. $data = $data? $data->toArray():[];
  47. if($data && $cache){
  48. RedisCache::set($cacheKey, $data, rand(3,5));
  49. }
  50. return $data;
  51. }
  52. /**
  53. * 结算利润到余额
  54. * @param $uid
  55. * @throws Exception
  56. * @throws \think\db\exception\DataNotFoundException
  57. * @throws \think\db\exception\DbException
  58. * @throws \think\db\exception\ModelNotFoundException
  59. */
  60. public function switchProfitToMoney($uid)
  61. {
  62. $userInfo = UserModel::where('id', $uid)->field('id,mobile,money,profit_money,status')->find();
  63. $profitMoney = isset($userInfo['profit_money'])? intval($userInfo['profit_money']): 0;
  64. $userMoney = isset($userInfo['money'])? floatval($userInfo['money']): 0;
  65. $userStatus = isset($userInfo['status'])? $userInfo['status'] : 0;
  66. if(empty($userInfo) || $userStatus != 1){
  67. sr_throw('用户参数错误或已被冻结');
  68. }
  69. if ($profitMoney < 100){
  70. sr_throw('利润小于100,结算失败');
  71. }else{
  72. $profitMoney = $profitMoney - $profitMoney % 100;
  73. $updateAccount = UserModel::where('id', $uid)
  74. ->inc('money',$profitMoney)
  75. ->inc('total_profit_money', $profitMoney)
  76. ->dec('profit_money', $profitMoney)
  77. ->update();
  78. if(!$updateAccount){
  79. sr_throw('利润结算失败');
  80. }
  81. $data = [
  82. 'uid'=>$uid,
  83. 'type'=> 8,
  84. 'money'=> $profitMoney,
  85. 'status'=> 1,
  86. 'state'=> 2,
  87. 'before_money'=> $userMoney,
  88. 'after_money'=> floatval($userMoney+$profitMoney),
  89. 'remark'=> '利润结算到余额',
  90. 'create_time'=>date('Y-m-d H:i:s')
  91. ];
  92. if(!UserUnmoneyModel::insertGetId($data)){
  93. sr_throw('利润结算处理失败');
  94. }
  95. }
  96. }
  97. /**
  98. * 用户升级
  99. * @return array|string
  100. */
  101. public function updateLevel()
  102. {
  103. $cacheKey = "caches:users:updateLevel:".date('YmdHi');
  104. if(RedisCache::get($cacheKey.'_lock')){
  105. return '请不要频繁提交处理';
  106. }
  107. Db::startTrans();
  108. try {
  109. RedisCache::setnx($cacheKey . 'lock', date('Y-m-d H:i:s'), rand(5, 10));
  110. $list = $this->model->where('has_update_level', '>', 0)
  111. ->field('id,level,pid,path')
  112. ->select();
  113. $list = $list? $list->toArray() : [];
  114. if (empty($list)) {
  115. return '暂无用户需要升级';
  116. }
  117. // 等级配置
  118. $levelConfig = LevelSettingService::make()->getConfigData(0, 1);
  119. if (empty($levelConfig)) {
  120. return '请先配置等级升级参数';
  121. }
  122. // 处理升级
  123. $noCatchUids = []; // 未升级的用户
  124. $levelIds = []; // 升级了的用户
  125. foreach ($list as $item) {
  126. $uid = isset($item['id']) ? $item['id'] : 0;
  127. $path = isset($item['path']) ? $item['path'] : 0;
  128. $userLevel = isset($item['level']) ? intval($item['level']) : 0;
  129. // 判断团队人数获取可升等级
  130. $updateLevel = 0;
  131. $teamCount = $this->getTeamCount($uid, $path); // 团队人数
  132. foreach ($levelConfig as $val) {
  133. $needTeamCount = isset($val['team_num']) ? $val['team_num'] : 0;
  134. $level = isset($val['level']) ? $val['level'] : 0;
  135. // 如果团队人数满足当前等级要求(排除)
  136. if ($level > 0 && $needTeamCount && $teamCount >= $needTeamCount) {
  137. $updateLevel = $level;
  138. }
  139. }
  140. // 如果当前用户需要升级
  141. $ztCount = 0;
  142. if ($updateLevel > $userLevel) {
  143. // 所需直推等级
  144. $ztLevel = isset($levelConfig[$updateLevel]['zt_level']) ? intval($levelConfig[$updateLevel]['zt_level']) : 0;
  145. $ztCount = $this->getZtCount($uid, $ztLevel);
  146. // 可升级的等级所需直推人数
  147. $needZtCount = isset($levelConfig[$updateLevel]['zt_num']) ? intval($levelConfig[$updateLevel]['zt_num']) : 0;
  148. if ($needZtCount <= $ztCount) {
  149. // 当前用户升级,且去掉可升级状态
  150. $this->model->where('id', $uid)->update(['level' => $updateLevel, 'has_update_level' => 0, 'update_time' => date('Y-m-d H:i:s')]);
  151. $levelIds[] = $uid;
  152. }else{
  153. $noCatchUids[] = $uid;
  154. }
  155. }else{
  156. $noCatchUids[] = $uid;
  157. }
  158. // 用户升级后,处理上层用户升级(设置为可升级状态)
  159. if ($path && $updateLevel>$userLevel) {
  160. $this->model->whereIn('id', explode(',', $path))->update(['has_update_level' => 1, 'update_time' => date('Y-m-d H:i:s')]);
  161. }
  162. // 处理缓存
  163. 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);
  164. }
  165. // 如果存在未升级用户清除升级状态
  166. if($noCatchUids){
  167. $this->model->whereIn('id', $noCatchUids)->update(['has_update_level' => 0, 'update_time' => date('Y-m-d H:i:s')]);
  168. }
  169. Db::commit();
  170. RedisCache::set($cacheKey.'_success', ['msg'=>'升级处理成功','total'=> count($list),'level'=>count($levelIds),'date'=>date('Y-m-d H:i:s')], 7200);
  171. return ['code'=>200, 'msg'=>"处理升级成功,累计处理用户".count($list)."个,升级用户".count($levelIds).'个'];
  172. } catch (\Exception $exception){
  173. Db::rollback();
  174. RedisCache::set($cacheKey.'_fail', ['msg'=> $exception->getMessage(),'trace'=> $exception->getTrace(),'date'=>date('Y-m-d H:i:s')], 7200);
  175. return ['code'=>500, 'msg'=>"处理升级失败:".$exception->getMessage()];
  176. }
  177. }
  178. /**
  179. * 统计有效直推人数
  180. * @param $uid
  181. * @param int $level 等级
  182. * @return array|int|mixed
  183. * @throws \think\db\exception\DbException
  184. */
  185. public function getZtCount($uid, $level = 0)
  186. {
  187. $cacheKey = "caches:users:counts:zt_num_{$uid}_{$level}";
  188. $data = RedisCache::get($cacheKey);
  189. if($data){
  190. return $data;
  191. }
  192. $where = ['pid'=> $uid,'has_fd'=>1];
  193. if($level>0){
  194. $where['level'] = $level;
  195. }
  196. $data = $this->model->where($where)->count('id');
  197. if($data){
  198. RedisCache::set($cacheKey, $data, rand(10,20));
  199. }
  200. return $data;
  201. }
  202. /**
  203. * 统计有效团队人数
  204. * @param $uid 用户ID
  205. * @param $path
  206. * @return array|int|mixed
  207. * @throws \think\db\exception\DbException
  208. */
  209. public function getTeamCount($uid, $path)
  210. {
  211. $cacheKey = "caches:users:counts:team_num_{$uid}";
  212. $data = RedisCache::get($cacheKey);
  213. if($data){
  214. return $data;
  215. }
  216. $data = $this->model->where('path','like',"%{$path}")
  217. ->where('has_fd',1)
  218. ->count('id');
  219. if($data){
  220. RedisCache::set($cacheKey, $data, rand(10,20));
  221. }
  222. return $data;
  223. }
  224. }