LoginServices.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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 think\facade\Config;
  21. /**
  22. *
  23. * Class LoginServices
  24. * @package app\services\user
  25. */
  26. class LoginServices extends BaseServices
  27. {
  28. /**
  29. * LoginServices constructor.
  30. * @param UserDao $dao
  31. */
  32. public function __construct(UserDao $dao)
  33. {
  34. $this->dao = $dao;
  35. }
  36. /**
  37. * H5账号登陆
  38. * @param $account
  39. * @param $password
  40. * @param $spread
  41. * @return array
  42. * @throws \think\db\exception\DataNotFoundException
  43. * @throws \think\db\exception\DbException
  44. * @throws \think\db\exception\ModelNotFoundException
  45. */
  46. public function login($account, $password, $spread)
  47. {
  48. $user = $this->dao->getOne(['account|phone' => $account, 'is_del' => 0]);
  49. if ($user) {
  50. if ($user->pwd !== md5((string)$password))
  51. throw new ApiException(410025);
  52. if ($user->pwd === md5('123456'))
  53. throw new ApiException(410026);
  54. } else {
  55. throw new ApiException(410025);
  56. }
  57. if (!$user['status'])
  58. throw new ApiException(410027);
  59. //更新用户信息
  60. $this->updateUserInfo(['code' => $spread], $user);
  61. $token = $this->createToken((int)$user['uid'], 'api');
  62. if ($token) {
  63. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  64. } else
  65. throw new ApiException(410019);
  66. }
  67. /**
  68. * 更新用户信息
  69. * @param $user
  70. * @param $userInfo
  71. * @param false $is_new
  72. * @return bool
  73. * @throws \think\db\exception\DataNotFoundException
  74. * @throws \think\db\exception\DbException
  75. * @throws \think\db\exception\ModelNotFoundException
  76. */
  77. public function updateUserInfo($user, $userInfo, $is_new = false)
  78. {
  79. $data = [];
  80. $data['phone'] = !isset($user['phone']) || !$user['phone'] ? $userInfo->phone : $user['phone'];
  81. $data['last_time'] = time();
  82. $data['last_ip'] = app()->request->ip();
  83. $spreadUid = $user['code'] ?? 0;
  84. //如果扫了员工邀请码,上级,代理商,区域代理都会改动。
  85. if (isset($user['is_staff']) && !$userInfo['is_agent'] && !$userInfo['is_division']) {
  86. $spreadInfo = $this->dao->get($spreadUid);
  87. if ($userInfo['uid'] != $spreadUid) {
  88. $data['spread_uid'] = $spreadUid;
  89. $data['spread_time'] = $userInfo->last_time;
  90. }
  91. $data['agent_id'] = $spreadInfo->agent_id;
  92. $data['division_id'] = $spreadInfo->division_id;
  93. $data['staff_id'] = $userInfo['uid'];
  94. $data['is_staff'] = $user['is_staff'] ?? 0;
  95. $data['division_type'] = 3;
  96. $data['division_change_time'] = time();
  97. $data['division_end_time'] = $spreadInfo->division_end_time;
  98. //如果店员切换代理商,则店员在之前代理商下推广的用户,他们的直接上级从当前店员变为之前代理商
  99. if ($userInfo->agent_id != 0 && $userInfo->agent_id != $spreadInfo->agent_id) {
  100. $this->dao->update($userInfo['uid'], ['spread_uid' => $userInfo->agent_id], 'spread_uid');
  101. }
  102. }
  103. if ($is_new) {
  104. if ($spreadUid) {
  105. $spreadInfo = $this->dao->get($spreadUid);
  106. $spreadUid = (int)$spreadUid;
  107. $data['spread_uid'] = $spreadUid;
  108. $data['spread_time'] = time();
  109. $data['agent_id'] = $spreadInfo->agent_id;
  110. $data['division_id'] = $spreadInfo->division_id;
  111. $data['staff_id'] = $spreadInfo->staff_id;
  112. //绑定用户后置事件
  113. event('UserRegisterListener', [$spreadUid, $userInfo['user_type'], $userInfo['nickname'], $userInfo['uid'], 0]);
  114. //推送消息
  115. event('NoticeListener', [['spreadUid' => $spreadUid, 'user_type' => $userInfo['user_type'], 'nickname' => $userInfo['nickname']], 'bind_spread_uid']);
  116. }
  117. } else {
  118. //永久绑定
  119. $store_brokerage_binding_status = sys_config('store_brokerage_binding_status', 1);
  120. if ($userInfo->spread_uid && $store_brokerage_binding_status == 1 && !isset($user['is_staff'])) {
  121. $data['login_type'] = $user['login_type'] ?? $userInfo->login_type;
  122. } else {
  123. //绑定分销关系 = 所有用户
  124. if (sys_config('brokerage_bindind', 1) == 1) {
  125. //分销绑定类型为时间段且过期 ||临时
  126. $store_brokerage_binding_time = sys_config('store_brokerage_binding_time', 30);
  127. if (!$userInfo['spread_uid'] || $store_brokerage_binding_status == 3 || ($store_brokerage_binding_status == 2 && ($userInfo['spread_time'] + $store_brokerage_binding_time * 24 * 3600) < time())) {
  128. if ($spreadUid && $user['code'] != $userInfo->uid && $userInfo->uid != $this->dao->value(['uid' => $spreadUid], 'spread_uid')) {
  129. $spreadInfo = $this->dao->get($spreadUid);
  130. $spreadUid = (int)$spreadUid;
  131. $data['spread_uid'] = $spreadUid;
  132. $data['spread_time'] = time();
  133. $data['agent_id'] = $spreadInfo->agent_id;
  134. $data['division_id'] = $spreadInfo->division_id;
  135. $data['staff_id'] = $spreadInfo->staff_id;
  136. //绑定用户后置事件
  137. event('UserRegisterListener', [$spreadUid, $userInfo['user_type'], $userInfo['nickname'], $userInfo['uid'], 0]);
  138. //推送消息
  139. event('NoticeListener', [['spreadUid' => $spreadUid, 'user_type' => $userInfo['user_type'], 'nickname' => $userInfo['nickname']], 'bind_spread_uid']);
  140. }
  141. }
  142. }
  143. }
  144. }
  145. if (!$this->dao->update($userInfo['uid'], $data, 'uid')) {
  146. throw new ApiException(100007);
  147. }
  148. return true;
  149. }
  150. public function verify(SmsService $services, $phone, $type, $time, $ip)
  151. {
  152. // if ($this->dao->getOne(['account' => $phone, 'is_del' => 0]) && $type == 'register') {
  153. // throw new ApiException(410028);
  154. // }
  155. if ($this->dao->getOne(['phone' => $phone, 'is_del' => 0]) && $type == 'register') {
  156. throw new ApiException('邮箱已注册');
  157. }
  158. $default = Config::get('sms.default', 'yihaotong');
  159. $defaultMaxPhoneCount = Config::get('sms.maxPhoneCount', 10);
  160. $defaultMaxIpCount = Config::get('sms.maxIpCount', 50);
  161. $maxPhoneCount = Config::get('sms.stores.' . $default . '.maxPhoneCount', $defaultMaxPhoneCount);
  162. $maxIpCount = Config::get('sms.stores.' . $default . '.maxIpCount', $defaultMaxIpCount);
  163. /** @var SmsRecordServices $smsRecord */
  164. $smsRecord = app()->make(SmsRecordServices::class);
  165. if ($smsRecord->count(['phone' => $phone, 'add_ip' => $ip, 'time' => 'today']) >= $maxPhoneCount) {
  166. throw new ApiException(410029);
  167. }
  168. if ($smsRecord->count(['add_ip' => $ip, 'time' => 'today']) >= $maxIpCount) {
  169. throw new ApiException(410030);
  170. }
  171. $code = rand(100000, 999999);
  172. $data['code'] = $code;
  173. $data['time'] = $time;
  174. $res = $services->send(true, $phone, $data, 'verify_code');
  175. if ($res !== true)
  176. throw new ApiException(410031);
  177. return $code;
  178. }
  179. /**
  180. * H5用户注册
  181. * @param $account
  182. * @param $password
  183. * @param $spread
  184. * @param string $user_type
  185. * @param $account1
  186. * @return mixed
  187. * @throws \think\db\exception\DataNotFoundException
  188. * @throws \think\db\exception\DbException
  189. * @throws \think\db\exception\ModelNotFoundException
  190. */
  191. public function register($account, $password, $spread, $user_type = 'h5',$account1 = '')
  192. {
  193. if ($this->dao->getOne(['account|phone' => $account, 'is_del' => 0])) {
  194. throw new ApiException(410028);
  195. }
  196. /** @var UserServices $userServices */
  197. $userServices = app()->make(UserServices::class);
  198. $phone = $account;
  199. $data['account'] = $account1 ? $account1 : $account;
  200. $data['pwd'] = md5((string)$password);
  201. $data['phone'] = $phone;
  202. if ($spread) {
  203. $data['spread_uid'] = $spread;
  204. $data['spread_time'] = time();
  205. $spreadInfo = $userServices->get($spread);
  206. $data['division_id'] = $spreadInfo['division_id'];
  207. $data['agent_id'] = $spreadInfo['agent_id'];
  208. $data['staff_id'] = $spreadInfo['staff_id'];
  209. }
  210. $data['real_name'] = '';
  211. $data['birthday'] = 0;
  212. $data['card_id'] = '';
  213. $data['mark'] = '';
  214. $data['addres'] = '';
  215. $data['user_type'] = $user_type;
  216. $data['add_time'] = time();
  217. $data['add_ip'] = app('request')->ip();
  218. $data['last_time'] = time();
  219. $data['last_ip'] = app('request')->ip();
  220. $data['nickname'] = substr_replace($account, '****', 3, 4);
  221. $data['nickname'] = $account1;
  222. $data['avatar'] = sys_config('h5_avatar');
  223. $data['city'] = '';
  224. $data['language'] = '';
  225. $data['province'] = '';
  226. $data['country'] = '';
  227. $data['status'] = 1;
  228. if (!$re = $this->dao->save($data)) {
  229. throw new ApiException(410014);
  230. } else {
  231. $userServices->rewardNewUser((int)$re->uid);
  232. //用户生成后置事件
  233. event('UserRegisterListener', [$spread, $user_type, $data['nickname'], $re->uid, 1]);
  234. //推送消息
  235. event('NoticeListener', [['spreadUid' => $spread, 'user_type' => $user_type, 'nickname' => $data['nickname']], 'bind_spread_uid']);
  236. return $re;
  237. }
  238. }
  239. /**
  240. * 重置密码
  241. * @param $account
  242. * @param $password
  243. * @return bool
  244. * @throws \think\db\exception\DataNotFoundException
  245. * @throws \think\db\exception\DbException
  246. * @throws \think\db\exception\ModelNotFoundException
  247. */
  248. public function reset($account, $password)
  249. {
  250. $user = $this->dao->getOne(['account|phone' => $account, 'is_del' => 0], 'uid');
  251. if (!$user) {
  252. throw new ApiException(410032);
  253. }
  254. if (!$this->dao->update($user['uid'], ['pwd' => md5((string)$password)], 'uid')) {
  255. throw new ApiException(410033);
  256. }
  257. return true;
  258. }
  259. /**
  260. * 手机号登录
  261. * @param $phone
  262. * @param $spread
  263. * @param string $user_type
  264. * @param $account
  265. * @param $password
  266. * @return array
  267. * @throws \think\db\exception\DataNotFoundException
  268. * @throws \think\db\exception\DbException
  269. * @throws \think\db\exception\ModelNotFoundException
  270. */
  271. public function mobile($phone, $spread, string $user_type = 'h5',$account,$password)
  272. {
  273. // 判断账号是否存在
  274. $is_account = $this->dao->value(['account' => $account, 'is_del' => 0],'account');
  275. if($is_account){
  276. throw new ApiException('账号已注册');
  277. }
  278. //数据库查询
  279. $user = $this->dao->getOne(['account|phone' => $phone, 'is_del' => 0]);
  280. if ($user) {
  281. throw new ApiException('邮箱已注册');
  282. }
  283. if (!$user) {
  284. $user = $this->register($phone, $password, $spread, $user_type,$account);
  285. if (!$user) {
  286. throw new ApiException(410034);
  287. }
  288. }
  289. if (!$user->status)
  290. throw new ApiException(410027);
  291. // 设置推广关系
  292. $this->updateUserInfo(['code' => $spread], $user);
  293. $token = $this->createToken((int)$user['uid'], 'api');
  294. if ($token) {
  295. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  296. } else {
  297. throw new ApiException(410019);
  298. }
  299. }
  300. /**
  301. * 切换登录
  302. * @param $user
  303. * @param $from
  304. * @return array
  305. * @throws \think\db\exception\DataNotFoundException
  306. * @throws \think\db\exception\DbException
  307. * @throws \think\db\exception\ModelNotFoundException
  308. */
  309. public function switchAccount($user, $from)
  310. {
  311. if ($from === 'h5') {
  312. $where = [['phone', '=', $user['phone']], ['user_type', '<>', 'h5'], ['is_del', '=', 0]];
  313. $login_type = 'wechat';
  314. } else {
  315. //数据库查询
  316. $where = [['account|phone', '=', $user['phone']], ['user_type', '=', 'h5'], ['is_del', '=', 0]];
  317. $login_type = 'h5';
  318. }
  319. $switch_user = $this->dao->getOne($where);
  320. if (!$switch_user) {
  321. return app('json')->fail(410035);
  322. }
  323. if (!$switch_user->status) {
  324. return app('json')->fail(410027);
  325. }
  326. $edit_data = ['login_type' => $login_type];
  327. if (!$this->dao->update($switch_user['uid'], $edit_data, 'uid')) {
  328. throw new ApiException(410036);
  329. }
  330. $token = $this->createToken((int)$switch_user['uid'], 'api');
  331. if ($token) {
  332. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  333. } else {
  334. throw new ApiException(410019);
  335. }
  336. }
  337. /**
  338. * 绑定手机号(静默还没写入用户信息)
  339. * @param $phone
  340. * @param string $key
  341. * @return array
  342. * @throws \Psr\SimpleCache\InvalidArgumentException
  343. * @throws \think\db\exception\DataNotFoundException
  344. * @throws \think\db\exception\ModelNotFoundException
  345. */
  346. public function bindind_phone($phone, string $key = '')
  347. {
  348. if (!$key) {
  349. throw new ApiException(410037);
  350. }
  351. [$openid, $wechatInfo, $spreadId, $login_type, $userType] = $createData = CacheService::get($key);
  352. if (!$createData) {
  353. throw new ApiException(410037);
  354. }
  355. $wechatInfo['phone'] = $phone;
  356. /** @var WechatUserServices $wechatUser */
  357. $wechatUser = app()->make(WechatUserServices::class);
  358. //更新用户信息
  359. $user = $wechatUser->wechatOauthAfter([$openid, $wechatInfo, $spreadId, $login_type, $userType]);
  360. $token = $this->createToken((int)$user['uid'], $userType);
  361. if ($token) {
  362. return [
  363. 'token' => $token['token'],
  364. 'userInfo' => $user,
  365. 'expires_time' => $token['params']['exp'],
  366. ];
  367. } else
  368. return app('json')->fail(410019);
  369. }
  370. /**
  371. * 用户绑定手机号
  372. * @param int $uid
  373. * @param $phone
  374. * @param $step
  375. * @return array
  376. * @throws \think\db\exception\DataNotFoundException
  377. * @throws \think\db\exception\DbException
  378. * @throws \think\db\exception\ModelNotFoundException
  379. */
  380. public function userBindindPhone(int $uid, $phone, $step)
  381. {
  382. $userInfo = $this->dao->get($uid);
  383. if (!$userInfo) {
  384. throw new ApiException(410113);
  385. }
  386. if ($this->dao->getOne([['phone', '=', $phone], ['user_type', '<>', 'h5'], ['is_del', '=', 0]])) {
  387. throw new ApiException(410039);
  388. }
  389. if ($userInfo->phone) {
  390. throw new ApiException(410040);
  391. }
  392. $data = [];
  393. if ($this->dao->getOne(['account' => $phone, 'phone' => $phone, 'user_type' => 'h5', 'is_del' => 0])) {
  394. if (!$step) return ['msg' => 410041, 'data' => ['is_bind' => 1]];
  395. } else {
  396. $data['account'] = $phone;
  397. }
  398. $data['phone'] = $phone;
  399. if ($this->dao->update($userInfo['uid'], $data, 'uid') || $userInfo->phone == $phone)
  400. return ['msg' => 410016, 'data' => []];
  401. else
  402. throw new ApiException(410017);
  403. }
  404. /**
  405. * 用户绑定手机号
  406. * @param int $uid
  407. * @param $phone
  408. * @return array
  409. * @throws \think\db\exception\DataNotFoundException
  410. * @throws \think\db\exception\DbException
  411. * @throws \think\db\exception\ModelNotFoundException
  412. */
  413. public function updateBindindPhone(int $uid, $phone)
  414. {
  415. $userInfo = $this->dao->get(['uid' => $uid, 'is_del' => 0]);
  416. if (!$userInfo) {
  417. throw new ApiException(410113);
  418. }
  419. if ($userInfo->phone == $phone) {
  420. throw new ApiException(410042);
  421. }
  422. if ($this->dao->getOne([['phone', '=', $phone], ['is_del', '=', 0]])) {
  423. throw new ApiException(410043);
  424. }
  425. $data = [];
  426. $data['phone'] = $phone;
  427. $data['account'] = $phone;
  428. if ($this->dao->update($userInfo['uid'], $data, 'uid'))
  429. return ['msg' => 100001, 'data' => []];
  430. else
  431. throw new ApiException(100007);
  432. }
  433. }