浏览代码

feat(second): 新增用户积分定时任务及信用分记录查询功能

- 新增SecondUserCreditJob类,实现每日用户积分统计任务
- 实现根据用户ID查询信用分记录接口,支持时间范围筛选
- 新增用户观看学习视频后增加积分的功能逻辑
- 创建SecondUserCreditDateRecord实体类及对应Mapper
- 新增SecondUserCreditRecordListVo用于信用分记录数据封装
- 完善相关服务层方法,支持积分记录与日期维度积分查询
- 优化用户积分更新逻辑,确保积分计算准确性
fcw 2 天之前
父节点
当前提交
0549d37667

+ 58 - 0
alien-entity/src/main/java/shop/alien/entity/second/SecondUserCreditDateRecord.java

@@ -0,0 +1,58 @@
+package shop.alien.entity.second;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 用户积分日期记录表
+ */
+@Data
+@JsonInclude
+@TableName("second_user_credit_date_record")
+public class SecondUserCreditDateRecord implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("user_id")
+    private Integer userId;
+
+    @TableField("record_date")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    @ApiModelProperty(value = "记录日期")
+    private Date recordDate;
+
+    @TableField("total_points")
+    @ApiModelProperty(value = "当日总积分")
+    private Integer totalPoints;
+
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(value = "创建时间")
+    private Date createdTime;
+
+    @TableField(value = "created_user_id", fill = FieldFill.INSERT)
+    @ApiModelProperty(value = "创建人ID")
+    private Integer createdUserId;
+
+    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(value = "修改时间")
+    private Date updatedTime;
+
+    @TableField(value = "updated_user_id", fill = FieldFill.INSERT_UPDATE)
+    @ApiModelProperty(value = "修改人ID")
+    private Integer updatedUserId;
+}
+

+ 27 - 0
alien-entity/src/main/java/shop/alien/entity/second/vo/SecondUserCreditRecordListVo.java

@@ -0,0 +1,27 @@
+package shop.alien.entity.second.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import shop.alien.entity.second.SecondUserCreditDateRecord;
+import shop.alien.entity.second.SecondUserCreditRecord;
+
+import java.util.List;
+
+/**
+ * 用户信用分记录列表VO
+ */
+@Data
+@JsonInclude
+public class SecondUserCreditRecordListVo {
+
+    @ApiModelProperty(value = "用户积分")
+    private Integer userPoints;
+
+    @ApiModelProperty(value = "信用分记录列表")
+    private List<SecondUserCreditRecord> recordsChange;
+
+    @ApiModelProperty(value = "日期积分记录列表")
+    private List<SecondUserCreditDateRecord> dateRecords;
+}
+

+ 14 - 0
alien-entity/src/main/java/shop/alien/mapper/second/SecondUserCreditDateRecordMapper.java

@@ -0,0 +1,14 @@
+package shop.alien.mapper.second;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import shop.alien.entity.second.SecondUserCreditDateRecord;
+
+import java.util.Date;
+
+/**
+ * 用户积分日期记录映射器
+ */
+public interface SecondUserCreditDateRecordMapper extends BaseMapper<SecondUserCreditDateRecord> {
+
+}
+

+ 202 - 0
alien-job/src/main/java/shop/alien/job/second/SecondUserCreditJob.java

@@ -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;
+        }
+    }
+
+}

+ 27 - 0
alien-second/src/main/java/shop/alien/second/controller/SecondUserCreditRecordController.java

@@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.second.SecondUserCreditRecord;
+import shop.alien.entity.second.vo.SecondUserCreditRecordListVo;
 import shop.alien.second.service.SecondUserCreditRecordService;
 
 import java.util.List;
@@ -39,6 +40,19 @@ public class SecondUserCreditRecordController {
             return R.fail("获取用户积分记录列表失败");
         }
     }
+
+    @ApiOperation("根据用户ID查询用户信用分记录")
+    @ApiOperationSupport(order = 5)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "timeRange", value = "时间范围:1-近一周,2-近一个月,3-近一年", dataType = "Integer", paramType = "query")
+    })
+    @GetMapping("/getByUserId")
+    public R<SecondUserCreditRecordListVo> getByUserId(
+            @RequestParam Integer userId,
+            @RequestParam(required = false) Integer timeRange) {
+        return secondUserPointsRecordService.getByUserId(userId, timeRange);
+    }
     
     @ApiOperation("创建积分记录")
     @ApiOperationSupport(order = 2)
