业务需求:
![用户签到.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;
}
}
网友评论