LoginServices.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\services\user;
  13. use app\dao\user\UserDao;
  14. use app\services\BaseServices;
  15. use app\services\yihaotong\SmsRecordServices;
  16. use app\services\message\notice\SmsService;
  17. use app\services\wechat\WechatUserServices;
  18. use crmeb\exceptions\ApiException;
  19. use crmeb\services\CacheService;
  20. use crmeb\services\HttpService;
  21. use Firebase\JWT\JWT;
  22. use think\facade\Config;
  23. /**
  24. *
  25. * Class LoginServices
  26. * @package app\services\user
  27. */
  28. class LoginServices extends BaseServices
  29. {
  30. /**
  31. * LoginServices constructor.
  32. * @param UserDao $dao
  33. */
  34. public function __construct(UserDao $dao)
  35. {
  36. $this->dao = $dao;
  37. }
  38. /**
  39. * H5账号登陆
  40. * @param $account
  41. * @param $password
  42. * @param $spread
  43. * @return array
  44. * @throws \think\db\exception\DataNotFoundException
  45. * @throws \think\db\exception\DbException
  46. * @throws \think\db\exception\ModelNotFoundException
  47. */
  48. public function login($account, $password, $spread, $agent_id)
  49. {
  50. $user = $this->dao->getOne(['account|phone' => $account, 'is_del' => 0]);
  51. if ($user) {
  52. if ($user->pwd !== md5((string)$password))
  53. throw new ApiException(410025);
  54. if ($user->pwd === md5('123456'))
  55. throw new ApiException(410026);
  56. } else {
  57. throw new ApiException(410025);
  58. }
  59. if (!$user['status'])
  60. throw new ApiException(410027);
  61. //更新用户信息
  62. if ($agent_id) {
  63. $this->updateUserInfo(['code' => $agent_id, 'is_staff' => 1], $user);
  64. } else {
  65. $this->updateUserInfo(['code' => $spread], $user);
  66. }
  67. $token = $this->createToken((int)$user['uid'], 'api');
  68. if ($token) {
  69. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  70. } else
  71. throw new ApiException(410019);
  72. }
  73. /**
  74. * 更新用户信息
  75. * @param $user
  76. * @param $userInfo
  77. * @param false $is_new
  78. * @return bool
  79. * @throws \think\db\exception\DataNotFoundException
  80. * @throws \think\db\exception\DbException
  81. * @throws \think\db\exception\ModelNotFoundException
  82. */
  83. public function updateUserInfo($user, $userInfo, $is_new = false)
  84. {
  85. $data = [];
  86. $data['phone'] = !isset($user['phone']) || !$user['phone'] ? $userInfo->phone : $user['phone'];
  87. $data['last_time'] = time();
  88. $data['last_ip'] = app()->request->ip();
  89. $spreadUid = $user['code'] ?? 0;
  90. //如果扫了员工邀请码,上级,代理商,区域代理都会改动。
  91. if (isset($user['is_staff']) && !$userInfo['is_agent'] && !$userInfo['is_division']) {
  92. $spreadInfo = $this->dao->get($spreadUid);
  93. if ($userInfo['uid'] != $spreadUid) {
  94. $data['spread_uid'] = $spreadUid;
  95. $data['spread_time'] = $userInfo->last_time;
  96. }
  97. $data['agent_id'] = $spreadInfo->agent_id;
  98. $data['division_id'] = $spreadInfo->division_id;
  99. $data['staff_id'] = $userInfo['uid'];
  100. $data['is_staff'] = $user['is_staff'] ?? 0;
  101. $data['division_type'] = 3;
  102. $data['division_status'] = 1;
  103. $data['division_change_time'] = time();
  104. $data['division_end_time'] = $spreadInfo->division_end_time;
  105. //如果店员切换代理商,则店员在之前代理商下推广的用户,他们的直接上级从当前店员变为之前代理商
  106. if ($userInfo->agent_id != 0 && $userInfo->agent_id != $spreadInfo->agent_id) {
  107. $this->dao->update(['staff_id' => $userInfo['uid'], 'spread_uid' => $userInfo['uid']], ['spread_uid' => $spreadInfo['agent_id'], 'staff_id' => 0]);
  108. $this->dao->update(['staff_id' => $userInfo['uid'], 'not_spread_uid' => $userInfo['uid']], ['staff_id' => 0]);
  109. }
  110. //绑定用户后置事件
  111. event('UserRegisterListener', [$spreadUid, $userInfo['user_type'], $userInfo['nickname'], $userInfo['uid'], $is_new]);
  112. //推送消息
  113. event('NoticeListener', [['spreadUid' => $spreadUid, 'user_type' => $userInfo['user_type'], 'nickname' => $userInfo['nickname']], 'bind_spread_uid']);
  114. //自定义事件-绑定关系
  115. event('CustomEventListener', ['user_spread', [
  116. 'uid' => $userInfo['uid'],
  117. 'nickname' => $userInfo['nickname'],
  118. 'spread_uid' => $spreadUid,
  119. 'spread_time' => date('Y-m-d H:i:s'),
  120. 'user_type' => $userInfo['user_type'],
  121. ]]);
  122. } else {
  123. if ($is_new) {
  124. if ($spreadUid) {
  125. $spreadInfo = $this->dao->get($spreadUid);
  126. $spreadUid = (int)$spreadUid;
  127. $data['spread_uid'] = $spreadUid;
  128. $data['spread_time'] = time();
  129. $data['agent_id'] = $spreadInfo->agent_id;
  130. $data['division_id'] = $spreadInfo->division_id;
  131. $data['staff_id'] = $spreadInfo->staff_id;
  132. //绑定用户后置事件
  133. event('UserRegisterListener', [$spreadUid, $userInfo['user_type'], $userInfo['nickname'], $userInfo['uid'], 1]);
  134. //推送消息
  135. event('NoticeListener', [['spreadUid' => $spreadUid, 'user_type' => $userInfo['user_type'], 'nickname' => $userInfo['nickname']], 'bind_spread_uid']);
  136. //自定义事件-绑定关系
  137. event('CustomEventListener', ['user_spread', [
  138. 'uid' => $userInfo['uid'],
  139. 'nickname' => $userInfo['nickname'],
  140. 'spread_uid' => $spreadUid,
  141. 'spread_time' => date('Y-m-d H:i:s'),
  142. 'user_type' => $userInfo['user_type'],
  143. ]]);
  144. }
  145. } else {
  146. //永久绑定
  147. $store_brokerage_binding_status = sys_config('store_brokerage_binding_status', 1);
  148. if ($userInfo->spread_uid && $store_brokerage_binding_status == 1 && !isset($user['is_staff'])) {
  149. $data['login_type'] = $user['login_type'] ?? $userInfo->login_type;
  150. } else {
  151. //绑定分销关系 = 所有用户
  152. if (sys_config('brokerage_bindind', 1) == 1) {
  153. //分销绑定类型为时间段且过期 ||临时
  154. $store_brokerage_binding_time = sys_config('store_brokerage_binding_time', 30);
  155. if (!$userInfo['spread_uid'] || $store_brokerage_binding_status == 3 || ($store_brokerage_binding_status == 2 && ($userInfo['spread_time'] + $store_brokerage_binding_time * 24 * 3600) < time())) {
  156. if ($spreadUid && $user['code'] != $userInfo->uid && $userInfo->uid != $this->dao->value(['uid' => $spreadUid], 'spread_uid')) {
  157. $spreadInfo = $this->dao->get($spreadUid);
  158. $spreadUid = (int)$spreadUid;
  159. $data['spread_uid'] = $spreadUid;
  160. $data['spread_time'] = time();
  161. $data['agent_id'] = $spreadInfo->agent_id;
  162. $data['division_id'] = $spreadInfo->division_id;
  163. $data['staff_id'] = $spreadInfo->staff_id;
  164. //绑定用户后置事件
  165. event('UserRegisterListener', [$spreadUid, $userInfo['user_type'], $userInfo['nickname'], $userInfo['uid'], 0]);
  166. //推送消息
  167. event('NoticeListener', [['spreadUid' => $spreadUid, 'user_type' => $userInfo['user_type'], 'nickname' => $userInfo['nickname']], 'bind_spread_uid']);
  168. //自定义事件-绑定关系
  169. event('CustomEventListener', ['user_spread', [
  170. 'uid' => $userInfo['uid'],
  171. 'nickname' => $userInfo['nickname'],
  172. 'spread_uid' => $spreadUid,
  173. 'spread_time' => date('Y-m-d H:i:s'),
  174. 'user_type' => $userInfo['user_type'],
  175. ]]);
  176. }
  177. }
  178. }
  179. }
  180. }
  181. }
  182. if (!$this->dao->update($userInfo['uid'], $data, 'uid')) {
  183. throw new ApiException(100007);
  184. }
  185. return true;
  186. }
  187. public function verify(SmsService $services, $phone, $type, $time)
  188. {
  189. if ($this->dao->getOne(['account' => $phone, 'is_del' => 0]) && $type == 'register') {
  190. throw new ApiException(410028);
  191. }
  192. $code = rand(100000, 999999);
  193. $data['code'] = $code;
  194. $data['time'] = $time;
  195. $res = $services->send(true, $phone, $data, 'verify_code');
  196. if ($res !== true)
  197. throw new ApiException(410031);
  198. return $code;
  199. }
  200. /**
  201. * H5用户注册
  202. * @param $account
  203. * @param $password
  204. * @param $spread
  205. * @param string $user_type
  206. * @return mixed
  207. * @throws \think\db\exception\DataNotFoundException
  208. * @throws \think\db\exception\DbException
  209. * @throws \think\db\exception\ModelNotFoundException
  210. */
  211. public function register($account, $password, $spread, $user_type = 'h5')
  212. {
  213. if ($this->dao->getOne(['account|phone' => $account, 'is_del' => 0])) {
  214. throw new ApiException(410028);
  215. }
  216. /** @var UserServices $userServices */
  217. $userServices = app()->make(UserServices::class);
  218. $phone = $account;
  219. $data['account'] = $account;
  220. $data['pwd'] = md5((string)$password);
  221. $data['phone'] = $phone;
  222. if ($spread) {
  223. $data['spread_uid'] = $spread;
  224. $data['spread_time'] = time();
  225. $spreadInfo = $userServices->get($spread);
  226. $data['division_id'] = $spreadInfo['division_id'];
  227. $data['agent_id'] = $spreadInfo['agent_id'];
  228. $data['staff_id'] = $spreadInfo['staff_id'];
  229. }
  230. $data['real_name'] = '';
  231. $data['birthday'] = 0;
  232. $data['card_id'] = '';
  233. $data['mark'] = '';
  234. $data['addres'] = '';
  235. $data['user_type'] = $user_type;
  236. $data['add_time'] = time();
  237. $data['add_ip'] = app('request')->ip();
  238. $data['last_time'] = time();
  239. $data['last_ip'] = app('request')->ip();
  240. $data['nickname'] = substr_replace($account, '****', 3, 4);
  241. $data['avatar'] = sys_config('h5_avatar');
  242. $data['city'] = '';
  243. $data['language'] = '';
  244. $data['province'] = '';
  245. $data['country'] = '';
  246. $data['status'] = 1;
  247. if (!$re = $this->dao->save($data)) {
  248. throw new ApiException(410014);
  249. } else {
  250. $userServices->rewardNewUser((int)$re->uid);
  251. //用户生成后置事件
  252. event('UserRegisterListener', [$spread, $user_type, $data['nickname'], $re->uid, 1]);
  253. //自定义事件-用户注册
  254. event('CustomEventListener', ['user_register', [
  255. 'uid' => $re->uid,
  256. 'nickname' => $data['nickname'],
  257. 'phone' => $data['phone'],
  258. 'add_time' => date('Y-m-d H:i:s'),
  259. 'user_type' => $user_type,
  260. ]]);
  261. if ($spread) {
  262. //推送消息
  263. event('NoticeListener', [['spreadUid' => $spread, 'user_type' => $user_type, 'nickname' => $data['nickname']], 'bind_spread_uid']);
  264. //自定义事件-绑定关系
  265. event('CustomEventListener', ['user_spread', [
  266. 'uid' => $re->uid,
  267. 'nickname' => $data['nickname'],
  268. 'spread_uid' => $spread,
  269. 'spread_time' => date('Y-m-d H:i:s'),
  270. 'user_type' => $user_type,
  271. ]]);
  272. }
  273. return $re;
  274. }
  275. }
  276. /**
  277. * 重置密码
  278. * @param $account
  279. * @param $password
  280. * @return bool
  281. * @throws \think\db\exception\DataNotFoundException
  282. * @throws \think\db\exception\DbException
  283. * @throws \think\db\exception\ModelNotFoundException
  284. */
  285. public function reset($account, $password)
  286. {
  287. $user = $this->dao->getOne(['account|phone' => $account, 'is_del' => 0], 'uid');
  288. if (!$user) {
  289. throw new ApiException(410032);
  290. }
  291. if (!$this->dao->update($user['uid'], ['pwd' => md5((string)$password)], 'uid')) {
  292. throw new ApiException(410033);
  293. }
  294. return true;
  295. }
  296. /**
  297. * 手机号登录
  298. * @param $phone
  299. * @param $spread
  300. * @param string $user_type
  301. * @return array
  302. * @throws \think\db\exception\DataNotFoundException
  303. * @throws \think\db\exception\DbException
  304. * @throws \think\db\exception\ModelNotFoundException
  305. */
  306. public function mobile($phone, $spread, string $user_type = 'h5', $agent_id = 0)
  307. {
  308. //数据库查询
  309. $user = $this->dao->getOne(['account|phone' => $phone, 'is_del' => 0]);
  310. if (!$user) {
  311. $user = $this->register($phone, '123456', $spread, $user_type);
  312. if (!$user) {
  313. throw new ApiException(410034);
  314. }
  315. }
  316. if (!$user->status)
  317. throw new ApiException(410027);
  318. // 设置推广关系
  319. if ($agent_id) {
  320. $this->updateUserInfo(['code' => $agent_id, 'is_staff' => 1], $user);
  321. } else {
  322. $this->updateUserInfo(['code' => $spread], $user);
  323. }
  324. $token = $this->createToken((int)$user['uid'], 'api');
  325. if ($token) {
  326. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  327. } else {
  328. throw new ApiException(410019);
  329. }
  330. }
  331. /**
  332. * 切换登录
  333. * @param $user
  334. * @param $from
  335. * @return array
  336. * @throws \think\db\exception\DataNotFoundException
  337. * @throws \think\db\exception\DbException
  338. * @throws \think\db\exception\ModelNotFoundException
  339. */
  340. public function switchAccount($user, $from)
  341. {
  342. if ($from === 'h5') {
  343. $where = [['phone', '=', $user['phone']], ['user_type', '<>', 'h5'], ['is_del', '=', 0]];
  344. $login_type = 'wechat';
  345. } else {
  346. //数据库查询
  347. $where = [['account|phone', '=', $user['phone']], ['user_type', '=', 'h5'], ['is_del', '=', 0]];
  348. $login_type = 'h5';
  349. }
  350. $switch_user = $this->dao->getOne($where);
  351. if (!$switch_user) {
  352. return app('json')->fail(410035);
  353. }
  354. if (!$switch_user->status) {
  355. return app('json')->fail(410027);
  356. }
  357. $edit_data = ['login_type' => $login_type];
  358. if (!$this->dao->update($switch_user['uid'], $edit_data, 'uid')) {
  359. throw new ApiException(410036);
  360. }
  361. $token = $this->createToken((int)$switch_user['uid'], 'api');
  362. if ($token) {
  363. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  364. } else {
  365. throw new ApiException(410019);
  366. }
  367. }
  368. /**
  369. * 绑定手机号(静默还没写入用户信息)
  370. * @param $phone
  371. * @param string $key
  372. * @return array
  373. * @throws \Psr\SimpleCache\InvalidArgumentException
  374. * @throws \think\db\exception\DataNotFoundException
  375. * @throws \think\db\exception\ModelNotFoundException
  376. */
  377. public function bindind_phone($phone, string $key = '')
  378. {
  379. if (!$key) {
  380. throw new ApiException(410037);
  381. }
  382. [$openid, $wechatInfo, $spreadId, $agent_id, $login_type, $userType] = $createData = CacheService::get($key);
  383. if (!$createData) {
  384. throw new ApiException(410037);
  385. }
  386. $wechatInfo['phone'] = $phone;
  387. /** @var WechatUserServices $wechatUser */
  388. $wechatUser = app()->make(WechatUserServices::class);
  389. //更新用户信息
  390. $user = $wechatUser->wechatOauthAfter([$openid, $wechatInfo, $spreadId, $agent_id, $login_type, $userType]);
  391. $token = $this->createToken((int)$user['uid'], 'api');
  392. if ($token) {
  393. return [
  394. 'token' => $token['token'],
  395. 'userInfo' => $user,
  396. 'expires_time' => $token['params']['exp'],
  397. ];
  398. } else
  399. return app('json')->fail(410019);
  400. }
  401. /**
  402. * 用户绑定手机号
  403. * @param int $uid
  404. * @param $phone
  405. * @param $step
  406. * @return array
  407. * @throws \think\db\exception\DataNotFoundException
  408. * @throws \think\db\exception\DbException
  409. * @throws \think\db\exception\ModelNotFoundException
  410. */
  411. public function userBindindPhone(int $uid, $phone, $step)
  412. {
  413. $userInfo = $this->dao->get($uid);
  414. if (!$userInfo) {
  415. throw new ApiException(410113);
  416. }
  417. if ($this->dao->getOne([['phone', '=', $phone], ['user_type', '<>', 'h5'], ['is_del', '=', 0]])) {
  418. throw new ApiException(410039);
  419. }
  420. if ($userInfo->phone) {
  421. throw new ApiException(410040);
  422. }
  423. $data = [];
  424. if ($this->dao->getOne(['account' => $phone, 'phone' => $phone, 'user_type' => 'h5', 'is_del' => 0])) {
  425. if (!$step) return ['msg' => 410041, 'data' => ['is_bind' => 1]];
  426. } else {
  427. $data['account'] = $phone;
  428. }
  429. $data['phone'] = $phone;
  430. if ($this->dao->update($userInfo['uid'], $data, 'uid') || $userInfo->phone == $phone)
  431. return ['msg' => 410016, 'data' => []];
  432. else
  433. throw new ApiException(410017);
  434. }
  435. /**
  436. * 用户绑定手机号
  437. * @param int $uid
  438. * @param $phone
  439. * @return array
  440. * @throws \think\db\exception\DataNotFoundException
  441. * @throws \think\db\exception\DbException
  442. * @throws \think\db\exception\ModelNotFoundException
  443. */
  444. public function updateBindindPhone(int $uid, $phone)
  445. {
  446. $userInfo = $this->dao->get(['uid' => $uid, 'is_del' => 0]);
  447. if (!$userInfo) {
  448. throw new ApiException(410113);
  449. }
  450. if ($userInfo->phone == $phone) {
  451. throw new ApiException(410042);
  452. }
  453. if ($this->dao->getOne([['phone', '=', $phone], ['is_del', '=', 0]])) {
  454. throw new ApiException(410043);
  455. }
  456. $data = [];
  457. $data['phone'] = $phone;
  458. $data['account'] = $phone;
  459. if ($this->dao->update($userInfo['uid'], $data, 'uid'))
  460. return ['msg' => 100001, 'data' => []];
  461. else
  462. throw new ApiException(100007);
  463. }
  464. /**
  465. * 远程注册登录
  466. * @param string $out_token
  467. * @return array
  468. * @throws \Psr\SimpleCache\InvalidArgumentException
  469. * @throws \think\db\exception\DataNotFoundException
  470. * @throws \think\db\exception\DbException
  471. * @throws \think\db\exception\ModelNotFoundException
  472. * @author wuhaotian
  473. * @email 442384644@qq.com
  474. * @date 2024/5/21
  475. */
  476. public function remoteRegister(string $out_token = '')
  477. {
  478. $info = JWT::jsonDecode(JWT::urlsafeB64Decode($out_token));
  479. $userInfo = $this->dao->get(['uid' => $info->uid]);
  480. $data = [];
  481. if (!$userInfo) {
  482. $data['uid'] = $info->uid;
  483. $data['account'] = $info->phone != '' ? $info->phone : 'out_' . $info->uid;
  484. $data['phone'] = $info->phone;
  485. $data['pwd'] = md5('123456');
  486. $data['real_name'] = $info->nickname;
  487. $data['birthday'] = 0;
  488. $data['card_id'] = '';
  489. $data['mark'] = '';
  490. $data['addres'] = '';
  491. $data['user_type'] = 'h5';
  492. $data['add_time'] = time();
  493. $data['add_ip'] = app('request')->ip();
  494. $data['last_time'] = time();
  495. $data['last_ip'] = app('request')->ip();
  496. $data['nickname'] = $info->nickname;
  497. $data['avatar'] = $info->avatar;
  498. $data['city'] = '';
  499. $data['language'] = '';
  500. $data['province'] = '';
  501. $data['country'] = '';
  502. $data['status'] = 1;
  503. $data['now_money'] = $info->now_money;
  504. $data['integral'] = $info->integral;
  505. $data['exp'] = $info->exp;
  506. $this->dao->save($data);
  507. } else {
  508. $data['nickname'] = $info->nickname;
  509. $data['avatar'] = $info->avatar;
  510. $data['now_money'] = $info->now_money;
  511. $data['integral'] = $info->integral;
  512. $data['exp'] = $info->exp;
  513. $this->dao->update($info->uid, $data);
  514. }
  515. $token = $this->createToken((int)$info->uid, 'api');
  516. if ($token) {
  517. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  518. } else {
  519. throw new ApiException('登录失败');
  520. }
  521. }
  522. }