UserLogic.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | likeshop100%开源免费商用商城系统
  4. // +----------------------------------------------------------------------
  5. // | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
  6. // | 开源版本可自由商用,可去除界面版权logo
  7. // | 商业版本务必购买商业授权,以免引起法律纠纷
  8. // | 禁止对系统程序代码以任何目的,任何形式的再发布
  9. // | gitee下载:https://gitee.com/likeshop_gitee
  10. // | github下载:https://github.com/likeshop-github
  11. // | 访问官网:https://www.likeshop.cn
  12. // | 访问社区:https://home.likeshop.cn
  13. // | 访问手册:http://doc.likeshop.cn
  14. // | 微信公众号:likeshop技术社区
  15. // | likeshop团队 版权所有 拥有最终解释权
  16. // +----------------------------------------------------------------------
  17. // | author: likeshopTeam
  18. // +----------------------------------------------------------------------
  19. namespace app\shopapi\logic;
  20. use EasyWeChat\Factory;
  21. use app\common\{enum\DistributionConfigEnum,
  22. enum\UserTerminalEnum,
  23. enum\YesNoEnum,
  24. model\DistributionConfig,
  25. model\GoodsCollect,
  26. model\User,
  27. model\Order,
  28. enum\PayEnum,
  29. enum\OrderEnum,
  30. enum\CouponEnum,
  31. model\UserAuth,
  32. model\UserLevel,
  33. logic\BaseLogic,
  34. model\AfterSale,
  35. model\CouponList,
  36. enum\AfterSaleEnum,
  37. model\UserTransfer,
  38. service\FileService,
  39. enum\AccountLogEnum,
  40. service\ConfigService,
  41. logic\AccountLogLogic,
  42. service\sms\SmsDriver,
  43. service\WeChatConfigService,
  44. service\WeChatService};
  45. use think\Exception;
  46. use think\facade\Config;
  47. use think\facade\Db;
  48. /**
  49. * 会员逻辑层
  50. * Class UserLogic
  51. * @package app\shopapi\logic
  52. */
  53. class UserLogic extends BaseLogic
  54. {
  55. /**
  56. * @notes 个人中心
  57. * @param int $userId
  58. * @return array
  59. * @throws \think\db\exception\DataNotFoundException
  60. * @throws \think\db\exception\DbException
  61. * @throws \think\db\exception\ModelNotFoundException
  62. * @author cjhao
  63. * @date 2021/8/6 19:16
  64. */
  65. public function centre(array $userInfo): array
  66. {
  67. $user = User::with('user_level')->field('id,sn,sex,nickname,avatar,user_money,user_integral,mobile,level,create_time,code,is_new_user,is_register_award')
  68. ->find($userInfo['user_id']);
  69. $user->level_rank = $user->rank ?? '';
  70. $user->level_name = $user->name ?? '';
  71. //待支付
  72. $user->wait_pay = Order::where(['user_id' => $userInfo['user_id'], 'order_status' => OrderEnum::STATUS_WAIT_PAY, 'pay_status' => PayEnum::UNPAID])->count();
  73. //待发货
  74. $user->wait_delivery = Order::where(['user_id' => $userInfo['user_id'], 'order_status' => OrderEnum::STATUS_WAIT_DELIVERY, 'pay_status' => PayEnum::ISPAID])->count();
  75. //待收货
  76. $user->wait_take = Order::where(['user_id' => $userInfo['user_id'], 'order_status' => OrderEnum::STATUS_WAIT_RECEIVE, 'pay_status' => PayEnum::ISPAID])->count();
  77. //待评论
  78. $user->wait_comment = Order::alias('O')
  79. ->join('order_goods OG', 'OG.order_id = O.id')
  80. ->where(['user_id' => $userInfo['user_id'], 'is_comment' => YesNoEnum::NO, 'order_status' => OrderEnum::STATUS_FINISH, 'pay_status' => PayEnum::ISPAID])
  81. ->count();
  82. //退款、售后
  83. $user->after_sale = AfterSale::where(['user_id' => $userInfo['user_id'], 'status' => AfterSaleEnum::STATUS_ING])->count();
  84. //优惠券
  85. $user->coupon = CouponList::where([
  86. ['user_id', '=', $userInfo['user_id']],
  87. ['status', '=', CouponEnum::USE_STATUS_NOT],
  88. ['invalid_time', '>=', time()]
  89. ])->count();
  90. //收藏数量
  91. $user->collect = GoodsCollect::where(['user_id' => $userInfo['user_id']])->count();
  92. // 自定义邀请海报
  93. $dbConfig = DistributionConfig::column('value', 'key');
  94. $dbConfig['apply_image'] = $dbConfig['apply_image'] ?? DistributionConfigEnum::DEFAULT_APPLY_IMAGE;
  95. $dbConfig['poster'] = $dbConfig['poster'] ?? DistributionConfigEnum::DEFAULT_POSTER;
  96. $dbConfig['apply_image'] = FileService::getFileUrl($dbConfig['apply_image']);
  97. $dbConfig['poster'] = FileService::getFileUrl($dbConfig['poster']);
  98. $user->poster = $dbConfig['poster'];
  99. $user->apply_image = $dbConfig['apply_image'];
  100. //是否有微信授权登录
  101. if (in_array($userInfo['terminal'], [UserTerminalEnum::WECHAT_MMP, UserTerminalEnum::WECHAT_OA])) {
  102. $auth = UserAuth::where(['user_id' => $userInfo['user_id'], 'terminal' => $userInfo['terminal']])->find();
  103. $user->is_auth = $auth ? 1 : 0;
  104. }
  105. $user->hidden(['name', 'rank']);
  106. return $user->toArray();
  107. }
  108. /**
  109. * @notes 设置用户信息
  110. * @param int $userId
  111. * @param array $params
  112. * @return bool
  113. * @author cjhao
  114. * @date 2021/8/6 19:44
  115. */
  116. public static function setInfo(int $userId, array $params): bool
  117. {
  118. User::update(['id' => $userId, $params['field'] => $params['value']]);
  119. return true;
  120. }
  121. /**
  122. * @notes 绑定手机号
  123. * @param $params
  124. * @return bool
  125. * @author Tab
  126. * @date 2021/8/25 17:55
  127. */
  128. public static function bindMobile($params)
  129. {
  130. try {
  131. $smsDriver = new SmsDriver();
  132. $result = $smsDriver->verify($params['mobile'], $params['code']);
  133. if (!$result) {
  134. throw new \Exception('验证码错误');
  135. }
  136. $user = User::where('mobile', $params['mobile'])->findOrEmpty();
  137. if (!$user->isEmpty()) {
  138. throw new \Exception('该手机号已被其他账号绑定');
  139. }
  140. unset($params['code']);
  141. User::update($params);
  142. return true;
  143. } catch (\Exception $e) {
  144. self::setError($e->getMessage());
  145. return false;
  146. }
  147. }
  148. /**
  149. * @notes 会员中心
  150. * @param int $userId
  151. * @return array
  152. * @throws \think\db\exception\DataNotFoundException
  153. * @throws \think\db\exception\DbException
  154. * @throws \think\db\exception\ModelNotFoundException
  155. * @author cjhao
  156. * @date 2021/8/9 11:03
  157. */
  158. public function userLevel(int $userId): array
  159. {
  160. $user = User::field('id,nickname,avatar,level')->find($userId);
  161. $levelList = UserLevel::order(['rank' => 'asc'])->withoutField('remark,create_time,update_time,delete_time')->select();
  162. $levelName = '';
  163. foreach ($levelList as $levelKey => $level) {
  164. if ($level->discount > 0) {
  165. $level->discount = '会员折扣:' . floatval($level->discount) . '折';
  166. }
  167. //下个等级
  168. $level->next_level = $levelList[$levelKey + 1]->name ?? '';
  169. $level->status = 0;
  170. if ($user->level == $level->id) {
  171. $level->status = 1;
  172. $levelName = $level->name;
  173. $user->rank = $level->rank;//更新为等级权重
  174. }
  175. //会员条件
  176. $conditionArray = [];
  177. if ($level->condition) {
  178. $condition = \app\common\logic\UserLogic::formatLevelCondition($level->condition);
  179. //没有设置条件;直接返回空数组
  180. if ('' === $condition['condition_type']) {
  181. $level->condition = $conditionArray;
  182. continue;
  183. }
  184. $level->condition_tips = '满足以下任意条件即可升级';
  185. //满足全部条件
  186. if ($condition['condition_type']) {
  187. $level->condition_tips = '满足以下全部条件即可升级';
  188. }
  189. //单笔消费满足金额
  190. if ($condition['is_single_money'] && $condition['single_money'] > 0) {
  191. $conditionArray[] = '单消费金额满' . $condition['single_money'] . '元';
  192. }
  193. //累计消费金额
  194. if ($condition['is_total_money'] && $condition['total_money'] > 0) {
  195. $conditionArray[] = '累计消费金额满' . $condition['total_money'] . '元';
  196. }
  197. //累计消费次数
  198. if ($condition['is_total_num'] && $condition['total_num'] > 0) {
  199. $conditionArray[] = '累计消费次数' . $condition['total_num'] . '次';
  200. }
  201. }
  202. $level->condition = $conditionArray;
  203. }
  204. $user->level_name = $levelName;
  205. $data = [
  206. 'user' => $user,
  207. 'level_list' => $levelList,
  208. ];
  209. return $data;
  210. }
  211. /**
  212. * @notes 余额转账
  213. * @param $params
  214. * @return false
  215. * @author Tab
  216. * @date 2021/8/12 9:15
  217. */
  218. public static function transfer($params)
  219. {
  220. Db::startTrans();
  221. try {
  222. // 扣减自身余额
  223. $me = User::findOrEmpty($params['user_id']);
  224. $me->user_money = $me->user_money - $params['money'];
  225. $me->save();
  226. // 记录账户流水
  227. AccountLogLogic::add($me->id, AccountLogEnum::BNW_DEC_TRANSFER, AccountLogEnum::DEC, $params['money'], '', '余额转账-转出');
  228. // 增加收款方余额
  229. $transferIn = User::whereOr('sn', $params['transfer_in'])
  230. ->whereOr('mobile', $params['transfer_in'])
  231. ->findOrEmpty();
  232. $transferIn->user_money = $transferIn->user_money + $params['money'];
  233. $transferIn->save();
  234. // 记录账户流水
  235. AccountLogLogic::add($transferIn->id, AccountLogEnum::BNW_INC_TRANSFER, AccountLogEnum::INC, $params['money'], '', '余额转账-转入');
  236. // 转账记录
  237. UserTransfer::create([
  238. 'transfer_out' => $me->id,
  239. 'transfer_in' => $transferIn->id,
  240. 'money' => $params['money']
  241. ]);
  242. Db::commit();
  243. return true;
  244. } catch (\Exception $e) {
  245. Db::rollback();
  246. self::setError($e->getMessage());
  247. return false;
  248. }
  249. }
  250. /**
  251. * @notes 最近转账记录(3条)
  252. * @param $userId
  253. * @return mixed
  254. * @author Tab
  255. * @date 2021/8/12 10:35
  256. */
  257. public static function transferRecent($userId)
  258. {
  259. $lists = UserTransfer::alias('ut')
  260. ->leftJoin('user u', 'u.id = ut.transfer_in')
  261. ->field('u.avatar,u.sn,u.nickname')
  262. ->distinct(true)
  263. ->where('ut.transfer_out', $userId)
  264. ->where('u.user_delete', 0)
  265. ->limit(3)
  266. ->select()
  267. ->toArray();
  268. foreach ($lists as &$item) {
  269. $item['avatar'] = FileService::getFileUrl($item['avatar']);
  270. }
  271. return $lists;
  272. }
  273. /**
  274. * @notes 收款用户信息
  275. * @param $params
  276. * @return array|false
  277. * @author Tab
  278. * @date 2021/8/12 11:03
  279. */
  280. public static function transferIn($params)
  281. {
  282. try {
  283. $user = User::field('avatar,nickname,sn,mobile,user_delete')
  284. ->where('sn|mobile', $params['transfer_in'])
  285. ->findOrEmpty();
  286. if ($user->isEmpty() || $user->user_delete) {
  287. throw new \think\Exception('收款用户不存在');
  288. }
  289. return $user->toArray();
  290. } catch (\Exception $e) {
  291. self::setError($e->getMessage());
  292. return false;
  293. }
  294. }
  295. /**
  296. * @notes 判断用户是否已设置支付密码
  297. * @param $userId
  298. * @return bool
  299. * @author Tab
  300. * @date 2021/8/17 10:31
  301. */
  302. public static function hasPayPassword($userId)
  303. {
  304. $user = User::findOrEmpty($userId);
  305. if (empty($user->pay_password)) {
  306. return ['has_pay_password' => false];
  307. }
  308. return ['has_pay_password' => true];
  309. }
  310. /**
  311. * @notes 设置/修改交易密码
  312. * @param $params
  313. * @return bool
  314. * @author Tab
  315. * @date 2021/8/12 11:32
  316. */
  317. public static function setPayPassword($params)
  318. {
  319. try {
  320. $user = User::findOrEmpty($params['user_id']);
  321. if (empty($user->pay_password)) {
  322. // 首次设置密码
  323. $user->pay_password = md5($params['pay_password']);
  324. $user->save();
  325. return true;
  326. }
  327. // 修改密码
  328. if (!isset($params['origin_pay_password']) || empty($params['origin_pay_password'])) {
  329. throw new \think\Exception('请输入原支付密码');
  330. }
  331. if ($user->pay_password != md5($params['origin_pay_password'])) {
  332. throw new \think\Exception('原支付密码错误');
  333. }
  334. // 设置新支付密码
  335. $user->pay_password = md5($params['pay_password']);
  336. $user->save();
  337. return true;
  338. } catch (\Exception $e) {
  339. self::setError($e->getMessage());
  340. return false;
  341. }
  342. }
  343. /**
  344. * @notes 重置支付密码
  345. * @param $params
  346. * @return bool
  347. * @author Tab
  348. * @date 2021/8/24 16:30
  349. */
  350. public static function resetPayPassword($params)
  351. {
  352. try {
  353. // 校验验证码
  354. $smsDriver = new SmsDriver();
  355. if (!$smsDriver->verify($params['mobile'], $params['code'])) {
  356. throw new \Exception('验证码错误');
  357. }
  358. $params['pay_password'] = md5($params['pay_password']);
  359. unset($params['code']);
  360. unset($params['mobile']);
  361. User::update($params);
  362. return true;
  363. } catch (\Exception $e) {
  364. self::setError($e->getMessage());
  365. return false;
  366. }
  367. }
  368. /**
  369. * @notes 重置登录密码
  370. * @param $params
  371. * @return bool
  372. * @author Tab
  373. * @date 2021/8/25 17:03
  374. */
  375. public static function resetPassword($params)
  376. {
  377. try {
  378. // 校验验证码
  379. $smsDriver = new SmsDriver();
  380. if (!$smsDriver->verify($params['mobile'], $params['code'])) {
  381. throw new \Exception('验证码错误');
  382. }
  383. $passwordSalt = Config::get('project.unique_identification');
  384. $password = create_password($params['password'], $passwordSalt);
  385. User::where('mobile', $params['mobile'])->update([
  386. 'password' => $password
  387. ]);
  388. return true;
  389. } catch (\Exception $e) {
  390. self::setError($e->getMessage());
  391. return false;
  392. }
  393. }
  394. /**
  395. * @notes 钱包
  396. * @param $userId
  397. * @return array
  398. * @author Tab
  399. * @date 2021/8/12 14:58
  400. */
  401. public static function wallet($userId)
  402. {
  403. $user = User::findOrEmpty($userId);
  404. $rechargeOpen = ConfigService::get('recharge', 'open');
  405. $rechargeMinAmount = ConfigService::get('recharge', 'min_amount');
  406. $userMoney = is_null($user->user_money) ? 0 : $user->user_money;
  407. $userEarnings = is_null($user->user_earnings) ? 0 : $user->user_earnings;
  408. $totalOrderAmount = is_null($user->total_order_amount) ? 0 : $user->total_order_amount;
  409. return [
  410. 'user_money' => $userMoney,
  411. 'user_earnings' => $userEarnings,
  412. 'total_amount' => round($userMoney + $userEarnings, 2),
  413. 'recharge_open' => $rechargeOpen,
  414. 'recharge_min_amount' => $rechargeMinAmount,
  415. 'total_order_amount' => $totalOrderAmount,
  416. ];
  417. }
  418. /**
  419. * @notes 用户信息
  420. * @param $userId
  421. * @return array
  422. * @author Tab
  423. * @date 2021/8/25 17:22
  424. */
  425. public static function info($userId)
  426. {
  427. $user = User::field('sn,avatar,nickname,sex,mobile,create_time')->findOrEmpty($userId)->toArray();
  428. $user['has_password'] = empty($user['password']) ? '未设置' : '已设置';
  429. $user['version'] = request()->header('version');
  430. return $user;
  431. }
  432. /**
  433. * @notes 获取微信手机号
  434. * @param $params
  435. * @return array|false
  436. * @author Tab
  437. * @date 2021/8/24 15:20
  438. * @deprecated 小程序获取手机号码更新升级,旧接口放弃
  439. */
  440. public static function getMobileByMnp($params)
  441. {
  442. try {
  443. $config = [
  444. 'app_id' => ConfigService::get('mini_program', 'app_id'),
  445. 'secret' => ConfigService::get('mini_program', 'app_secret'),
  446. ];
  447. $app = Factory::miniProgram($config);
  448. $response = $app->auth->session($params['code']);
  449. if (!isset($response['session_key'])) {
  450. throw new \Exception('获取用户信息失败');
  451. }
  452. $response = $app->encryptor->decryptData($response['session_key'], $params['iv'], $params['encrypted_data']);
  453. $user = User::where([
  454. ['mobile', '=', $response['phoneNumber']],
  455. ['id', '<>', $params['user_id']]
  456. ])->findOrEmpty();
  457. if (!$user->isEmpty()) {
  458. throw new \Exception('手机号已被其他账号绑定');
  459. }
  460. // 绑定手机号
  461. self::setInfo($params['user_id'], [
  462. 'field' => 'mobile',
  463. 'value' => $response['phoneNumber']
  464. ]);
  465. return true;
  466. } catch (\Exception $e) {
  467. self::setError($e->getMessage());
  468. return false;
  469. }
  470. }
  471. /**
  472. * @notes 微信小程序获取手机号码并绑定
  473. * @param $params
  474. * @return bool
  475. * @throws \GuzzleHttp\Exception\GuzzleException
  476. * @author cjhao
  477. * @date 2022/5/17 9:34
  478. */
  479. public static function getNewMobileByMnp($params)
  480. {
  481. try {
  482. $getMnpConfig = WeChatConfigService::getMnpConfig();
  483. $app = Factory::miniProgram($getMnpConfig);
  484. $response = $app->phone_number->getUserPhoneNumber($params['code']);
  485. $phoneNumber = $response['phone_info']['purePhoneNumber'] ?? '';
  486. if(empty($phoneNumber)){
  487. throw new Exception('获取手机号码失败');
  488. }
  489. $user = User::where([
  490. ['mobile', '=', $phoneNumber],
  491. ['id', '<>', $params['user_id']]
  492. ])->findOrEmpty();
  493. if (!$user->isEmpty()) {
  494. throw new \Exception('手机号已被其他账号绑定');
  495. }
  496. // 绑定手机号
  497. self::setInfo($params['user_id'], [
  498. 'field' => 'mobile',
  499. 'value' => $phoneNumber
  500. ]);
  501. return true;
  502. } catch (\Exception $e) {
  503. self::setError($e->getMessage());
  504. return false;
  505. }
  506. }
  507. /**
  508. * @notes 获取服务协议
  509. * @return array
  510. * @author Tab
  511. * @date 2021/8/24 16:48
  512. */
  513. public static function getServiceAgreement()
  514. {
  515. $data = [
  516. 'service_agreement_name' => ConfigService::get('shop', 'service_agreement_name', ''),
  517. 'service_agreement_content' => ConfigService::get('shop', 'service_agreement_content', ''),
  518. ];
  519. return $data;
  520. }
  521. /**
  522. * @notes 获取隐私政策
  523. * @return array
  524. * @author Tab
  525. * @date 2021/8/24 16:50
  526. */
  527. public static function getPrivacyPolicy()
  528. {
  529. $data = [
  530. 'privacy_policy_name' => ConfigService::get('shop', 'privacy_policy_name', ''),
  531. 'privacy_policy_content' => ConfigService::get('shop', 'privacy_policy_content', '')
  532. ];
  533. return $data;
  534. }
  535. /**
  536. * @notes 设置登录密码
  537. * @author Tab
  538. * @date 2021/10/22 18:10
  539. */
  540. public static function setPassword($params)
  541. {
  542. try {
  543. $user = User::findOrEmpty($params['user_id']);
  544. if ($user->isEmpty()) {
  545. throw new \Exception('用户不存在');
  546. }
  547. if (!empty($user->password)) {
  548. throw new \Exception('用户已设置登录密码');
  549. }
  550. $passwordSalt = Config::get('project.unique_identification');
  551. $password = create_password($params['password'], $passwordSalt);
  552. $user->password = $password;
  553. $user->save();
  554. return true;;
  555. } catch (\Exception $e) {
  556. self::setError($e->getMessage());
  557. return false;
  558. }
  559. }
  560. /**
  561. * @notes 修改登录密码
  562. * @param $params
  563. * @return bool
  564. * @author Tab
  565. * @date 2021/10/22 18:17
  566. */
  567. public static function changePassword($params)
  568. {
  569. try {
  570. $user = User::findOrEmpty($params['user_id']);
  571. if ($user->isEmpty()) {
  572. throw new \Exception('用户不存在');
  573. }
  574. $passwordSalt = Config::get('project.unique_identification');
  575. $oldPassword = create_password($params['old_password'], $passwordSalt);
  576. $newPassword = create_password($params['password'], $passwordSalt);
  577. if ($user->password != $oldPassword) {
  578. throw new \Exception('原密码错误');
  579. }
  580. $user->password = $newPassword;
  581. $user->save();
  582. return true;;
  583. } catch (\Exception $e) {
  584. self::setError($e->getMessage());
  585. return false;
  586. }
  587. }
  588. /**
  589. * @notes 判断用户是否有设置登录密码
  590. * @param $userId
  591. * @author Tab
  592. * @date 2021/10/22 18:25
  593. */
  594. public static function hasPassword($userId)
  595. {
  596. $user = User::findOrEmpty($userId);
  597. return empty($user->password) ? false : true;
  598. }
  599. static function updateRegisterAward($userId)
  600. {
  601. User::update([
  602. 'id' => $userId,
  603. 'is_register_award' => 1,
  604. ]);
  605. }
  606. }