美文网首页
php+redise用户连续签到

php+redise用户连续签到

作者: Paradise_2fa3 | 来源:发表于2019-06-27 18:11 被阅读0次

业务需求:

![用户签到.png](https://img.haomeiwen.com/i8916618/28d8a4d2f6ba820c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

问题点:

  • 积分签到有循环周期,连续签到的天数达到了循环的天数,那么重新开始新一轮签到。
  • 积分签到因本项目的也无需求,需要区分添加到用户积分中,还是会员积分中。
  • 若未设置用户签到赠送的积分、连续签到的积分时,只更新签到的天数不添加用户积分、也不写入积分赠送记录。
  • 若当日赠送积分已经达到当日赠送的积分上限,那么不赠送(当日赠送积分已到99积分,当日最大赠送积分100,签到赠送10积分,意思再送1积分就达到上限,那么也不赠送)

功能实现:

  • 数据库对积分赠送记录储存:包含每日赠送积分记录、连续签到额外赠送积分记录
  • redis储存用户签到的天数、最后签到的时间
  • 队列处理赠送积分到用户

签到业务思维导图

用户签到.png

签到业务核心代码

<?php

namespace app\user\service;


/*
 *   用户签到模块
 */

use app\general\model\spreadPlatformUserModel;
use app\platform\model\spreadCardModel;
use app\platform\service\spreadCardScoreLogService;
use app\platform\service\spreadCardScoreRuleService;
use app\platform\service\spreadCardService;
use app\platform\service\spreadPlatformUserService;
use app\user\cache\signCache;
use think\Db;

class userSignService
{
    /*
     *todo 用户签到,分发到对应的用户角色中(区分用户、会员积分)
     */
    public static function userSign($spreadId, $userId)
    {
        if (empty($spreadId) || empty($userId)) {
            recordError('参数缺失');
            return false;
        }
        //todo 获取平台设置的积分规则设置
        $spreadRule = spreadCardScoreRuleService::getCardScoreRule($spreadId, true);
        //todo 查看用户是否是平台用户
        $userInfo = spreadPlatformUserService::getPlatformUserInfoByUserId($spreadId, $userId);
        if (empty($userInfo)) {
            //todo 不存在平台用户,则新增平台用户
            $addNewPlatUserData = [
                'user_id' => $userId,
                'spread_id' => $spreadId,
                'recommend_num' => '',
                'user_type' => spreadPlatformUserModel::USER_TYPE_REG,
                'reg_time' => time(),
                'latest_time' => time(),
                'last_order' => time(),
            ];
            spreadPlatformUserService::addPlatUser($addNewPlatUserData);
        } else {
            if ($userInfo['status'] == spreadPlatformUserModel::STATE_DISABLE) {
                recordError('抱歉,您已被禁用,不能签到!');
                return false;
            }
            $cardUser = spreadCardService::getCardByUserIdV3($userId, $spreadId);
        }
        //todo 开始分发签到到对应角色
        if (isset($cardUser) && $cardUser['status'] != spreadCardModel::STATUS_HIDDEN) {
            return self::addScoreToCard($spreadId, $userId, $cardUser, $spreadRule);
        } else {
            return self::addScoreToUser($spreadId, $userId, $userInfo, $spreadRule);
        }
    }


    /*
     * todo 逻辑处理用户是否签到,是否是连续签到,是否超过循环周期
     */
    public static function addScoreToUser($spreadId, $userId, $userInfo, $spreadRule)
    {
        //todo 查询缓存的签到天数与最后签到时间
        $oldSignDay = signCache::getUserSign($spreadId, $userId);
        //初始签到天数
        $newSignDay = [
            'day' => 1,
            'last_time' => time()
        ];
        //获取循环周期
        $defaultDay = empty($spreadRule['cycle']) ? 7 : $spreadRule['cycle'];
        // 计算上一天的开始时间
        $lastDayStartTime = strtotime(date('Y-m-d') . ' -1 day');
        //todo 判断是否是缓存的最后签到时间
        if (empty($oldSignDay) || $oldSignDay == false) {
            //如果没有设置相关签到的积分赠送规则,那么返回缓存签到的天数
            if($spreadRule['day_get_score'] == 0 && empty($spreadRule['continue_info'])){
                if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                    recordError('签到失败');
                    return false;
                }
                return $spreadRule['day_get_score'];
            }
            return self::setUserSignScore($spreadId, $userId, $newSignDay, $userInfo, $spreadRule);
        } else {
            //判断用户当天是否已经签到
            if ($oldSignDay['last_time'] >= strtotime(date("Y-m-d", time())) && $oldSignDay['last_time'] <= strtotime(date("Y-m-d " . '23:59:59', time()))) {
                recordError('抱歉,已经签到过了');
                return false;
            }
            //判断最后的签到天数是否等于循环的周期
            if($oldSignDay['day'] == $defaultDay){
                //如果没有设置相关签到的积分赠送规则,直接写入缓存,返回每日赠送的积分
                if($spreadRule['day_get_score'] == 0 && empty($spreadRule['continue_info'])){
                    if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                        recordError('签到失败');
                        return false;
                    }
                    return $spreadRule['day_get_score'];
                }
                return self::setUserSignScore($spreadId, $userId, $newSignDay, $userInfo, $spreadRule);
            }
            //判断用户的最后签到时间是否在上一天之内
            if ($oldSignDay['last_time'] < strtotime(date("Y-m-d", time())) && $oldSignDay['last_time'] >=
                $lastDayStartTime) {
                $newSignDay = [
                    'day' => $oldSignDay['day'] + 1,
                    'last_time' => time(),
                ];
                //如果没有设置相关签到的积分赠送规则,直接写入缓存,返回每日赠送的积分
                if($spreadRule['day_get_score'] == 0 && empty($spreadRule['continue_info'])){
                    if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                        recordError('签到失败');
                        return false;
                    }
                    return $spreadRule['day_get_score'];
                }
                return self::setUserSignScore($spreadId, $userId, $newSignDay, $userInfo, $spreadRule);
            } else {
                //如果没有设置相关签到的积分赠送规则,直接写入缓存,返回每日赠送的积分
                if($spreadRule['day_get_score'] == 0 && empty($spreadRule['continue_info'])){
                    if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                        recordError('签到失败');
                        return false;
                    }
                    return $spreadRule['day_get_score'];
                }
                return self::setUserSignScore($spreadId, $userId, $newSignDay, $userInfo, $spreadRule);
            }
        }
    }

    /*
      * todo 逻辑处理会员是否签到,是否是连续签到,是否超过循环周期
      */
    public static function addScoreToCard($spreadId, $userId, $cardUser, $spreadRule)
    {
        //todo 查询缓存的签到天数与最后签到时间
        $oldSignDay = signCache::getUserSign($spreadId, $userId);
        //初始签到天数
        $newSignDay = [
            'day' => 1,
            'last_time' => time()
        ];
        //获取循环周期
        $defaultDay = empty($spreadRule['cycle']) ? 7 : $spreadRule['cycle'];
        // 计算上一天的开始时间
        $lastDayStartTime = strtotime(date('Y-m-d') . ' -1 day');
        //todo 判断是否是缓存的最后签到时间
        if (empty($oldSignDay) || $oldSignDay == false) {
            //如果没有设置相关签到的积分赠送规则,直接写入缓存,返回每日赠送的积分
            if($spreadRule['day_get_score'] == 0 && empty($spreadRule['continue_info'])){
                if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                    recordError('签到失败');
                    return false;
                }
                return $spreadRule['day_get_score'];
            }
            return self::setCardSignScore($spreadId, $userId, $newSignDay, $cardUser, $spreadRule);
        } else {
            //判断用户当天是否已经签到
            if ($oldSignDay['last_time'] >= strtotime(date("Y-m-d", time())) && $oldSignDay['last_time'] <= strtotime(date("Y-m-d " . '23:59:59', time()))) {
                recordError('抱歉,已经签到过了');
                return false;
            }
            //判断最后的签到天数是否等于循环的周期
            if($oldSignDay['day'] == $defaultDay){
                //如果没有设置相关签到的积分赠送规则,直接写入缓存,返回每日赠送的积分
                if($spreadRule['day_get_score'] == 0 && empty($spreadRule['continue_info'])){
                    if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                        recordError('签到失败');
                        return false;
                    }
                    return $spreadRule['day_get_score'];
                }
                return self::setCardSignScore($spreadId, $userId, $newSignDay, $cardUser, $spreadRule);
            }
            //判断最后签到的时间是否在上一天的时间内
            if ($oldSignDay['last_time'] < strtotime(date("Y-m-d", time())) && $oldSignDay['last_time'] >=
                $lastDayStartTime) {
                $newSignDay = [
                    'day' => $oldSignDay['day'] + 1,
                    'last_time' => time(),
                ];
                //如果没有设置相关签到的积分赠送规则,直接写入缓存,返回每日赠送的积分
                if($spreadRule['day_get_score'] == 0 && empty($spreadRule['continue_info'])){
                    if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                        recordError('签到失败');
                        return false;
                    }
                    return $spreadRule['day_get_score'];
                }
                return self::setCardSignScore($spreadId, $userId, $newSignDay, $cardUser, $spreadRule);
            } else {
                //如果没有设置相关签到的积分赠送规则,直接写入缓存,返回每日赠送的积分
               if($spreadRule['day_get_score'] == 0 && empty($spreadRule['continue_info'])){
                   if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                       recordError('签到失败');
                       return false;
                   }
                   return $spreadRule['day_get_score'];
               }
               return self::setCardSignScore($spreadId, $userId, $newSignDay, $cardUser, $spreadRule);
            }
        }
    }


    /*
     * todo 获取所有必备的增加用户积分的参数
     */
    public static function setUserSignScore($spreadId, $userId, $newSignDay, $userInfo, $spreadRule)
    {
        if(empty($spreadId) || empty($userId) || empty($newSignDay) || empty($userInfo) || empty($spreadRule)){
            recordError('参数错误');
            return false;
        }
        $scoreRule = isset($spreadRule['continue_info']) ? json_decode($spreadRule['continue_info'], true) : [];
        //判断后台是否设置的有连续签到规则
        if (!empty($scoreRule)) {
            foreach ($scoreRule as $rule) {
                if ($rule['day'] == $newSignDay['day']) {
                    $extraScore = $rule['score'];
                }
            }
        }
        $userTodayScore = spreadCardScoreLogService::getTodayPlatUserGetScore($spreadId, $userId);
        return self::addScoreUserScore($spreadId, $userId, $newSignDay, $userInfo, $spreadRule, $userTodayScore, isset
        ($extraScore) ? $extraScore : 0);
    }

    /*
     * todo 获取所有必备的增加会员积分的参数
     */
    public static function setCardSignScore($spreadId, $userId, $newSignDay, $cardInfo, $spreadRule)
    {
        if(empty($spreadId) || empty($userId) || empty($newSignDay) || empty($cardInfo) || empty($spreadRule)){
            recordError('参数错误');
            return false;
        }
        $scoreRule = isset($spreadRule['continue_info']) ? json_decode($spreadRule['continue_info'], true) : [];
        //判断后台是否设置的有连续签到规则
        if (!empty($scoreRule)) {
            foreach ($scoreRule as $rule) {
                if ($rule['day'] == $newSignDay['day']) {
                    $extraScore = $rule['score'];
                }
            }
        }
        $userTodayScore = spreadCardScoreLogService::getTodayPlatUserGetScore($spreadId, $userId);
        return self::addScoreCardScore($spreadId, $userId, $newSignDay, $cardInfo, $spreadRule, $userTodayScore, isset
        ($extraScore) ? $extraScore : 0);
    }

    /*
     * todo  事务新增用户签到积分
     */
    public static function addScoreUserScore($spreadId, $userId, $newSignDay, $userInfo, $spreadRule,
                                             $userTodayScore, $extraScore)
    {
        Db::startTrans();
        $where = [
            'spread_id' => $spreadId,
            'user_id' => $userId,
            'status' => ['in', [spreadCardModel::STATUS_NORMAL, spreadCardModel::STATUS_FORBIDDEN]]
        ];
        if (!empty($newSignDay) && $newSignDay['day'] > 0) {
            if ($userTodayScore >= $spreadRule['today_get_score_limit']) {
                if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                    recordError('签到失败');
                    return false;
                }
                return $spreadRule['day_get_score'] + $extraScore;
            } else {
                if($spreadRule['day_get_score'] > 0 || $extraScore > 0){
                    if (!spreadPlatformUserService::incScore($where, $spreadRule['day_get_score'] + $extraScore)) {
                        recordError('增加用户积分失败');
                        Db::rollback();
                        return false;
                    }
                }
                if($spreadRule['day_get_score'] > 0){
                    if (!spreadCardScoreLogService::addUserSignScoreLog($spreadId, $userInfo, $spreadRule['day_get_score'])) {
                        recordError('增加用户签到赠送积分记录失败');
                        Db::rollback();
                        return false;
                    }
                }
                if($extraScore > 0){
                    if (!spreadCardScoreLogService::addUserSignExtraScoreLog($spreadId, $userInfo, $extraScore,
                        $newSignDay['day'], $spreadRule['day_get_score'])) {
                        recordError('增加用户连续签到赠送积分记录失败');
                        Db::rollback();
                        return false;
                    }
                }
                if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                    recordError('签到失败');
                    Db::rollback();
                    return false;
                }
            }
        }else{
            recordError('签到失败');
            return false;
        }
        Db::commit();
        return $spreadRule['day_get_score'] + $extraScore;
    }

    /*
     * todo  事务新增会员签到积分
     */
    public static function addScoreCardScore($spreadId, $userId, $newSignDay, $cardInfo, $spreadRule,
                                             $userTodayScore, $extraScore)
    {
        Db::startTrans();
        $where = [
            'spread_id' => $spreadId,
            'user_id' => $userId,
            'status' => ['in', [spreadCardModel::STATUS_NORMAL, spreadCardModel::STATUS_FORBIDDEN]]
        ];
        if (!empty($newSignDay) && $newSignDay['day'] > 0) {
            if ($userTodayScore >= $spreadRule['today_get_score_limit']) {
                if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                    recordError('签到失败');
                    return false;
                }
                return $spreadRule['day_get_score'] + $extraScore;
            } else {
                if($spreadRule['day_get_score'] > 0 || $extraScore > 0){
                    if (!spreadCardService::incScore($where, $spreadRule['day_get_score'] + $extraScore)) {
                        recordError('增加会员积分失败');
                        Db::rollback();
                        return false;
                    }
                }
                if($spreadRule['day_get_score'] > 0){
                    if (!spreadCardScoreLogService::addUserSignScoreLog($spreadId, $cardInfo, $spreadRule['day_get_score'])) {
                        recordError('增加会员签到赠送积分记录失败');
                        Db::rollback();
                        return false;
                    }
                }
                if($extraScore > 0){
                    if (!spreadCardScoreLogService::addUserSignExtraScoreLog($spreadId, $cardInfo, $extraScore,
                        $newSignDay['day'], $spreadRule['day_get_score'])) {
                        recordError('增加会员连续签到赠送积分记录失败');
                        Db::rollback();
                        return false;
                    }
                }
                if (!signCache::setUserSIgn($spreadId, $userId, $newSignDay)) {
                    recordError('签到失败');
                    Db::rollback();
                    return false;
                }
            }
        }else{
            recordError('签到失败');
            return false;
        }
        Db::commit();
        return $spreadRule['day_get_score'] + $extraScore;
    }

    /*
     *todo 获取用户的签到天数
     */
    public static function getUserSignDay($spreadId, $userId)
    {
        $newSignDay = [
            'day' => 0,
            'last_time' => 0
        ];
        if (empty($spreadId) || empty($userId)) {
            return $newSignDay;
        }
        //todo 查询缓存的签到天数与最后签到时间
        $oldSignDay = signCache::getUserSign($spreadId, $userId);
        //获取平台设置的积分规则设置
        $spreadRule = spreadCardScoreRuleService::getCardScoreRule($spreadId, true);
        //平台设置的签到天数 默认7
        $defaultDay = isset($spreadRule['cycle']) ? $spreadRule['cycle'] : 7;
        //todo 判断是有缓存的最后签到时间
        if (empty($oldSignDay) || $oldSignDay == false) {
            return $newSignDay;
        } else {
            //todo 判断缓存的最后时间是否已经超出了循环签到的周期
            if ($oldSignDay['last_time'] <= time() && $oldSignDay['last_time'] > (time() - $defaultDay * 24 * 60 *
                    60)) {
                return $oldSignDay;
            } else {
                return $newSignDay;
            }
        }
    }
}

