UserSignServices.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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\services\BaseServices;
  14. use app\dao\user\UserSignDao;
  15. use app\services\system\SystemSignRewardServices;
  16. use app\services\user\member\MemberCardServices;
  17. use crmeb\exceptions\ApiException;
  18. use crmeb\services\CacheService;
  19. use think\facade\Log;
  20. /**
  21. *
  22. * Class UserSignServices
  23. * @package app\services\user
  24. */
  25. class UserSignServices extends BaseServices
  26. {
  27. /**
  28. * UserSignServices constructor.
  29. * @param UserSignDao $dao
  30. */
  31. public function __construct(UserSignDao $dao)
  32. {
  33. $this->dao = $dao;
  34. }
  35. /**
  36. * 获取用户是否签到
  37. * @param int $uid
  38. * @param string $type
  39. * @return bool
  40. * @throws \ReflectionException
  41. * @author: 吴汐
  42. * @email: 442384644@qq.com
  43. * @date: 2023/8/8
  44. */
  45. public function getIsSign(int $uid, string $type = 'today')
  46. {
  47. return (bool)$this->dao->count(['uid' => $uid, 'time' => $type]);
  48. }
  49. /**
  50. * 获取用户累计签到次数
  51. * @param int $uid
  52. * @return int
  53. * @throws \ReflectionException
  54. * @author: 吴汐
  55. * @email: 442384644@qq.com
  56. * @date: 2023/8/8
  57. */
  58. public function getSignSumDay(int $uid)
  59. {
  60. return $this->dao->count(['uid' => $uid]);
  61. }
  62. /**
  63. * 设置签到数据
  64. * @param $uid
  65. * @param string $title
  66. * @param int $number
  67. * @param int $integral_balance
  68. * @param int $exp_banlance
  69. * @param int $exp_num
  70. * @return bool
  71. * @throws \think\Exception
  72. * @author: 吴汐
  73. * @email: 442384644@qq.com
  74. * @date: 2023/8/8
  75. */
  76. public function setSignData($uid, $title = '', $number = 0, $integral_balance = 0, $exp_banlance = 0, $exp_num = 0)
  77. {
  78. $data = [];
  79. $data['uid'] = $uid;
  80. $data['title'] = $title;
  81. $data['number'] = $number;
  82. $data['balance'] = $integral_balance + $number;
  83. $data['add_time'] = time();
  84. if (!$this->dao->save($data)) {
  85. throw new ApiException(410290);
  86. }
  87. /** @var UserBillServices $userBill */
  88. $userBill = app()->make(UserBillServices::class);
  89. $data['mark'] = $title;
  90. $userBill->incomeIntegral($uid, 'sign', $data);
  91. if ($exp_num) {
  92. $data['number'] = $exp_num;
  93. $data['category'] = 'exp';
  94. $data['type'] = 'sign';
  95. $data['title'] = $data['mark'] = '签到奖励';
  96. $data['balance'] = $exp_banlance + $exp_num;
  97. $data['pm'] = 1;
  98. $data['status'] = 1;
  99. if (!$userBill->save($data)) {
  100. throw new ApiException(410291);
  101. }
  102. //检测会员等级
  103. try {
  104. //用户升级事件
  105. event('UserLevelListener', [$uid]);
  106. } catch (\Throwable $e) {
  107. Log::error('会员等级升级失败,失败原因:' . $e->getMessage());
  108. }
  109. }
  110. return true;
  111. }
  112. /**
  113. * 获取用户签到列表
  114. * @param int $uid
  115. * @param string $field
  116. * @return array
  117. * @throws \think\db\exception\DataNotFoundException
  118. * @throws \think\db\exception\DbException
  119. * @throws \think\db\exception\ModelNotFoundException
  120. * @author: 吴汐
  121. * @email: 442384644@qq.com
  122. * @date: 2023/8/8
  123. */
  124. public function getUserSignList(int $uid, string $field = '*')
  125. {
  126. [$page, $limit] = $this->getPageValue();
  127. $list = $this->dao->getList(['uid' => $uid], $field, $page, $limit);
  128. foreach ($list as &$item) {
  129. $item['add_time'] = $item['add_time'] ? date('Y-m-d', $item['add_time']) : '';
  130. }
  131. return $list;
  132. }
  133. /**
  134. * 用户签到
  135. * @param $uid
  136. * @return bool|int|mixed
  137. * @throws \think\db\exception\DataNotFoundException
  138. * @throws \think\db\exception\DbException
  139. * @throws \think\db\exception\ModelNotFoundException
  140. */
  141. public function sign(int $uid)
  142. {
  143. /** @var UserServices $userServices */
  144. $userServices = app()->make(UserServices::class);
  145. //检测用户是否存在
  146. $user = $userServices->getUserInfo($uid);
  147. if (!$user) {
  148. throw new ApiException(410032);
  149. }
  150. $userServices->offMemberLevel($uid);
  151. //检测今天是否已经签到
  152. if ($this->getIsSign($uid, 'today')) {
  153. throw new ApiException(410293);
  154. }
  155. $title = '签到奖励';
  156. //检测昨天是否签到,如果没有签到,连续签到清0
  157. if (!$this->getIsSign($uid, 'yesterday')) $user->sign_num = 0;
  158. //获取签到周期配置,如果周签到,每周一清空连续签到记录,如果月签到,每月一日清空连续签到记录
  159. $sign_mode = sys_config('sign_mode', -1);
  160. if ($sign_mode == 1 && date('w') == 1) $user->sign_num = 0;
  161. if ($sign_mode == 0 && date('d') == 1) $user->sign_num = 0;
  162. //连续签到天数
  163. $user->sign_num += 1;
  164. $continuousDays = $user->sign_num;
  165. //累积签到天数
  166. $cumulativeDays = $this->dao->getCumulativeDays($sign_mode, $uid);
  167. //基础签到奖励
  168. $sign_point = sys_config('sign_give_point', 0);
  169. $sign_exp = sys_config('member_func_status', 1) ? sys_config('sign_give_exp', 0) : 0;
  170. //连续签到和累积签到奖励
  171. $signRewardsServices = app()->make(SystemSignRewardServices::class);
  172. [$continuousStatus, $continuousRewardPoint, $continuousRewardExp] = $signRewardsServices->getSignRewards(0, $continuousDays);
  173. [$cumulativeStatus, $cumulativeRewardPoint, $cumulativeRewardExp] = $signRewardsServices->getSignRewards(1, $cumulativeDays);
  174. if ($continuousStatus && $cumulativeStatus) {
  175. $sign_point = $continuousRewardPoint + $cumulativeRewardPoint;
  176. $sign_exp = $continuousRewardExp + $cumulativeRewardExp;
  177. } elseif ($continuousStatus) {
  178. $sign_point = $continuousRewardPoint;
  179. $sign_exp = $continuousRewardExp;
  180. } elseif ($cumulativeStatus) {
  181. $sign_point = $cumulativeRewardPoint;
  182. $sign_exp = $cumulativeRewardExp;
  183. }
  184. //会员签到积分会员奖励
  185. if ($user->is_money_level > 0) {
  186. //看是否开启签到积分翻倍奖励
  187. /** @var MemberCardServices $memberCardService */
  188. $memberCardService = app()->make(MemberCardServices::class);
  189. $sign_rule_number = $memberCardService->isOpenMemberCard('sign');
  190. if ($sign_rule_number) {
  191. $up_num = (int)$sign_rule_number * $sign_point - $sign_point;
  192. $sign_point = (int)$sign_rule_number * $sign_point;
  193. if (!$this->getIsSign($uid, 'yesterday')) $title = '签到奖励(SVIP+' . $up_num . ')';
  194. }
  195. }
  196. //增加签到数据
  197. $this->transaction(function () use ($uid, $title, $sign_point, $user, $sign_exp) {
  198. $this->setSignData($uid, $title, $sign_point, $user['integral'], (int)$user['exp'], $sign_exp);
  199. $user->integral = (int)$user->integral + (int)$sign_point;
  200. if ($sign_exp) $user->exp = bcadd((string)$user->exp, (string)$sign_exp, 2);
  201. if (!$user->save()) {
  202. throw new ApiException(410287);
  203. }
  204. });
  205. //自定义事件-用户签到
  206. event('CustomEventListener', ['user_sign', [
  207. 'uid' => $uid,
  208. 'sign_point' => $sign_point,
  209. 'sign_exp' => $sign_exp,
  210. 'sign_time' => date('Y-m-d H:i:s'),
  211. ]]);
  212. return $sign_point;
  213. }
  214. /**
  215. * 签到用户信息
  216. * @param int $uid
  217. * @param $sign
  218. * @param $integral
  219. * @param $all
  220. * @return array
  221. * @throws \think\db\exception\DataNotFoundException
  222. * @throws \think\db\exception\DbException
  223. * @throws \think\db\exception\ModelNotFoundException
  224. * @author: 吴汐
  225. * @email: 442384644@qq.com
  226. * @date: 2023/8/8
  227. */
  228. public function signUser(int $uid, $sign, $integral, $all)
  229. {
  230. /** @var UserServices $userServices */
  231. $userServices = app()->make(UserServices::class);
  232. $user = $userServices->getUserInfo($uid);
  233. if (!$user) {
  234. throw new ApiException(100026);
  235. }
  236. //是否统计签到
  237. if ($sign || $all) {
  238. $user['sum_sgin_day'] = $this->getSignSumDay($user['uid']);
  239. $user['is_day_sgin'] = false;
  240. $user['is_YesterDay_sgin'] = $this->getIsSign($user['uid'], 'yesterday');
  241. if (!$user['is_day_sgin'] && !$user['is_YesterDay_sgin']) {
  242. $user['sign_num'] = 0;
  243. }
  244. }
  245. //是否统计积分使用情况
  246. if ($integral || $all) {
  247. /** @var UserBillServices $userBill */
  248. $userBill = app()->make(UserBillServices::class);
  249. $user['sum_integral'] = intval($userBill->getRecordCount($user['uid'], 'integral', 'sign,system_add,gain,lottery_add,product_gain,pay_product_integral_back'));
  250. $user['deduction_integral'] = intval($userBill->getRecordCount($user['uid'], 'integral', 'deduction,lottery_use,order_deduction,storeIntegral_use', '', true) ?? 0);
  251. $user['today_integral'] = intval($userBill->getRecordCount($user['uid'], 'integral', 'sign,system_add,gain,product_gain,lottery_add,pay_product_integral_back', 'today'));
  252. /** @var UserBillServices $userBillServices */
  253. $userBillServices = app()->make(UserBillServices::class);
  254. $user['frozen_integral'] = $userBillServices->getBillSum(['uid' => $user['uid'], 'is_frozen' => 1]);
  255. }
  256. unset($user['pwd']);
  257. if (!$user['is_promoter']) {
  258. $user['is_promoter'] = (int)sys_config('store_brokerage_statu') == 2;
  259. }
  260. return $user->hidden(['account', 'real_name', 'birthday', 'card_id', 'mark', 'partner_id', 'group_id', 'add_time', 'add_ip', 'phone', 'last_time', 'last_ip', 'spread_uid', 'spread_time', 'user_type', 'status', 'level', 'clean_time', 'addres'])->toArray();
  261. }
  262. /**
  263. * 获取签到
  264. * @param $uid
  265. * @return array
  266. * @throws \think\db\exception\DataNotFoundException
  267. * @throws \think\db\exception\DbException
  268. * @throws \think\db\exception\ModelNotFoundException
  269. * @author: 吴汐
  270. * @email: 442384644@qq.com
  271. * @date: 2023/8/8
  272. */
  273. public function getSignMonthList($uid)
  274. {
  275. [$page, $limit] = $this->getPageValue();
  276. $data = $this->dao->getListGroup(['uid' => $uid], 'FROM_UNIXTIME(add_time,"%Y-%m") as time,group_concat(id SEPARATOR ",") ids', $page, $limit, 'time');
  277. $list = [];
  278. if ($data) {
  279. $ids = array_unique(array_column($data, 'ids'));
  280. $dataIdsList = $this->dao->getList(['id' => $ids], 'FROM_UNIXTIME(add_time,"%Y-%m-%d") as add_time,title,number,id,uid', 0, 0);
  281. foreach ($data as $item) {
  282. $value['month'] = $item['time'];
  283. $value['list'] = array_merge(array_filter($dataIdsList, function ($val) use ($item) {
  284. if (in_array($val['id'], explode(',', $item['ids']))) {
  285. return $val;
  286. }
  287. }));
  288. array_push($list, $value);
  289. }
  290. }
  291. return $list;
  292. }
  293. /**
  294. * 返回签到列表数据
  295. * @param $uid
  296. * @return array
  297. * @throws \think\db\exception\DataNotFoundException
  298. * @throws \think\db\exception\DbException
  299. * @throws \think\db\exception\ModelNotFoundException
  300. * @author: 吴汐
  301. * @email: 442384644@qq.com
  302. * @date: 2023/8/8
  303. */
  304. public function signConfig($uid, $signMode = 0)
  305. {
  306. if (!$signMode) {
  307. //获取周签到还是月签到
  308. $signMode = (int)sys_config('sign_mode', 1);
  309. }
  310. //获取签到列表
  311. $startDate = $signMode == 1 ? strtotime('this week Monday') : strtotime('first day of this month midnight');
  312. $endDate = $signMode == 1 ? strtotime('this week Sunday') : strtotime('last day of this month midnight');
  313. $dateList = range($startDate, $endDate, 86400);
  314. //获取已经签到的列表
  315. $list = $this->dao->getUserSignList($signMode, $uid);
  316. //获取累积签到和连续签到
  317. $cumulativeSignDays = $this->dao->getCumulativeDays($signMode, $uid);
  318. $continuousSignDays = app()->make(UserServices::class)->value($uid, 'sign_num');
  319. //获取累积签到和连续签到奖励
  320. $nextCumulativeSignRewardList = app()->make(SystemSignRewardServices::class)->selectList(['type' => 1], '*', 1, 200, 'days asc')->toArray();
  321. $nextContinuousSignRewardList = app()->make(SystemSignRewardServices::class)->selectList(['type' => 0], '*', 1, 200, 'days asc')->toArray();
  322. //下一次连续签到奖励还需签到几天
  323. $nextContinuousDays = 0;
  324. foreach ($nextContinuousSignRewardList as $continuousNext) {
  325. if ($continuousSignDays < $continuousNext['days']) {
  326. $nextContinuousDays = $continuousNext['days'] - $continuousSignDays > 0 ? $continuousNext['days'] - $continuousSignDays : 1;
  327. break;
  328. }
  329. }
  330. $nextCumulativeDays = 0;
  331. foreach ($nextCumulativeSignRewardList as $cumulativeNext) {
  332. if ($cumulativeSignDays < $cumulativeNext['days']) {
  333. $nextCumulativeDays = $cumulativeNext['days'] - $cumulativeSignDays > 0 ? $cumulativeNext['days'] - $cumulativeSignDays : 1;
  334. break;
  335. }
  336. }
  337. //整理签到列表数据
  338. $signList = [];
  339. $i = 0;
  340. $checkSign = $this->getIsSign($uid, 'today');
  341. foreach ($dateList as $key => $time) {
  342. $day = date('m.d', $time);
  343. if ($day[0] == '0') $day = substr($day, 1);
  344. $signList[$key]['day'] = $day;
  345. $signList[$key]['is_sign'] = false;
  346. $signList[$key]['type'] = 0;
  347. //判断当前签到日期
  348. $signList[$key]['sign_day'] = date('Y-m-d', $time) == date('Y-m-d', time());
  349. //判断今日是否签到
  350. foreach ($list as $value) {
  351. if (date('Y-m-d', $time) == date('Y-m-d', $value['add_time'])) {
  352. $signList[$key]['is_sign'] = true;
  353. break;
  354. }
  355. }
  356. //处理处理签到类型展示,type 0已签到,1积分,2经验,3连续,4累积
  357. $signList[$key]['type'] = sys_config('sign_give_point', 0) == 0 && sys_config('member_func_status', 1) == 1 && sys_config('sign_give_exp', 0) > 0 ? 2 : 1;
  358. $signList[$key]['point'] = (int)sys_config('sign_give_point');
  359. if (date('Y-m-d', $time) >= date('Y-m-d', time())) {
  360. foreach ($nextContinuousSignRewardList as $continuous) {
  361. if (($continuous['days'] - $continuousSignDays) == $i) {
  362. $signList[$key]['type'] = 3;
  363. $signList[$key]['point'] = $continuous['point'];
  364. }
  365. }
  366. foreach ($nextCumulativeSignRewardList as $cumulative) {
  367. if (($cumulative['days'] - $cumulativeSignDays) == $i) {
  368. $signList[$key]['type'] = 4;
  369. $signList[$key]['point'] = $cumulative['point'];
  370. }
  371. }
  372. $i++;
  373. }
  374. }
  375. //格式化签到数据
  376. $signList = array_chunk($signList, 7);
  377. //获取用户签到提醒状态
  378. $signRemindStatus = app()->make(UserServices::class)->value($uid, 'sign_remind');
  379. //是否显示签到提醒开关
  380. $signRemindSwitch = (int)sys_config('sign_remind', 0);
  381. //签到功能是否关闭
  382. $signStatus = (int)sys_config('sign_status', 0);
  383. //签到功能是否关闭
  384. $signGivePoint = (int)sys_config('sign_give_point', 0);
  385. return compact('signList', 'continuousSignDays', 'cumulativeSignDays', 'nextContinuousDays', 'nextCumulativeDays', 'signMode', 'checkSign', 'signRemindStatus', 'signRemindSwitch', 'signStatus', 'signGivePoint');
  386. }
  387. /**
  388. * 签到提醒设置
  389. * @param $uid
  390. * @param $status
  391. * @return bool
  392. * @author: 吴汐
  393. * @email: 442384644@qq.com
  394. * @date: 2023/8/9
  395. */
  396. public function setSignRemind($uid, $status)
  397. {
  398. app()->make(UserServices::class)->update($uid, ['sign_remind' => $status]);
  399. return true;
  400. }
  401. /**
  402. * 签到提醒
  403. * @return bool
  404. * @author wuhaotian
  405. * @email 442384644@qq.com
  406. * @date 2023/9/30
  407. */
  408. public function sendSignRemind()
  409. {
  410. //今天已经发送过,不执行发送提醒逻辑
  411. if (CacheService::get('sign_remind_expire')) return true;
  412. //当前时间小于每天执行提醒发送的时间,不执行发送提醒逻辑
  413. if (time() < strtotime('today ' . sys_config('sign_remind_time'))) return true;
  414. //获取需要签到提醒的用户
  415. $list = app()->make(UserServices::class)->getColumn(['sign_remind' => 1], 'phone', 'uid');
  416. if ($list) {
  417. //获取今天已经签到的用户
  418. $signList = $this->dao->getColumn([['add_time', 'between', [strtotime('today'), strtotime('today 23:59:59')]]], 'uid');
  419. $noSignList = array_diff_key($list, array_flip($signList));
  420. foreach ($noSignList as $uid => $phone) {
  421. event('NoticeListener', [['uid' => $uid, 'phone' => $phone], 'sign_remind']);
  422. }
  423. }
  424. //已经发送提醒,写入缓存,禁止当天多次执行
  425. CacheService::set('sign_remind_expire', 1, strtotime('tomorrow') - time());
  426. return true;
  427. }
  428. }