165 lines
5.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.designhub.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.designhub.entity.CheckIn;
import com.designhub.exception.BusinessException;
import com.designhub.mapper.CheckInMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;
/**
* 签到Service
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class CheckInService {
private final CheckInMapper checkInMapper;
private final NotificationService notificationService;
private final SystemConfigService systemConfigService;
/**
* 用户签到
*/
@Transactional(rollbackFor = Exception.class)
public CheckIn checkIn(Long userId) {
LocalDate today = LocalDate.now();
// 检查今天是否已签到
int count = checkInMapper.countTodayCheckIn(userId, today);
if (count > 0) {
throw new BusinessException("今天已经签到过了");
}
// 获取最近一次签到记录
CheckIn lastCheckIn = checkInMapper.getLatestCheckIn(userId);
int continuousDays = 1;
if (lastCheckIn != null) {
LocalDate lastDate = lastCheckIn.getCheckInDate();
long daysBetween = ChronoUnit.DAYS.between(lastDate, today);
if (daysBetween == 1) {
// 连续签到
continuousDays = lastCheckIn.getContinuousDays() + 1;
} else if (daysBetween > 1) {
// 中断了,重新开始
continuousDays = 1;
}
}
// 计算奖励积分(连续签到越多,奖励越高)
int baseScore = systemConfigService.getIntValue("incentive.daily_checkin_score", 5);
int rewardScore = calculateRewardScore(baseScore, continuousDays);
// 创建签到记录
CheckIn checkIn = new CheckIn();
checkIn.setUserId(userId);
checkIn.setCheckInDate(today);
checkIn.setContinuousDays(continuousDays);
checkIn.setRewardScore(rewardScore);
checkIn.setRemark("连续签到" + continuousDays + "天");
checkInMapper.insert(checkIn);
// TODO: 实际发放积分奖励
log.info("用户签到成功: userId={}, continuousDays={}, rewardScore={}", userId, continuousDays, rewardScore);
// 发送通知
String message = String.format("签到成功!连续签到%d天,获得%d积分", continuousDays, rewardScore);
if (continuousDays >= 7) {
message += "。坚持得真棒!🎉";
}
notificationService.sendSystemNotification(userId, "每日签到", message, "normal");
// 检查签到成就
if (continuousDays == 7 || continuousDays == 30 || continuousDays == 100) {
notificationService.sendSystemNotification(
userId,
"🏆 签到成就达成",
String.format("恭喜您达成连续签到%d天的成就!", continuousDays),
"high"
);
}
return checkIn;
}
/**
* 检查用户今天是否已签到
*/
public boolean hasCheckedInToday(Long userId) {
LocalDate today = LocalDate.now();
return checkInMapper.countTodayCheckIn(userId, today) > 0;
}
/**
* 获取用户签到记录
*/
public List<CheckIn> getUserCheckInHistory(Long userId, Integer limit) {
LambdaQueryWrapper<CheckIn> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CheckIn::getUserId, userId);
queryWrapper.orderByDesc(CheckIn::getCheckInDate);
if (limit != null && limit > 0) {
queryWrapper.last("LIMIT " + limit);
}
return checkInMapper.selectList(queryWrapper);
}
/**
* 获取用户连续签到天数
*/
public int getContinuousDays(Long userId) {
CheckIn lastCheckIn = checkInMapper.getLatestCheckIn(userId);
if (lastCheckIn != null) {
LocalDate today = LocalDate.now();
LocalDate lastDate = lastCheckIn.getCheckInDate();
long daysBetween = ChronoUnit.DAYS.between(lastDate, today);
if (daysBetween == 0) {
// 今天已签到
return lastCheckIn.getContinuousDays();
} else if (daysBetween == 1) {
// 今天还没签到,但昨天签了
return lastCheckIn.getContinuousDays();
}
}
return 0;
}
/**
* 获取用户总签到天数
*/
public long getTotalCheckInDays(Long userId) {
return checkInMapper.selectCount(
new LambdaQueryWrapper<CheckIn>()
.eq(CheckIn::getUserId, userId)
);
}
/**
* 计算奖励积分
* 基础分值 + 连续签到加成
*/
private int calculateRewardScore(int baseScore, int continuousDays) {
if (continuousDays >= 30) {
return baseScore * 3; // 30天以上,3倍奖励
} else if (continuousDays >= 14) {
return (int) (baseScore * 2.5); // 14天以上,2.5倍奖励
} else if (continuousDays >= 7) {
return baseScore * 2; // 7天以上,2倍奖励
} else if (continuousDays >= 3) {
return (int) (baseScore * 1.5); // 3天以上,1.5倍奖励
} else {
return baseScore; // 基础奖励
}
}
}