redis缓存用户签到的天数和最后签到时间

<?php

namespace app\user\cache;

use app\platform\service\spreadCardScoreRuleService;
use think\cache\driver\Redis;

/**
 * All rights reserved.
 * 用户签到缓存
 */
class signCache
{

    const SPREAD_USER_SIGN_DAY = 'SPREAD:USER:SIGN:DAY';

    /*
     * 获取用户签到缓存
     * @param $unityId
     * @return string
     */
    private static function getSignCacheKey($spreadId, $userId)
    {
        return self::SPREAD_USER_SIGN_DAY . $spreadId . "_" . $userId;
    }

    /*
     * 获取平台签到缓存
     * @param $unityId
     * @return string
     */
    private static function getSpreadSignCacheKey($spreadId)
    {
        return self::SPREAD_USER_SIGN_DAY . $spreadId;
    }

    /*
     * 获取用户签到缓存
     * @param $unityId
     * @return mixed
     */
    public static function getUserSign($spreadId, $userId)
    {
        $key = self::getSignCacheKey($spreadId, $userId);
        return Redis::make()->get($key);
    }

    /*
     * 设置用户签到缓存 缓存一周
     * @param $unityId
     * @param array $data
     * @return bool
     */
    public static function setUserSign($spreadId, $userId, $day)
    {
        $key = self::getSignCacheKey($spreadId, $userId);
        //获取平台设置的积分规则设置
        $spreadRule = spreadCardScoreRuleService::getCardScoreRule($spreadId, true);
        $defaultDay = empty($spreadRule['cycle']) ? 7 : $spreadRule['cycle'];
        $time = strtotime(date('Y-m-d', strtotime($defaultDay . ' day'))) - time();
        return Redis::make()->set($key, $day, $time);
    }

    /*
     * 清除平台签到缓存
     * @return bool
     */
    public static function clearSpreadSign($spreadId)
    {
        $redis = new Redis();
        $key = self::getSpreadSignCacheKey($spreadId);
        $pattern = $key . "_*";
        $time = strtotime(date('Y-m-d', time()) . "23:59:59");
        $keys = $redis->getKeys($pattern);
        if ($keys) {
            foreach ($keys as $k) {
                $redis->expireAt($k, $time);
            }
        }
        return true;
    }
}

相关文章

网友评论

      本文标题:php+redise用户连续签到

      本文链接:https://www.haomeiwen.com/subject/ucfdcctx.html