| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- <?php
- namespace App\Repositories\Service;
- use Hyperf\Redis\Redis;
- class UserSingInService
- {
- /**
- * @var Redis
- */
- protected $redis;
- public function __construct()
- {
- $this->redis = make(Redis::class);
- }
- /**
- * 签到
- *
- * @param string $userId
- * @return int
- */
- public function doSigns(string $userId): bool
- {
- $day = date('d') - 1;
- $date = date('Y-m');
- return $this->redis->setbit($this->buildSignKey($userId, $date), (int)$day, true);
- }
- /**
- * 统计连续签到次数
- * 统计的是连续的签到次数,按业务需求改为七天的
- *
- * @param string $userId
- * @return int
- */
- public function getContinuousSignCount(string $userId): int
- {
- $day = date('d');
- $lastMonthCount = 0;
- if ($day == '1' || $day == '01') {
- $lastMonthCount = $this->lastMonthContinuousSignCount($userId);
- }
- $date = date('Y-m');
- $key = $this->buildSignKey($userId, $date);
- //获取本月的二进制数据
- $nowContinuousStr = $this->redis->rawCommand('BITFIELD', $key, 'GET', 'u' . (int)$day, 0);
- //获取连续签到天数
- if ($nowContinuousStr) {
- $count = $this->countContinuousSignCount($nowContinuousStr, (int)$day);
- } else {
- $count = 0;
- }
- $count = $count + $lastMonthCount;
- if ($count > 7) {
- $count = 7;
- }
- return $count;
- }
- /**
- * 检查用户是否签到
- *
- * @param string $userId
- * @param string $date
- * @return int
- */
- public function checkSign(string $userId, string $date): int
- {
- $day = date('d') - 1;
- return $this->redis->getBit($this->buildSignKey($userId, $date), $day);
- }
- /**
- * 统计上个月连续签到总数
- *
- * @param string $userId
- * @return int
- */
- public function lastMonthContinuousSignCount(string $userId): int
- {
- $date = date('Ym', strtotime('-1 month'));
- //上个月最后一天
- $day = date("d", strtotime(-date('d') . 'day'));
- $key = $this->buildSignKey($userId, $date);
- //获取本月签到的所有二进制数据
- $continuousStr = $this->redis->get($key);
- if ($continuousStr) {
- $res = $this->countContinuousSignCount($continuousStr, (int)$day);
- } else {
- $res = 0;
- }
- return $res;
- }
- /**
- * 连续签到计算
- *
- * @param string $continuousStr
- * @param string $day
- * @return int
- */
- private function countContinuousSignCount(array $continuousStr, int $day): int
- {
- if (!empty($continuousStr)) {
- $v = $continuousStr[0];
- $count = 0;
- for ($i = 0; $i < $day; $i++) {
- if ($v >> 1 << 1 == $v) {
- // 低位为0且非当天说明连续签到中断了
- if ($i > 0) {
- break;
- }
- } else {
- $count += 1;
- }
- $v >>= 1;
- }
- } else {
- $count = 0;
- }
- return $count;
- }
- /**
- * 构建签到key
- *
- * @param string $userId
- * @param string $date
- * @return string
- */
- private function buildSignKey(string $userId, string $date): string
- {
- return "u:sign:{$userId}:{$date}";
- }
- }
|