UserLogic.php 18 KB

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