@@ -57,4 +71,17 @@ public class SecondUserCreditRecordController {
             return R.fail("积分记录创建失败");
         }
     }
+
+    @ApiOperation("用户观看完学习视频后增加积分")
+    @ApiOperationSupport(order = 6)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "learningId", value = "学习视频ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @PostMapping("/addPointsAfterWatchingVideo")
+    public R<String> addPointsAfterWatchingVideo(
+            @RequestParam Integer userId,
+            @RequestParam Integer learningId) {
+        return secondUserPointsRecordService.addPointsAfterWatchingVideo(userId, learningId);
+    }
 }

+ 17 - 0
alien-second/src/main/java/shop/alien/second/service/SecondUserCreditRecordService.java

@@ -1,7 +1,12 @@
 package shop.alien.second.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.result.R;
+import shop.alien.entity.second.SecondUserCredit;
 import shop.alien.entity.second.SecondUserCreditRecord;
+import shop.alien.entity.second.vo.SecondUserCreditRecordListVo;
+
+import java.util.List;
 
 /**
  * 二手平台用户积分记录服务接口
@@ -21,4 +26,16 @@ public interface SecondUserCreditRecordService extends IService<SecondUserCredit
      * @return 是否创建成功
      */
     boolean createRecord(SecondUserCreditRecord record);
+
+    R<SecondUserCreditRecordListVo> getByUserId(Integer userId, Integer timeRange);
+
+    /**
+     * 用户观看完学习视频后增加积分
+     * @param userId 用户ID
+     * @param learningId 学习视频ID
+     * @return 操作结果
+     */
+    R<String> addPointsAfterWatchingVideo(Integer userId, Integer learningId);
+
+
 }

+ 182 - 1
alien-second/src/main/java/shop/alien/second/service/impl/SecondUserCreditRecordServiceImpl.java

@@ -5,10 +5,21 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import shop.alien.entity.result.R;
+import shop.alien.entity.second.SecondUserCredit;
+import shop.alien.entity.second.SecondUserCreditDateRecord;
 import shop.alien.entity.second.SecondUserCreditRecord;
+import shop.alien.entity.second.vo.SecondUserCreditRecordListVo;
+import shop.alien.entity.store.LifeUserLearningRecord;
+import shop.alien.entity.store.LifeUserLearningVideo;
+import shop.alien.mapper.LifeUserLearningRecordMapper;
+import shop.alien.mapper.LifeUserLearningVideoMapper;
+import shop.alien.mapper.second.SecondUserCreditDateRecordMapper;
+import shop.alien.mapper.second.SecondUserCreditMapper;
 import shop.alien.mapper.second.SecondUserCreditRecordMapper;
 import shop.alien.second.service.SecondUserCreditRecordService;
 
+import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
 
