UserLogic.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. <?php
  2. namespace app\admin\logic;
  3. use app\admin\model\dao\MoneyLog;
  4. use app\admin\model\dao\ScoreLog;
  5. use app\admin\model\dao\User;
  6. use app\common\model\UserModel;
  7. use app\common\model\UserMoneyModel;
  8. use think\facade\Cache;
  9. use think\facade\Db;
  10. class UserLogic
  11. {
  12. public static function forbid($id)
  13. {
  14. $user = User::getUserOrEmptyById($id);
  15. if (empty($user)) return [false, '数据不存在'];
  16. if ($user['status'] == 0) return [false, '该用户已被禁用'];
  17. $result = User::updateStatus($id, 0);
  18. return $result ? [true, '禁用成功'] : [false, '禁用失败'];
  19. }
  20. public static function enable($id)
  21. {
  22. $user = User::getUserOrEmptyById($id);
  23. if (empty($user)) return [false, '数据不存在'];
  24. if ($user['status'] == 1) return [false, '该用户已启用'];
  25. $result = User::updateStatus($id, 1);
  26. return $result ? [true, '禁用成功'] : [false, '禁用失败'];
  27. }
  28. public static function getUserDetail($id)
  29. {
  30. $user = new User();
  31. return $user->getUserDetail($id);
  32. }
  33. public static function levelset($post)
  34. {
  35. $level = $post['level'];
  36. if ($level > 4) {
  37. return '最高等级4级';
  38. }
  39. $user = User::getUserOrEmptyById($post['id']);
  40. if (empty($user)) return '用户不存在';
  41. $level_type = 1;
  42. if ($level > $user['level']) {
  43. $level_type = 2;
  44. }
  45. Db::startTrans();
  46. try {
  47. $userData = ['level' => $level, 'level_type' => $level_type];
  48. User::update($post['id'], $userData);
  49. Db::commit();
  50. } catch (\Exception $e) {
  51. Db::rollback();
  52. return '失败' . $e->getMessage();
  53. }
  54. return true;
  55. }
  56. public static function lookpidlevel($id)
  57. {
  58. $path = Db::name('user')->where('id', $id)->value('path');
  59. if (empty($path)) {
  60. return [0, []];
  61. }
  62. $arr = explode(',', $path);
  63. $ids = $arr;
  64. $ids = implode(',', $ids);
  65. $order = 'field(id,' . $ids . ')';
  66. $where = array();
  67. $where[] = ['uid', 'in', $arr];
  68. sr_log($where);
  69. $user = new UserModel();
  70. $count = $user
  71. ->withJoin('userData', 'INNER')
  72. ->where($where)
  73. ->count();
  74. $list = $user
  75. ->withJoin('userData', 'INNER')
  76. ->where($where)
  77. ->order(Db::raw($order))
  78. ->select();
  79. return [$count, $list];
  80. }
  81. public static function getExportList($where, $page, $limit)
  82. {
  83. return (new UserModel())
  84. ->where($where)
  85. ->withJoin('userData', 'INNER')
  86. ->where($where)
  87. ->page($page, $limit)
  88. ->order('id', 'desc')
  89. ->select()
  90. ->toArray();
  91. }
  92. public static function recycleCountSet($post)
  93. {
  94. $user = User::getUserById($post['id']);
  95. if (empty($user)) return '用户不存在';
  96. if (empty($post['recycle_count']) || $post['recycle_count'] < 0 || $post['recycle_count'] > 500) {
  97. return '回收卡数量格式有误';
  98. }
  99. try {
  100. $updateData = ['recycle_count' => $post['recycle_count']];
  101. $result = User::update($user['id'], $updateData);
  102. if (!$result) return "更新临时卡数量失败";
  103. } catch (\Exception $e) {
  104. return '失败' . $e->getMessage();
  105. }
  106. return true;
  107. }
  108. public function getList($page, $limit, $where, $sort, $userMap)
  109. {
  110. $where[] = ['status', '<>', 3];
  111. $userDao = new User();
  112. $count = $userDao->getCount($where, $userMap);
  113. $list = $userDao->getPageList($page, $limit, $where, $sort, $userMap);
  114. foreach ($list as &$item) {
  115. //团队会员(包括1、2级和自身)的积分账户合计、余额账户合计
  116. // 计算团队成员(包括1、2级和自身)ID
  117. $teamIds = $this->getTeamMoneyAndScore($item['id']);
  118. // 积分账户合计
  119. $item['score_total'] = $teamIds['score'];
  120. // 余额账户合计
  121. $item['money_total'] = $teamIds['money'];
  122. }
  123. $data = [
  124. 'code' => 0,
  125. 'msg' => Db::getLastSql(),
  126. 'count' => $count,
  127. 'data' => $list,
  128. ];
  129. return json($data);
  130. }
  131. /**
  132. * 获取团队自身,一级、二级自己的余额/积分
  133. * @param $uid
  134. */
  135. private function getTeamMoneyAndScore($uid)
  136. {
  137. $cacheKey = 'userLogicTeamIds_' . $uid;
  138. if (!Cache::has($cacheKey)) {
  139. // 自身
  140. $user = Db::table(User::$table)
  141. ->where('id', $uid)
  142. ->field(['id', 'score', 'money'])
  143. ->find();
  144. $totalScore = $user['score'];
  145. $totalMoney = $user['money'];
  146. // 一级子用户
  147. Db::table(User::$table)
  148. ->where('pid', $uid)
  149. ->field(['id', 'score', 'money'])
  150. ->chunk(100, function ($users) use (&$totalScore, &$totalMoney) {
  151. foreach ($users as $user) {
  152. $uids[] = $user['id'];
  153. $totalScore += $user['score'];
  154. $totalMoney += $user['money'];
  155. }
  156. // 二级子用户
  157. Db::table(User::$table)
  158. ->whereIn('pid', $uids)
  159. ->field(['id', 'score', 'money'])
  160. ->chunk(100, function ($users) use (&$totalScore, &$totalMoney) {
  161. foreach ($users as $user) {
  162. $totalScore += $user['score'];
  163. $totalMoney += $user['money'];
  164. }
  165. });
  166. }, ['score', 'money']);
  167. Cache::set($cacheKey, ['score' => $totalScore, 'money' => sprintf("%.2f", $totalMoney)], 5 * 60);
  168. }
  169. return Cache::get($cacheKey);
  170. }
  171. /**
  172. * 修改用户手机号码
  173. * @param $uid
  174. * @param $phone
  175. */
  176. public function modifyPhone($uid, $phone)
  177. {
  178. // 判断手机号码是否使用过
  179. $user = User::getUserById($uid);
  180. if (empty($user)) return '用户不存在';
  181. if ($user['mobile'] == $phone) return "请输入新的手机号码";
  182. if (User::getUserByMobile($phone)) return "该手机号码已注册";
  183. // 修改用户信息
  184. try {
  185. $updateData = [
  186. 'mobile' => $phone,
  187. ];
  188. // 按照账号原规则,手机号码作为用户名,同时修改新的用户名
  189. if ($user['mobile'] == $user['user_name']) {
  190. $updateData['user_name'] = $phone;
  191. }
  192. $result = User::update($uid, $updateData);
  193. if (!$result) return "更新手机号码失败,请稍后重试";
  194. } catch (\Exception $e) {
  195. return '失败' . $e->getMessage();
  196. }
  197. return true;
  198. }
  199. /**
  200. * 修改用户所属上级
  201. * @param $uid
  202. * @param $pid
  203. */
  204. public function modifypid($uid, $pid)
  205. {
  206. $user = User::getUserById($uid);
  207. if (empty($user)) return '用户不存在';
  208. // 查询pid是否存在用户path中
  209. if ($uid == $pid) {
  210. return "不能修改自己为上级";
  211. }
  212. if ($user['pid'] == $pid) {
  213. return "该用户已所属待变更的上级,不能修改";
  214. }
  215. $parentUser = User::getUserById($pid);
  216. if (empty($parentUser)) {
  217. return '所属上级不存在';
  218. }
  219. // 判断降级或升级
  220. // 判断升级,降级、插入
  221. list($operateType, $prefixPath) = $this->getOperateType($user['id'], $user['path'], $pid, $parentUser['path']);
  222. Db::startTrans();
  223. try {
  224. if ($operateType) {
  225. // 死循环,分支
  226. $result = $this->modifypidByResetTopLevel($user['id'], $user['path'], $pid, $parentUser['path'], $prefixPath);
  227. } else {
  228. // 正常,迭代修改下级
  229. $result = $this->modifypidByUpdateNextLevel($user['id'], $user['path'], $pid, $parentUser['path']);
  230. }
  231. if (!$result) {
  232. Db::rollback();
  233. return "修改用户所属上级失败,请确认用户的层级关系";
  234. }
  235. Db::commit();
  236. } catch (\Exception $exception) {
  237. Db::rollback();
  238. return "失败:" . $exception->getMessage();
  239. }
  240. return true;
  241. // 升级,abcdef,e升级到b后 分为两种情况 1.abef 2.abcd
  242. // 降级 abcdef,c降级到e后 分为两种情况 1. ecf 2.abcd
  243. // 插入 abcdef,插入j到b后 分为两种情况 1.abj 2.abcdef
  244. }
  245. /**
  246. * 修改余额
  247. * @param $post
  248. */
  249. public function ModifyMoney($post)
  250. {
  251. $user = User::getUserById($post['uid']);
  252. if (empty($user)) {
  253. return "用户不存在";
  254. }
  255. Db::startTrans();
  256. try {
  257. if ($post['state'] == 1) {
  258. $afterMoney = $user['money'] + $post['money'];
  259. } else {
  260. $afterMoney = $user['money'] - $post['money'];
  261. if ($afterMoney < 0) {
  262. return "账号余额不足";
  263. }
  264. }
  265. $afterMoney = round($afterMoney, 2);
  266. $moneyLog = [
  267. 'uid' => $post['uid'],
  268. 'type' => $post['type'] ?? 0,
  269. 'money' => $post['money'],
  270. 'create_at' => date('Y-m-d H:i:s'),
  271. 'state' => $post['state'] ?? '0',
  272. 'from_id' => $post['from_id'] ?? '0',
  273. 'before_money' => $user['money'],
  274. 'after_money' => $afterMoney,
  275. 'uid2' => $post['uid2'] ?? 0,
  276. 'free_type' => $post['free_type'] ?? '',
  277. 'remark' => $post['remark'],
  278. ];
  279. // 子级path变更
  280. MoneyLog::AddMoneyLog($moneyLog);
  281. User::UpdateUserMoney($user['id'], $afterMoney);
  282. Db::commit();
  283. } catch (\Exception $exception) {
  284. Db::rollback();
  285. return "失败:" . $exception->getMessage();
  286. }
  287. return true;
  288. }
  289. /**
  290. * 修改积分
  291. * @param $post
  292. */
  293. public function ModifyScore($post)
  294. {
  295. $user = User::getUserById($post['uid']);
  296. if (empty($user)) {
  297. return "用户不存在";
  298. }
  299. Db::startTrans();
  300. try {
  301. if ($post['state'] == 1) {
  302. $afterScore = $user['score'] + $post['score'];
  303. } else {
  304. $afterScore = $user['score'] - $post['score'];
  305. if ($afterScore < 0) {
  306. return "账号积分不足";
  307. }
  308. }
  309. $moneyLog = [
  310. 'uid' => $post['uid'],
  311. 'type' => $post['type'] ?? 0,
  312. 'score' => $post['score'],
  313. 'create_at' => date('Y-m-d H:i:s'),
  314. 'scene' => $post['scene'] ?? 0,
  315. 'from_id' => $post['from_id'] ?? '0',
  316. 'state' => $post['state'] ?? '0',
  317. 'before_score' => $user['score'],
  318. 'after_score' => $afterScore,
  319. 'uid2' => $post['uid2'] ?? 0,
  320. ];
  321. // 子级path变更
  322. ScoreLog::AddScoreLog($moneyLog);
  323. User::UpdateUserScore($user['id'], $afterScore);
  324. Db::commit();
  325. } catch (\Exception $exception) {
  326. Db::rollback();
  327. return "失败:" . $exception->getMessage();
  328. }
  329. return true;
  330. }
  331. /**
  332. * 删除用户
  333. * @param $id
  334. */
  335. public function delUser($id)
  336. {
  337. $user = User::getUserById($id);
  338. if (empty($user)) {
  339. return "用户不存在";
  340. }
  341. if (User::updateStatus($id, 3) !== 1) {
  342. return false;
  343. }
  344. return true;
  345. }
  346. /* 注册用户数量统计
  347. * @param string $time 时间节点如:2023-03-01
  348. * @return
  349. * @throws \think\db\exception\DbException
  350. */
  351. public static function getCountByTime($time = '0')
  352. {
  353. $cacheKey = "caches:user:counts_{$time}";
  354. if (!Cache::has($cacheKey)) {
  355. $data = UserModel::where(['status' => 1])
  356. ->where(function ($query) use ($time) {
  357. if ($time) {
  358. $query->where('reg_time', '>=', $time);
  359. }
  360. })->count('id');
  361. if ($data) {
  362. Cache::set($cacheKey, $data, rand(3, 5));
  363. }
  364. return $data;
  365. }
  366. return Cache::get($cacheKey);
  367. }
  368. /**
  369. * 判断操作类型,true-死循环 false-正常
  370. * @param $pid
  371. * @param $path
  372. * @return int
  373. */
  374. private function getOperateType($uid, $path, $pid, $pUserPath)
  375. {
  376. // $pUserPathArr = explode(',', $pUserPath);
  377. list($isFallLevel, $prefixPath) = $this->isFallLevel($uid, $pid);
  378. if ($isFallLevel) {
  379. return [true, $prefixPath];
  380. }
  381. return [false, null];
  382. }
  383. private function modifypidByUpdateNextLevel($id, $path, $pid, $parentUserPath)
  384. {
  385. $parentUserPathArr = explode(',', $parentUserPath);
  386. $newUserPathArr = $parentUserPathArr;
  387. $newUserPathArr[] = $pid;
  388. $result = $this->iteraMidifyPathByPid($newUserPathArr, $id);
  389. if (!$result) return false;
  390. // 更新用户Pid,Path
  391. return User::modifyUserPidAndPath($id, $pid, implode(',', $newUserPathArr));
  392. }
  393. private function iteraMidifyPathByPid($newUserPathArr, $pid)
  394. {
  395. $newUserPathArr[] = $pid;
  396. $result = Db::table(User::$table)
  397. ->where([
  398. 'pid' => $pid
  399. ])
  400. ->field(['id', 'path'])
  401. ->chunk(100, function ($users) use ($pid, $newUserPathArr) {
  402. foreach ($users as $user) {
  403. User::modifyUserPath($user['id'], implode(',', $newUserPathArr));
  404. $this->iteraMidifyPathByPid($newUserPathArr, $user['id']);
  405. }
  406. });
  407. return $result;
  408. }
  409. private function modifypidByResetTopLevel($id, $path, $pid, $parentUserPath, $prefixPath)
  410. {
  411. $newUserPathArr[] = $pid;
  412. $this->updatePidAndPathByPath($id, $prefixPath);
  413. $parentUser = User::getUserById($pid);
  414. $newUserPathArr = explode(',', $parentUser['path']);
  415. $newUserPathArr[] = $pid;
  416. User::modifyUserPidAndPath($id, $pid, implode(',', $newUserPathArr));
  417. $this->iteraMidifyPathByPid($newUserPathArr, $id);
  418. return true;
  419. // $result = User::modifyUserPidAndPath($pid, 0, '');
  420. // if (!$result) return false;
  421. // return User::modifyUserPidAndPath($id, $pid, implode(',', $newUserPathArr));
  422. }
  423. private function isFallLevel($uid, $pid)
  424. {
  425. $user = Db::query(sprintf("SELECT id,path,pid FROM db_user WHERE FIND_IN_SET('%s',path) and FIND_IN_SET('%s',path) LIMIT 1;", $uid, $pid));
  426. if (empty($user)) {
  427. return [false, null];
  428. }
  429. $userPath = explode(',', $user[0]['path']);
  430. $uidIndex = array_search($uid, $userPath);
  431. if ($uidIndex < array_search($pid, $userPath)) {
  432. $returnPath = [];
  433. if (isset($userPath[$uidIndex - 1])) {
  434. $returnPath[] = $userPath[$uidIndex - 1];
  435. }
  436. $returnPath[] = $userPath[$uidIndex];
  437. $returnPath[] = $userPath[$uidIndex + 1];
  438. return [true, $returnPath];
  439. }
  440. return [false, null];
  441. }
  442. private function updatePidAndPathByPath($uid, $prefixPath)
  443. {
  444. $newTopUid = $prefixPath[count($prefixPath) - 1];
  445. // 从阶段处更新,分支出来作为第一层
  446. User::modifyUserPidAndPath($newTopUid, 0, '');
  447. User::modifyUserPidAndPathByPid($uid, 0, '');
  448. $newUserPathArr = [];
  449. return $this->iteraMidifyPathByPid($newUserPathArr, $newTopUid);
  450. }
  451. }