507 lines
18 KiB
Java
507 lines
18 KiB
Java
package com.designhub.service;
|
||
|
||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||
import com.designhub.common.ResultCode;
|
||
import com.designhub.entity.RewardRecord;
|
||
import com.designhub.entity.RewardRule;
|
||
import com.designhub.entity.Task;
|
||
import com.designhub.entity.User;
|
||
import com.designhub.exception.BusinessException;
|
||
import com.designhub.mapper.RewardRecordMapper;
|
||
import com.designhub.mapper.RewardRuleMapper;
|
||
import com.designhub.mapper.TaskMapper;
|
||
import com.designhub.mapper.UserMapper;
|
||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||
import com.fasterxml.jackson.core.type.TypeReference;
|
||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||
import lombok.RequiredArgsConstructor;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.scheduling.annotation.Scheduled;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
|
||
import java.time.LocalDateTime;
|
||
import java.time.temporal.TemporalAdjusters;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 自动奖励规则 Service
|
||
*/
|
||
@Slf4j
|
||
@Service
|
||
@RequiredArgsConstructor
|
||
public class RewardRuleService {
|
||
|
||
private final RewardRuleMapper rewardRuleMapper;
|
||
private final RewardRecordMapper rewardRecordMapper;
|
||
private final UserMapper userMapper;
|
||
private final TaskMapper taskMapper;
|
||
private final NotificationService notificationService;
|
||
private final ObjectMapper objectMapper;
|
||
|
||
/**
|
||
* 创建奖励规则
|
||
*/
|
||
@Transactional
|
||
public RewardRule createRule(RewardRule rule) {
|
||
rule.setEnabled(1);
|
||
rule.setDeleted(0);
|
||
rewardRuleMapper.insert(rule);
|
||
log.info("创建奖励规则成功: id={}, name={}", rule.getId(), rule.getName());
|
||
return rule;
|
||
}
|
||
|
||
/**
|
||
* 更新奖励规则
|
||
*/
|
||
@Transactional
|
||
public RewardRule updateRule(Long id, RewardRule rule) {
|
||
RewardRule existing = rewardRuleMapper.selectById(id);
|
||
if (existing == null) {
|
||
throw new BusinessException(ResultCode.NOT_FOUND, "规则不存在");
|
||
}
|
||
rule.setId(id);
|
||
rewardRuleMapper.updateById(rule);
|
||
return rewardRuleMapper.selectById(id);
|
||
}
|
||
|
||
/**
|
||
* 启用/禁用规则
|
||
*/
|
||
@Transactional
|
||
public void toggleRule(Long id, boolean enabled) {
|
||
RewardRule rule = rewardRuleMapper.selectById(id);
|
||
if (rule == null) {
|
||
throw new BusinessException(ResultCode.NOT_FOUND, "规则不存在");
|
||
}
|
||
rule.setEnabled(enabled ? 1 : 0);
|
||
rewardRuleMapper.updateById(rule);
|
||
}
|
||
|
||
/**
|
||
* 删除规则
|
||
*/
|
||
@Transactional
|
||
public void deleteRule(Long id) {
|
||
rewardRuleMapper.deleteById(id);
|
||
}
|
||
|
||
/**
|
||
* 获取规则列表
|
||
*/
|
||
public IPage<RewardRule> getRuleList(Integer page, Integer pageSize, String ruleType) {
|
||
Page<RewardRule> pageParam = new Page<>(page, pageSize);
|
||
LambdaQueryWrapper<RewardRule> wrapper = new LambdaQueryWrapper<>();
|
||
|
||
if (ruleType != null && !ruleType.isEmpty()) {
|
||
wrapper.eq(RewardRule::getRuleType, ruleType);
|
||
}
|
||
|
||
wrapper.orderByDesc(RewardRule::getPriority)
|
||
.orderByDesc(RewardRule::getCreateTime);
|
||
return rewardRuleMapper.selectPage(pageParam, wrapper);
|
||
}
|
||
|
||
/**
|
||
* 获取规则详情
|
||
*/
|
||
public RewardRule getRuleById(Long id) {
|
||
RewardRule rule = rewardRuleMapper.selectById(id);
|
||
if (rule == null) {
|
||
throw new BusinessException(ResultCode.NOT_FOUND, "规则不存在");
|
||
}
|
||
return rule;
|
||
}
|
||
|
||
/**
|
||
* 获取所有启用的规则
|
||
*/
|
||
public List<RewardRule> getEnabledRules() {
|
||
LambdaQueryWrapper<RewardRule> wrapper = new LambdaQueryWrapper<>();
|
||
wrapper.eq(RewardRule::getEnabled, 1);
|
||
return rewardRuleMapper.selectList(wrapper);
|
||
}
|
||
|
||
/**
|
||
* 任务完成时触发检查
|
||
*/
|
||
@Transactional
|
||
public void onTaskCompleted(Task task, User user) {
|
||
// 获取任务相关的奖励规则
|
||
LambdaQueryWrapper<RewardRule> wrapper = new LambdaQueryWrapper<>();
|
||
wrapper.eq(RewardRule::getEnabled, 1)
|
||
.eq(RewardRule::getRuleType, "task");
|
||
List<RewardRule> rules = rewardRuleMapper.selectList(wrapper);
|
||
|
||
for (RewardRule rule : rules) {
|
||
if (checkRuleCondition(rule, user, task)) {
|
||
applyReward(rule, user);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 好评时触发检查
|
||
*/
|
||
@Transactional
|
||
public void onTaskRated(Task task, User user, Integer rating) {
|
||
if (rating == null || rating < 5) return;
|
||
|
||
// 获取好评相关的奖励规则
|
||
LambdaQueryWrapper<RewardRule> wrapper = new LambdaQueryWrapper<>();
|
||
wrapper.eq(RewardRule::getEnabled, 1)
|
||
.eq(RewardRule::getRuleType, "rating");
|
||
List<RewardRule> rules = rewardRuleMapper.selectList(wrapper);
|
||
|
||
for (RewardRule rule : rules) {
|
||
if (checkRuleCondition(rule, user, task)) {
|
||
applyReward(rule, user);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查规则条件是否满足
|
||
*/
|
||
private boolean checkRuleCondition(RewardRule rule, User user, Task task) {
|
||
try {
|
||
Map<String, Object> condition = objectMapper.readValue(
|
||
rule.getTriggerCondition(), new TypeReference<Map<String, Object>>() {});
|
||
|
||
String type = (String) condition.get("type");
|
||
String operator = (String) condition.get("operator");
|
||
int targetValue = ((Number) condition.get("value")).intValue();
|
||
|
||
int actualValue = 0;
|
||
|
||
switch (type) {
|
||
case "task_count":
|
||
// 统计用户完成任务数
|
||
actualValue = countUserTasks(user.getId(), "completed");
|
||
break;
|
||
case "rating":
|
||
// 任务评分
|
||
actualValue = task.getRating() != null ? task.getRating() : 0;
|
||
break;
|
||
case "five_star_count":
|
||
// 统计五星好评数
|
||
actualValue = countUserFiveStarTasks(user.getId());
|
||
break;
|
||
default:
|
||
return false;
|
||
}
|
||
|
||
return compareValue(actualValue, operator, targetValue);
|
||
} catch (JsonProcessingException e) {
|
||
log.error("解析规则条件失败", e);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 值比较
|
||
*/
|
||
private boolean compareValue(int actual, String operator, int target) {
|
||
switch (operator) {
|
||
case ">=": return actual >= target;
|
||
case ">": return actual > target;
|
||
case "<=": return actual <= target;
|
||
case "<": return actual < target;
|
||
case "==": return actual == target;
|
||
default: return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 统计用户任务数
|
||
*/
|
||
private int countUserTasks(Long userId, String status) {
|
||
LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();
|
||
wrapper.eq(Task::getReceiverId, userId)
|
||
.eq(Task::getStatus, status);
|
||
Long count = taskMapper.selectCount(wrapper);
|
||
return count != null ? count.intValue() : 0;
|
||
}
|
||
|
||
/**
|
||
* 统计用户五星好评数
|
||
*/
|
||
private int countUserFiveStarTasks(Long userId) {
|
||
LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();
|
||
wrapper.eq(Task::getReceiverId, userId)
|
||
.eq(Task::getStatus, "completed")
|
||
.ge(Task::getRating, 5);
|
||
Long count = taskMapper.selectCount(wrapper);
|
||
return count != null ? count.intValue() : 0;
|
||
}
|
||
|
||
/**
|
||
* 应用奖励
|
||
*/
|
||
@Transactional
|
||
public void applyReward(RewardRule rule, User user) {
|
||
applyReward(rule, user, null);
|
||
}
|
||
|
||
/**
|
||
* 应用奖励(带触发数据)
|
||
*/
|
||
@Transactional
|
||
public void applyReward(RewardRule rule, User user, Object triggerData) {
|
||
if (rule.getRewardScore() != null && rule.getRewardScore() > 0) {
|
||
int currentScore = user.getScore() != null ? user.getScore() : 0;
|
||
user.setScore(currentScore + rule.getRewardScore());
|
||
userMapper.updateById(user);
|
||
|
||
// 记录奖励发放
|
||
try {
|
||
Map<String, Object> rewardValue = new java.util.HashMap<>();
|
||
rewardValue.put("score", rule.getRewardScore());
|
||
|
||
RewardRecord record = new RewardRecord();
|
||
record.setUserId(user.getId());
|
||
record.setRuleId(rule.getId());
|
||
record.setRuleName(rule.getName());
|
||
record.setRewardType("score");
|
||
record.setRewardValue(objectMapper.writeValueAsString(rewardValue));
|
||
if (triggerData != null) {
|
||
record.setTriggerData(objectMapper.writeValueAsString(triggerData));
|
||
}
|
||
record.setCreateTime(LocalDateTime.now());
|
||
rewardRecordMapper.insert(record);
|
||
} catch (Exception e) {
|
||
log.error("记录奖励发放失败", e);
|
||
}
|
||
|
||
// 更新规则触发次数
|
||
rule.setTriggerCount(rule.getTriggerCount() != null ? rule.getTriggerCount() + 1 : 1);
|
||
rewardRuleMapper.updateById(rule);
|
||
|
||
// 发送通知
|
||
notificationService.sendNotification(
|
||
user.getId(),
|
||
"获得奖励",
|
||
String.format("恭喜!根据「%s」规则,您获得 %d 积分奖励!", rule.getName(), rule.getRewardScore()),
|
||
"reward",
|
||
rule.getId()
|
||
);
|
||
|
||
log.info("用户获得自动奖励: userId={}, ruleId={}, score={}",
|
||
user.getId(), rule.getId(), rule.getRewardScore());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 定时任务:执行每日奖励规则
|
||
*/
|
||
@Scheduled(cron = "0 0 23 * * ?") // 每天23点执行
|
||
@Transactional
|
||
public void executeDailyRewards() {
|
||
log.info("开始执行每日自动奖励规则");
|
||
executePeriodicRewards("daily");
|
||
}
|
||
|
||
/**
|
||
* 定时任务:执行每周奖励规则
|
||
*/
|
||
@Scheduled(cron = "0 0 22 ? * SUN") // 每周日22点执行
|
||
@Transactional
|
||
public void executeWeeklyRewards() {
|
||
log.info("开始执行每周自动奖励规则");
|
||
executePeriodicRewards("weekly");
|
||
}
|
||
|
||
/**
|
||
* 定时任务:执行每月奖励规则
|
||
*/
|
||
@Scheduled(cron = "0 0 21 L * ?") // 每月最后一天21点执行
|
||
@Transactional
|
||
public void executeMonthlyRewards() {
|
||
log.info("开始执行每月自动奖励规则");
|
||
executePeriodicRewards("monthly");
|
||
}
|
||
|
||
/**
|
||
* 执行周期性奖励
|
||
*/
|
||
private void executePeriodicRewards(String ruleType) {
|
||
LambdaQueryWrapper<RewardRule> wrapper = new LambdaQueryWrapper<>();
|
||
wrapper.eq(RewardRule::getEnabled, 1)
|
||
.eq(RewardRule::getRuleType, ruleType);
|
||
List<RewardRule> rules = rewardRuleMapper.selectList(wrapper);
|
||
|
||
for (RewardRule rule : rules) {
|
||
try {
|
||
executePeriodicRule(rule);
|
||
rule.setLastExecuteTime(LocalDateTime.now());
|
||
rewardRuleMapper.updateById(rule);
|
||
} catch (Exception e) {
|
||
log.error("执行奖励规则失败: ruleId={}", rule.getId(), e);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 执行单个周期性规则
|
||
*/
|
||
private void executePeriodicRule(RewardRule rule) {
|
||
// 获取符合范围的用户
|
||
List<User> users = getUsersByScope(rule);
|
||
|
||
LocalDateTime startTime = getStartTimeByRuleType(rule.getRuleType());
|
||
LocalDateTime endTime = LocalDateTime.now();
|
||
|
||
for (User user : users) {
|
||
// 检查用户在该周期内是否满足条件
|
||
if (checkPeriodicCondition(rule, user, startTime, endTime)) {
|
||
applyReward(rule, user);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 根据范围获取用户列表
|
||
*/
|
||
private List<User> getUsersByScope(RewardRule rule) {
|
||
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
|
||
wrapper.eq(User::getDeleted, 0);
|
||
|
||
if ("designer".equals(rule.getScope())) {
|
||
// 获取设计师角色的用户
|
||
// 简化处理,获取所有用户
|
||
} else if ("department".equals(rule.getScope()) && rule.getScopeDeptIds() != null) {
|
||
try {
|
||
List<Long> deptIds = objectMapper.readValue(
|
||
rule.getScopeDeptIds(), new TypeReference<List<Long>>() {});
|
||
wrapper.in(User::getDeptId, deptIds);
|
||
} catch (JsonProcessingException e) {
|
||
log.error("解析部门ID失败", e);
|
||
}
|
||
}
|
||
|
||
return userMapper.selectList(wrapper);
|
||
}
|
||
|
||
/**
|
||
* 获取周期开始时间
|
||
*/
|
||
private LocalDateTime getStartTimeByRuleType(String ruleType) {
|
||
LocalDateTime now = LocalDateTime.now();
|
||
switch (ruleType) {
|
||
case "daily":
|
||
return now.toLocalDate().atStartOfDay();
|
||
case "weekly":
|
||
return now.with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY))
|
||
.toLocalDate().atStartOfDay();
|
||
case "monthly":
|
||
return now.with(TemporalAdjusters.firstDayOfMonth())
|
||
.toLocalDate().atStartOfDay();
|
||
default:
|
||
return now.minusDays(1);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查周期性条件
|
||
*/
|
||
private boolean checkPeriodicCondition(RewardRule rule, User user,
|
||
LocalDateTime startTime, LocalDateTime endTime) {
|
||
try {
|
||
Map<String, Object> condition = objectMapper.readValue(
|
||
rule.getTriggerCondition(), new TypeReference<Map<String, Object>>() {});
|
||
|
||
String type = (String) condition.get("type");
|
||
String operator = (String) condition.get("operator");
|
||
int targetValue = ((Number) condition.get("value")).intValue();
|
||
|
||
int actualValue = 0;
|
||
|
||
switch (type) {
|
||
case "task_count":
|
||
// 统计周期内完成任务数
|
||
LambdaQueryWrapper<Task> taskWrapper = new LambdaQueryWrapper<>();
|
||
taskWrapper.eq(Task::getReceiverId, user.getId())
|
||
.eq(Task::getStatus, "completed")
|
||
.ge(Task::getCompleteTime, startTime)
|
||
.le(Task::getCompleteTime, endTime);
|
||
Long taskCount = taskMapper.selectCount(taskWrapper);
|
||
actualValue = taskCount != null ? taskCount.intValue() : 0;
|
||
break;
|
||
case "five_star_count":
|
||
// 统计周期内五星好评数
|
||
LambdaQueryWrapper<Task> fiveStarWrapper = new LambdaQueryWrapper<>();
|
||
fiveStarWrapper.eq(Task::getReceiverId, user.getId())
|
||
.eq(Task::getStatus, "completed")
|
||
.ge(Task::getRating, 5)
|
||
.ge(Task::getCompleteTime, startTime)
|
||
.le(Task::getCompleteTime, endTime);
|
||
Long fiveStarCount = taskMapper.selectCount(fiveStarWrapper);
|
||
actualValue = fiveStarCount != null ? fiveStarCount.intValue() : 0;
|
||
break;
|
||
default:
|
||
return false;
|
||
}
|
||
|
||
return compareValue(actualValue, operator, targetValue);
|
||
} catch (JsonProcessingException e) {
|
||
log.error("解析规则条件失败", e);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 初始化默认奖励规则
|
||
*/
|
||
@Transactional
|
||
public void initDefaultRules() {
|
||
// 检查是否已有规则
|
||
if (rewardRuleMapper.selectCount(null) > 0) {
|
||
return;
|
||
}
|
||
|
||
// 每日完成5个任务奖励
|
||
RewardRule dailyRule = new RewardRule();
|
||
dailyRule.setName("每日任务达人");
|
||
dailyRule.setDescription("每天完成5个任务,额外奖励20积分");
|
||
dailyRule.setRuleType("daily");
|
||
dailyRule.setTriggerCondition("{\"type\":\"task_count\",\"operator\":\">=\",\"value\":5}");
|
||
dailyRule.setRewardType("score");
|
||
dailyRule.setRewardScore(20);
|
||
dailyRule.setScope("all");
|
||
dailyRule.setEnabled(1);
|
||
dailyRule.setPriority(100);
|
||
rewardRuleMapper.insert(dailyRule);
|
||
|
||
// 每周完成20个任务奖励
|
||
RewardRule weeklyRule = new RewardRule();
|
||
weeklyRule.setName("每周效率之星");
|
||
weeklyRule.setDescription("每周完成20个任务,额外奖励100积分");
|
||
weeklyRule.setRuleType("weekly");
|
||
weeklyRule.setTriggerCondition("{\"type\":\"task_count\",\"operator\":\">=\",\"value\":20}");
|
||
weeklyRule.setRewardType("score");
|
||
weeklyRule.setRewardScore(100);
|
||
weeklyRule.setScope("all");
|
||
weeklyRule.setEnabled(1);
|
||
weeklyRule.setPriority(90);
|
||
rewardRuleMapper.insert(weeklyRule);
|
||
|
||
// 五星好评奖励
|
||
RewardRule ratingRule = new RewardRule();
|
||
ratingRule.setName("五星好评奖励");
|
||
ratingRule.setDescription("获得五星好评,奖励10积分");
|
||
ratingRule.setRuleType("rating");
|
||
ratingRule.setTriggerCondition("{\"type\":\"rating\",\"operator\":\">=\",\"value\":5}");
|
||
ratingRule.setRewardType("score");
|
||
ratingRule.setRewardScore(10);
|
||
ratingRule.setScope("all");
|
||
ratingRule.setEnabled(1);
|
||
ratingRule.setPriority(80);
|
||
rewardRuleMapper.insert(ratingRule);
|
||
|
||
log.info("初始化默认奖励规则完成");
|
||
}
|
||
}
|