@@ -21,7 +32,11 @@ import java.util.List;
 public class SecondUserCreditRecordServiceImpl extends ServiceImpl<SecondUserCreditRecordMapper, SecondUserCreditRecord> implements SecondUserCreditRecordService {
     
     private final SecondUserCreditRecordMapper secondUserCreditRecordMapper;
-    
+    private final SecondUserCreditMapper secondUserCreditMapper;
+    private final SecondUserCreditDateRecordMapper secondUserCreditDateRecordMapper;
+    private final LifeUserLearningVideoMapper lifeUserLearningVideoMapper;
+    private final LifeUserLearningRecordMapper lifeUserLearningRecordMapper;
+
     /**
      * 根据用户ID获取积分记录列表
      * @param userId 用户ID
@@ -56,4 +71,170 @@ public class SecondUserCreditRecordServiceImpl extends ServiceImpl<SecondUserCre
             return false;
         }
     }
+
+    @Override
+    public R<SecondUserCreditRecordListVo> getByUserId(Integer userId, Integer timeRange) {
+        log.info("SecondUserCreditRecordServiceImpl.getByUserId, userId={}, timeRange={}", userId, timeRange);
+        LambdaQueryWrapper<SecondUserCreditRecord> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SecondUserCreditRecord::getUserId, userId);
+
+        // 根据时间范围过滤
+        Date startTime = null;
+
+
+        queryWrapper.orderByDesc(SecondUserCreditRecord::getCreatedTime);
+        // 下面全部 忽略时间范围 需求变动再去添加
+        List<SecondUserCreditRecord> recordsChange = this.list(queryWrapper);
+
+        if (timeRange != null) {
+            startTime = calculateStartTime(timeRange);
+            if (startTime != null) {
+                queryWrapper.ge(SecondUserCreditRecord::getCreatedTime, startTime);
+            }
+        }
+        
+        // 查询日期积分记录,按照相同的时间范围筛选
+        LambdaQueryWrapper<SecondUserCreditDateRecord> dateRecordQueryWrapper = new LambdaQueryWrapper<>();
+        dateRecordQueryWrapper.eq(SecondUserCreditDateRecord::getUserId, userId);
+        
+        if (startTime != null) {
+            // 将开始时间转换为日期(忽略时间部分)
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(startTime);
+            cal.set(Calendar.HOUR_OF_DAY, 0);
+            cal.set(Calendar.MINUTE, 0);
+            cal.set(Calendar.SECOND, 0);
+            cal.set(Calendar.MILLISECOND, 0);
+            Date startDate = cal.getTime();
+            dateRecordQueryWrapper.ge(SecondUserCreditDateRecord::getRecordDate, startDate);
+        }
+        
+        dateRecordQueryWrapper.orderByDesc(SecondUserCreditDateRecord::getRecordDate);
+        List<SecondUserCreditDateRecord> dateRecords = secondUserCreditDateRecordMapper.selectList(dateRecordQueryWrapper);
+        
+        // 查询用户积分
+        Integer userPoints = null;
+        SecondUserCredit secondUserCredit = this.getUserCreditByUserId(userId);
+        if (secondUserCredit != null) {
+            userPoints = secondUserCredit.getUserPoints();
+        }
+        
+        // 构建返回对象
+        SecondUserCreditRecordListVo result = new SecondUserCreditRecordListVo();
+        result.setRecordsChange(recordsChange);
+        result.setDateRecords(dateRecords);
+        result.setUserPoints(userPoints);
+        return R.data(result);
+    }
+
+    /**
+     * 根据时间范围计算开始时间
+     * @param timeRange 时间范围:1-近一周,2-近一个月,3-近一年
+     * @return 开始时间
+     */
+    private Date calculateStartTime(Integer timeRange) {
+        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);
+
+        switch (timeRange) {
+            case 1: // 近一周
+                calendar.add(Calendar.DAY_OF_YEAR, -7);
+                break;
+            case 2: // 近一个月
+                calendar.add(Calendar.MONTH, -1);
+                break;
+            case 3: // 近一年
+                calendar.add(Calendar.YEAR, -1);
+                break;
+            default:
+                return null;
+        }
+
+        return calendar.getTime();
+    }
+
+    @Override
+    public R<String> addPointsAfterWatchingVideo(Integer userId, Integer learningId) {
+        log.info("用户观看完学习视频后增加积分,userId={}, learningId={}", userId, learningId);
+        
+        try {
+            // 1. 查询学习视频信息,获取奖励分数
+            LifeUserLearningVideo learningVideo = lifeUserLearningVideoMapper.selectById(learningId);
+            if (learningVideo == null) {
+                return R.fail("学习视频不存在");
+            }
+            
+            Integer score = learningVideo.getScore();
+            if (score == null || score <= 0) {
+                return R.fail("该学习视频没有奖励分数");
+            }
+            
+            // 2. 检查是否已经观看过(避免重复奖励)
+            LambdaQueryWrapper<LifeUserLearningRecord> recordQueryWrapper = new LambdaQueryWrapper<>();
+            recordQueryWrapper.eq(LifeUserLearningRecord::getUserId, userId)
+                    .eq(LifeUserLearningRecord::getLearningId, learningId)
+                    .eq(LifeUserLearningRecord::getDeleteFlag, 0);
+            long count = lifeUserLearningRecordMapper.selectCount(recordQueryWrapper);
+            if (count > 0) {
+                return R.fail("您已经观看过该视频,无法重复获得奖励");
+            }
+            
+            // 3. 查询或创建用户积分记录
+            SecondUserCredit userCredit = this.getUserCreditByUserId(userId);
+            if (userCredit == null) {
+                // 如果用户没有积分记录,先创建
+                userCredit = new SecondUserCredit();
+                userCredit.setUserId(userId);
+                userCredit.setUserPoints(0);
+                userCredit.setDeleteFlag(0);
+                userCredit.setCreatedTime(new Date());
+                userCredit.setUpdatedTime(new Date());
+                secondUserCreditMapper.insert(userCredit);
+            }
+            
+            // 4. 更新用户积分
+            secondUserCreditMapper.updatePointsByUserId(userId, score);
+            
+            // 5. 添加积分记录(pointsType = 8 表示学习视频奖励)
+            SecondUserCreditRecord creditRecord = new SecondUserCreditRecord();
+            creditRecord.setUserId(userId);
+            creditRecord.setPoints(score);
+            creditRecord.setPointsType(8); // 8-学习视频奖励
+            creditRecord.setDeleteFlag(0);
+            creditRecord.setCreatedTime(new Date());
+            creditRecord.setUpdatedTime(new Date());
+            secondUserCreditRecordMapper.insert(creditRecord);
+            
+            // 6. 添加学习记录
+            LifeUserLearningRecord learningRecord = new LifeUserLearningRecord();
+            learningRecord.setUserId(userId);
+            learningRecord.setLearningId(learningId);
+            learningRecord.setDeleteFlag(0);
+            learningRecord.setCreatedTime(new Date());
+            learningRecord.setUpdatedTime(new Date());
+            lifeUserLearningRecordMapper.insert(learningRecord);
+            
+            log.info("用户观看完学习视频后增加积分成功,userId={}, learningId={}, score={}", userId, learningId, score);
+            return R.success("观看视频成功,获得" + score + "积分");
+            
+        } catch (Exception e) {
+            log.error("用户观看完学习视频后增加积分失败,userId={}, learningId={}", userId, learningId, e);
+            return R.fail("操作失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 根据用户ID获取用户积分信息
+     * @param userId 用户ID
+     * @return 用户积分信息
+     */
+    private SecondUserCredit getUserCreditByUserId(Integer userId) {
+        LambdaQueryWrapper<SecondUserCredit> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SecondUserCredit::getUserId, userId)
+                .eq(SecondUserCredit::getDeleteFlag, 0);
+        return secondUserCreditMapper.selectOne(queryWrapper);
+    }
 }

+ 4 - 3
alien-second/src/main/java/shop/alien/second/service/impl/SecondUserCreditServiceImpl.java

@@ -14,6 +14,7 @@ import shop.alien.entity.second.vo.SecondUserCreditVo;
 import shop.alien.mapper.second.SecondUserCreditMapper;
 import shop.alien.mapper.second.SecondUserCreditRecordMapper;
 import shop.alien.second.service.SecondGoodsService;
+import shop.alien.second.service.SecondUserCreditRecordService;
 import shop.alien.second.service.SecondUserCreditService;
 
 import java.util.Date;
@@ -27,7 +28,7 @@ import java.util.Date;
 public class SecondUserCreditServiceImpl extends ServiceImpl<SecondUserCreditMapper, SecondUserCredit> implements SecondUserCreditService {
     
     private final SecondUserCreditMapper secondUserCreditMapper;
-    private final SecondUserCreditRecordServiceImpl serviceImpl;
+    private final SecondUserCreditRecordService secondUserCreditRecordService;
     private final SecondUserCreditRecordMapper secondUserCreditRecordMapper;
 
     /**
@@ -116,7 +117,7 @@ public class SecondUserCreditServiceImpl extends ServiceImpl<SecondUserCreditMap
                     record.setUserId(userId);
                     record.setPoints(initialPoints);
                     record.setPointsType(pointsType);
-                    serviceImpl.createRecord(record);
+                    secondUserCreditRecordService.createRecord(record);
                     return true;
                 }
 
@@ -205,7 +206,7 @@ public class SecondUserCreditServiceImpl extends ServiceImpl<SecondUserCreditMap
             record.setUserId(userId);
             record.setPoints(points);
             record.setPointsType(pointsType);
-            serviceImpl.createRecord(record);
+            secondUserCreditRecordMapper.insert(record);
 
             return result > 0;
         } catch (Exception e) {