|
|
@@ -0,0 +1,202 @@
|
|
|
+package shop.alien.job.second;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.xxl.job.core.handler.annotation.XxlJob;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import shop.alien.entity.second.SecondUserCreditDateRecord;
|
|
|
+import shop.alien.entity.second.SecondUserCreditRecord;
|
|
|
+import shop.alien.mapper.second.SecondUserCreditDateRecordMapper;
|
|
|
+import shop.alien.mapper.second.SecondUserCreditRecordMapper;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class SecondUserCreditJob {
|
|
|
+
|
|
|
+ private final SecondUserCreditRecordMapper secondUserCreditRecordMapper;
|
|
|
+ private final SecondUserCreditDateRecordMapper secondUserCreditDateRecordMapper;
|
|
|
+
|
|
|
+ @XxlJob("sumUserCredit")
|
|
|
+ public void sumUserCredit() {
|
|
|
+ log.info("开始执行用户积分任务");
|
|
|
+ // 计算每个用户从有数据的第一天开始,逐日计算积分
|
|
|
+ // 如果表中已经有该用户对应日期的数据,则跳过不计算
|
|
|
+ // 存到数据库second_user_credit_date_record表中
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取当天的开始时间(作为计算的结束日期)
|
|
|
+ Calendar calendar = Calendar.getInstance();
|
|
|
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
+ calendar.set(Calendar.MINUTE, 0);
|
|
|
+ calendar.set(Calendar.SECOND, 0);
|
|
|
+ calendar.set(Calendar.MILLISECOND, 0);
|
|
|
+ Date todayStart = calendar.getTime();
|
|
|
+
|
|
|
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
|
|
|
+ calendar.set(Calendar.MINUTE, 59);
|
|
|
+ calendar.set(Calendar.SECOND, 59);
|
|
|
+ calendar.set(Calendar.MILLISECOND, 999);
|
|
|
+ Date todayEnd = calendar.getTime();
|
|
|
+
|
|
|
+ log.info("开始处理用户积分,计算截止日期:{}", todayStart);
|
|
|
+
|
|
|
+ // 获取所有有积分记录的用户ID
|
|
|
+ LambdaQueryWrapper<SecondUserCreditRecord> userQuery = new LambdaQueryWrapper<>();
|
|
|
+ userQuery.select(SecondUserCreditRecord::getUserId)
|
|
|
+ .eq(SecondUserCreditRecord::getDeleteFlag, 0)
|
|
|
+ .groupBy(SecondUserCreditRecord::getUserId);
|
|
|
+ List<SecondUserCreditRecord> userRecords = secondUserCreditRecordMapper.selectList(userQuery);
|
|
|
+ Set<Integer> allUserIds = userRecords.stream()
|
|
|
+ .map(SecondUserCreditRecord::getUserId)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+
|
|
|
+ log.info("找到有积分记录的用户总数:{}", allUserIds.size());
|
|
|
+
|
|
|
+ int successCount = 0;
|
|
|
+ int skipCount = 0;
|
|
|
+ int failCount = 0;
|
|
|
+
|
|
|
+ // 为每个用户从有数据的第一天开始计算
|
|
|
+ for (Integer userId : allUserIds) {
|
|
|
+ try {
|
|
|
+ // 查找用户最早的积分记录日期
|
|
|
+ LambdaQueryWrapper<SecondUserCreditRecord> firstRecordQuery = new LambdaQueryWrapper<>();
|
|
|
+ firstRecordQuery.eq(SecondUserCreditRecord::getUserId, userId)
|
|
|
+ .eq(SecondUserCreditRecord::getDeleteFlag, 0)
|
|
|
+ .orderByAsc(SecondUserCreditRecord::getCreatedTime)
|
|
|
+ .last("LIMIT 1");
|
|
|
+ SecondUserCreditRecord firstRecord = secondUserCreditRecordMapper.selectOne(firstRecordQuery);
|
|
|
+
|
|
|
+ if (firstRecord == null || firstRecord.getCreatedTime() == null) {
|
|
|
+ log.debug("用户 {} 没有找到有效的积分记录,跳过", userId);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取用户最早记录日期(作为第一天)
|
|
|
+ Date firstRecordDate = firstRecord.getCreatedTime();
|
|
|
+ Calendar firstCal = Calendar.getInstance();
|
|
|
+ firstCal.setTime(firstRecordDate);
|
|
|
+ firstCal.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
+ firstCal.set(Calendar.MINUTE, 0);
|
|
|
+ firstCal.set(Calendar.SECOND, 0);
|
|
|
+ firstCal.set(Calendar.MILLISECOND, 0);
|
|
|
+ Date firstDate = firstCal.getTime();
|
|
|
+
|
|
|
+ log.debug("用户 {} 最早记录日期:{},开始逐日计算", userId, firstDate);
|
|
|
+
|
|
|
+ // 查询该用户已有的日期记录(避免重复计算)
|
|
|
+ LambdaQueryWrapper<SecondUserCreditDateRecord> existingQuery = new LambdaQueryWrapper<>();
|
|
|
+ existingQuery.eq(SecondUserCreditDateRecord::getUserId, userId)
|
|
|
+ .eq(SecondUserCreditDateRecord::getDeleteFlag, 0)
|
|
|
+ .ge(SecondUserCreditDateRecord::getRecordDate, firstDate)
|
|
|
+ .le(SecondUserCreditDateRecord::getRecordDate, todayEnd)
|
|
|
+ .orderByAsc(SecondUserCreditDateRecord::getRecordDate);
|
|
|
+ List<SecondUserCreditDateRecord> existingRecords = secondUserCreditDateRecordMapper.selectList(existingQuery);
|
|
|
+
|
|
|
+ // 构建已存在日期的Map(用于快速查找和判断)
|
|
|
+ Map<String, Integer> existingDatesMap = new HashMap<>();
|
|
|
+ for (SecondUserCreditDateRecord record : existingRecords) {
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ cal.setTime(record.getRecordDate());
|
|
|
+ String dateStr = String.format("%d-%02d-%02d",
|
|
|
+ cal.get(Calendar.YEAR),
|
|
|
+ cal.get(Calendar.MONTH) + 1,
|
|
|
+ cal.get(Calendar.DAY_OF_MONTH));
|
|
|
+ existingDatesMap.put(dateStr, record.getTotalPoints());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询该用户所有的积分记录(用于计算每天的总积分)
|
|
|
+ LambdaQueryWrapper<SecondUserCreditRecord> allRecordsQuery = new LambdaQueryWrapper<>();
|
|
|
+ allRecordsQuery.eq(SecondUserCreditRecord::getUserId, userId)
|
|
|
+ .eq(SecondUserCreditRecord::getDeleteFlag, 0)
|
|
|
+ .ge(SecondUserCreditRecord::getCreatedTime, firstDate)
|
|
|
+ .le(SecondUserCreditRecord::getCreatedTime, todayEnd)
|
|
|
+ .orderByAsc(SecondUserCreditRecord::getCreatedTime);
|
|
|
+ List<SecondUserCreditRecord> allUserRecords = secondUserCreditRecordMapper.selectList(allRecordsQuery);
|
|
|
+
|
|
|
+ // 将积分记录按日期分组
|
|
|
+ Map<String, Integer> dailyPointsMap = allUserRecords.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ record -> {
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ cal.setTime(record.getCreatedTime());
|
|
|
+ return String.format("%d-%02d-%02d",
|
|
|
+ cal.get(Calendar.YEAR),
|
|
|
+ cal.get(Calendar.MONTH) + 1,
|
|
|
+ cal.get(Calendar.DAY_OF_MONTH));
|
|
|
+ },
|
|
|
+ Collectors.summingInt(SecondUserCreditRecord::getPoints)
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 从第一天开始,逐日计算到当天
|
|
|
+ Calendar currentCal = Calendar.getInstance();
|
|
|
+ currentCal.setTime(firstDate);
|
|
|
+ Calendar endCal = Calendar.getInstance();
|
|
|
+ endCal.setTime(todayEnd);
|
|
|
+ endCal.set(Calendar.HOUR_OF_DAY, 23);
|
|
|
+ endCal.set(Calendar.MINUTE, 59);
|
|
|
+ endCal.set(Calendar.SECOND, 59);
|
|
|
+ endCal.set(Calendar.MILLISECOND, 999);
|
|
|
+
|
|
|
+ // 从第一天开始,逐日计算
|
|
|
+ int accumulatedPoints = 0;
|
|
|
+
|
|
|
+ while (!currentCal.after(endCal)) {
|
|
|
+ Date currentDate = currentCal.getTime();
|
|
|
+ String currentDateStr = String.format("%d-%02d-%02d",
|
|
|
+ currentCal.get(Calendar.YEAR),
|
|
|
+ currentCal.get(Calendar.MONTH) + 1,
|
|
|
+ currentCal.get(Calendar.DAY_OF_MONTH));
|
|
|
+
|
|
|
+ // 检查该日期是否已存在记录,如果存在则跳过
|
|
|
+ if (existingDatesMap.containsKey(currentDateStr)) {
|
|
|
+ // 已存在记录,更新累积积分为该日期的积分值,用于后续日期的计算
|
|
|
+ accumulatedPoints = existingDatesMap.get(currentDateStr);
|
|
|
+ skipCount++;
|
|
|
+ currentCal.add(Calendar.DAY_OF_YEAR, 1);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 当天有积分变动,累加到总积分
|
|
|
+ Integer dayPoints = dailyPointsMap.getOrDefault(currentDateStr, 0);
|
|
|
+ accumulatedPoints += dayPoints;
|
|
|
+
|
|
|
+ // 创建该日期的积分记录
|
|
|
+ SecondUserCreditDateRecord dateRecord = new SecondUserCreditDateRecord();
|
|
|
+ dateRecord.setUserId(userId);
|
|
|
+ dateRecord.setRecordDate(currentDate);
|
|
|
+ dateRecord.setTotalPoints(accumulatedPoints);
|
|
|
+ dateRecord.setDeleteFlag(0);
|
|
|
+ dateRecord.setCreatedTime(new Date());
|
|
|
+ dateRecord.setUpdatedTime(new Date());
|
|
|
+
|
|
|
+ secondUserCreditDateRecordMapper.insert(dateRecord);
|
|
|
+ successCount++;
|
|
|
+
|
|
|
+ log.debug("用户 {} 日期 {} 积分记录已生成,当天变动:{},累计总积分:{}",
|
|
|
+ userId, currentDateStr, dayPoints, accumulatedPoints);
|
|
|
+
|
|
|
+ // 移动到下一天
|
|
|
+ currentCal.add(Calendar.DAY_OF_YEAR, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理用户积分记录失败,userId={}", userId, e);
|
|
|
+ failCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("用户积分任务执行完成,成功:{},跳过:{},失败:{}", successCount, skipCount, failCount);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("执行用户积分任务失败", e);
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|