|
|
@@ -13,14 +13,13 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
import java.time.LocalDateTime;
|
|
|
-import java.time.YearMonth;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
/**
|
|
|
* 签到服务实现类
|
|
|
- * 使用Redis的Bitmap实现签到功能
|
|
|
+ * 支持普通用户和红娘分开签到统计
|
|
|
*/
|
|
|
@Service
|
|
|
public class CheckinServiceImpl implements CheckinService {
|
|
|
@@ -37,34 +36,40 @@ public class CheckinServiceImpl implements CheckinService {
|
|
|
private static final String CHECKIN_KEY_PREFIX = "checkin:";
|
|
|
|
|
|
/**
|
|
|
- * 生成Redis Key: checkin:userId:yyyyMM
|
|
|
+ * 生成Redis Key: checkin:userType:userId:yyyyMM
|
|
|
*/
|
|
|
- private String getCheckinKey(Long userId, LocalDate date) {
|
|
|
+ private String getCheckinKey(Long userId, Integer userType, LocalDate date) {
|
|
|
String yearMonth = date.format(DateTimeFormatter.ofPattern("yyyyMM"));
|
|
|
- return CHECKIN_KEY_PREFIX + userId + ":" + yearMonth;
|
|
|
+ return CHECKIN_KEY_PREFIX + userType + ":" + userId + ":" + yearMonth;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- @Transactional(rollbackFor = Exception.class)
|
|
|
public CheckinInfoVO checkin(Long userId) {
|
|
|
+ // 默认普通用户签到
|
|
|
+ return checkin(userId, CheckinRecord.USER_TYPE_NORMAL);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public CheckinInfoVO checkin(Long userId, Integer userType) {
|
|
|
LocalDate today = LocalDate.now();
|
|
|
|
|
|
- // 检查今天是否已签到(从数据库查询,更准确)
|
|
|
- CheckinRecord existRecord = checkinRecordMapper.selectByUserIdAndDate(userId, today);
|
|
|
+ // 检查今天是否已签到(区分用户类型)
|
|
|
+ CheckinRecord existRecord = checkinRecordMapper.selectByUserIdAndTypeAndDate(userId, userType, today);
|
|
|
if (existRecord != null) {
|
|
|
throw new RuntimeException("今日已签到");
|
|
|
}
|
|
|
|
|
|
// 使用Redis Bitmap记录签到
|
|
|
- String key = getCheckinKey(userId, today);
|
|
|
+ String key = getCheckinKey(userId, userType, today);
|
|
|
int dayOfMonth = today.getDayOfMonth();
|
|
|
redisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
|
|
|
|
|
|
- // 计算连续签到天数
|
|
|
- Integer continuousDays = calculateContinuousDays(userId);
|
|
|
+ // 计算连续签到天数(区分用户类型)
|
|
|
+ Integer continuousDays = calculateContinuousDays(userId, userType);
|
|
|
|
|
|
- // 计算累计签到天数
|
|
|
- Integer totalDays = calculateTotalDays(userId);
|
|
|
+ // 计算累计签到天数(区分用户类型)
|
|
|
+ Integer totalDays = calculateTotalDays(userId, userType);
|
|
|
|
|
|
// 判断是否获得奖励
|
|
|
Integer rewardType = getRewardType(continuousDays);
|
|
|
@@ -73,6 +78,7 @@ public class CheckinServiceImpl implements CheckinService {
|
|
|
// 保存签到记录到数据库
|
|
|
CheckinRecord record = new CheckinRecord();
|
|
|
record.setUserId(userId);
|
|
|
+ record.setUserType(userType);
|
|
|
record.setCheckinDate(today);
|
|
|
record.setContinuousDays(continuousDays);
|
|
|
record.setTotalDays(totalDays);
|
|
|
@@ -81,8 +87,8 @@ public class CheckinServiceImpl implements CheckinService {
|
|
|
record.setCreateTime(LocalDateTime.now());
|
|
|
checkinRecordMapper.insert(record);
|
|
|
|
|
|
- // 如果获得VIP奖励,自动发放
|
|
|
- if (rewardType > 0) {
|
|
|
+ // 如果获得VIP奖励,自动发放(仅普通用户)
|
|
|
+ if (rewardType > 0 && userType == CheckinRecord.USER_TYPE_NORMAL) {
|
|
|
Integer vipDays = getVipDays(rewardType);
|
|
|
if (vipDays > 0) {
|
|
|
vipService.grantVip(userId, vipDays, "签到奖励-连续" + continuousDays + "天");
|
|
|
@@ -90,29 +96,35 @@ public class CheckinServiceImpl implements CheckinService {
|
|
|
}
|
|
|
|
|
|
// 返回签到信息
|
|
|
- return getCheckinInfo(userId);
|
|
|
+ return getCheckinInfo(userId, userType);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public CheckinInfoVO getCheckinInfo(Long userId) {
|
|
|
+ // 默认普通用户
|
|
|
+ return getCheckinInfo(userId, CheckinRecord.USER_TYPE_NORMAL);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public CheckinInfoVO getCheckinInfo(Long userId, Integer userType) {
|
|
|
LocalDate today = LocalDate.now();
|
|
|
|
|
|
CheckinInfoVO vo = new CheckinInfoVO();
|
|
|
|
|
|
- // 计算连续签到天数
|
|
|
- Integer continuousDays = calculateContinuousDays(userId);
|
|
|
+ // 计算连续签到天数(区分用户类型)
|
|
|
+ Integer continuousDays = calculateContinuousDays(userId, userType);
|
|
|
vo.setContinuousDays(continuousDays);
|
|
|
|
|
|
- // 计算累计签到天数
|
|
|
- Integer totalDays = calculateTotalDays(userId);
|
|
|
+ // 计算累计签到天数(区分用户类型)
|
|
|
+ Integer totalDays = calculateTotalDays(userId, userType);
|
|
|
vo.setTotalDays(totalDays);
|
|
|
|
|
|
- // 检查今天是否已签到(从数据库查询)
|
|
|
- CheckinRecord todayRecord = checkinRecordMapper.selectByUserIdAndDate(userId, today);
|
|
|
+ // 检查今天是否已签到(区分用户类型)
|
|
|
+ CheckinRecord todayRecord = checkinRecordMapper.selectByUserIdAndTypeAndDate(userId, userType, today);
|
|
|
vo.setTodayChecked(todayRecord != null);
|
|
|
|
|
|
- // 获取本月已签到日期
|
|
|
- List<String> checkedDates = getMonthCheckedDates(userId, today);
|
|
|
+ // 获取本月已签到日期(区分用户类型)
|
|
|
+ List<String> checkedDates = getMonthCheckedDates(userId, userType, today);
|
|
|
vo.setCheckedDates(checkedDates);
|
|
|
|
|
|
// 设置奖励信息
|
|
|
@@ -123,16 +135,16 @@ public class CheckinServiceImpl implements CheckinService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 计算连续签到天数(从数据库查询)
|
|
|
+ * 计算连续签到天数(区分用户类型)
|
|
|
*/
|
|
|
- private Integer calculateContinuousDays(Long userId) {
|
|
|
+ private Integer calculateContinuousDays(Long userId, Integer userType) {
|
|
|
LocalDate today = LocalDate.now();
|
|
|
int continuousDays = 0;
|
|
|
LocalDate checkDate = today;
|
|
|
|
|
|
// 从今天往前推,检查连续签到
|
|
|
for (int i = 0; i < 365; i++) {
|
|
|
- CheckinRecord record = checkinRecordMapper.selectByUserIdAndDate(userId, checkDate);
|
|
|
+ CheckinRecord record = checkinRecordMapper.selectByUserIdAndTypeAndDate(userId, userType, checkDate);
|
|
|
if (record != null) {
|
|
|
continuousDays++;
|
|
|
checkDate = checkDate.minusDays(1);
|
|
|
@@ -145,24 +157,24 @@ public class CheckinServiceImpl implements CheckinService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 计算累计签到天数
|
|
|
+ * 计算累计签到天数(区分用户类型)
|
|
|
*/
|
|
|
- private Integer calculateTotalDays(Long userId) {
|
|
|
- // 从数据库查询累计天数(更准确)
|
|
|
- Integer totalDays = checkinRecordMapper.countTotalDays(userId);
|
|
|
+ private Integer calculateTotalDays(Long userId, Integer userType) {
|
|
|
+ Integer totalDays = checkinRecordMapper.countTotalDaysByType(userId, userType);
|
|
|
return totalDays == null ? 0 : totalDays;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取本月已签到的日期列表(从数据库查询,确保数据一致性)
|
|
|
+ * 获取本月已签到的日期列表(区分用户类型)
|
|
|
*/
|
|
|
- private List<String> getMonthCheckedDates(Long userId, LocalDate date) {
|
|
|
+ private List<String> getMonthCheckedDates(Long userId, Integer userType, LocalDate date) {
|
|
|
List<String> dates = new ArrayList<>();
|
|
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
|
|
- // 从数据库查询本月的签到记录
|
|
|
- List<LocalDate> checkinDates = checkinRecordMapper.selectMonthCheckinDates(
|
|
|
+ // 从数据库查询本月的签到记录(区分用户类型)
|
|
|
+ List<LocalDate> checkinDates = checkinRecordMapper.selectMonthCheckinDatesByType(
|
|
|
userId,
|
|
|
+ userType,
|
|
|
date.getYear(),
|
|
|
date.getMonthValue()
|
|
|
);
|
|
|
@@ -178,7 +190,7 @@ public class CheckinServiceImpl implements CheckinService {
|
|
|
|
|
|
/**
|
|
|
* 根据连续签到天数判断奖励类型
|
|
|
- * 0: 无奖励, 1: 1天VIP, 2: 3天VIP, 3: 7天VIP
|
|
|
+ * 0: 无奖励, 1: 1天会员, 2: 3天会员, 3: 7天会员
|
|
|
*/
|
|
|
private Integer getRewardType(Integer continuousDays) {
|
|
|
if (continuousDays == 7) {
|
|
|
@@ -196,9 +208,9 @@ public class CheckinServiceImpl implements CheckinService {
|
|
|
*/
|
|
|
private Integer getVipDays(Integer rewardType) {
|
|
|
switch (rewardType) {
|
|
|
- case 1: return 1;
|
|
|
- case 2: return 3;
|
|
|
- case 3: return 7;
|
|
|
+ case 1: return 1; // 签到7天给1天会员
|
|
|
+ case 2: return 3; // 签到14天给3天会员
|
|
|
+ case 3: return 7; // 签到30天给7天会员
|
|
|
default: return 0;
|
|
|
}
|
|
|
}
|
|
|
@@ -209,22 +221,21 @@ public class CheckinServiceImpl implements CheckinService {
|
|
|
private List<CheckinRewardVO> buildRewards(Integer continuousDays) {
|
|
|
List<CheckinRewardVO> rewards = new ArrayList<>();
|
|
|
|
|
|
- // 7天VIP奖励
|
|
|
+ // 7天会员奖励
|
|
|
boolean received7 = continuousDays >= 7;
|
|
|
boolean isCurrent7 = continuousDays < 7;
|
|
|
- rewards.add(new CheckinRewardVO(7, "👑", "VIP+1天", received7, isCurrent7));
|
|
|
+ rewards.add(new CheckinRewardVO(7, "👑", "会员+1天", received7, isCurrent7));
|
|
|
|
|
|
- // 14天VIP奖励
|
|
|
+ // 14天会员奖励
|
|
|
boolean received14 = continuousDays >= 14;
|
|
|
boolean isCurrent14 = continuousDays >= 7 && continuousDays < 14;
|
|
|
- rewards.add(new CheckinRewardVO(14, "💎", "VIP+3天", received14, isCurrent14));
|
|
|
+ rewards.add(new CheckinRewardVO(14, "💎", "会员+3天", received14, isCurrent14));
|
|
|
|
|
|
- // 30天VIP奖励
|
|
|
+ // 30天会员奖励
|
|
|
boolean received30 = continuousDays >= 30;
|
|
|
boolean isCurrent30 = continuousDays >= 14 && continuousDays < 30;
|
|
|
- rewards.add(new CheckinRewardVO(30, "🏆", "VIP+7天", received30, isCurrent30));
|
|
|
+ rewards.add(new CheckinRewardVO(30, "🏆", "会员+7天", received30, isCurrent30));
|
|
|
|
|
|
return rewards;
|
|
|
}
|
|
|
}
|
|
|
-
|