Ver código fonte

提交积分接口代码

yuhongqi 1 dia atrás
pai
commit
50736f4eda

+ 6 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveCompletionPointsRecordMapper.java

@@ -33,6 +33,12 @@ public interface LiveCompletionPointsRecordMapper {
      */
     LiveCompletionPointsRecord selectLatestByUser(@Param("userId") Long userId);
 
+    /**
+     * 查询用户在某直播间最近一次完课记录(不限制日期)
+     */
+    LiveCompletionPointsRecord selectLatestByUserAndLiveId(@Param("liveId") Long liveId, 
+                                                            @Param("userId") Long userId);
+
     /**
      * 查询用户未领取的完课记录列表
      */

+ 5 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java

@@ -129,6 +129,9 @@ public class LiveServiceImpl implements ILiveService
     @Autowired
     LiveTagConfigMapper liveTagConfigMapper;
 
+    @Autowired
+    private ILiveWatchUserService liveWatchUserService;
+
     private static String TOKEN_VALID_CODE = "40001";
 
     private static volatile Integer version = 0;
@@ -295,6 +298,8 @@ public class LiveServiceImpl implements ILiveService
 			long seconds = live.getStartTime().until(now, ChronoUnit.SECONDS);
 			liveVo.setNowDuration(seconds);
 		}
+        Map<String, Integer> liveFlagWithCache = liveWatchUserService.getLiveFlagWithCache(live.getLiveId());
+        liveVo.setLiveFlag(liveFlagWithCache.get("liveFlag"));
         ThreadUtil.execute(()->{
             redisCache.deleteObject(String.format(LiveKeysConstant.LIVE_HOME_PAGE_DETAIL, live.getLiveId()));
             redisCache.setCacheObject(String.format(LiveKeysConstant.LIVE_HOME_PAGE_DETAIL, live.getLiveId()), liveVo,LiveKeysConstant.LIVE_HOME_PAGE_DETAIL_EXPIRE, TimeUnit.SECONDS);

+ 2 - 1
fs-service/src/main/java/com/fs/live/vo/LiveVo.java

@@ -58,7 +58,8 @@ public class LiveVo {
     private Integer previewVideoType;
     private Long previewVideoId;
     private Integer globalVisible;
-    
+    private Integer liveFlag;
+
     /** 是否开启直播完课积分功能 */
     private Boolean completionPointsEnabled;
     

+ 9 - 0
fs-service/src/main/resources/mapper/live/LiveCompletionPointsRecordMapper.xml

@@ -89,6 +89,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         LIMIT 1
     </select>
 
+    <!-- 查询用户在某直播间最近一次完课记录(不限制日期) -->
+    <select id="selectLatestByUserAndLiveId" resultMap="LiveCompletionPointsRecordResult">
+        SELECT * FROM live_completion_points_record
+        WHERE live_id = #{liveId}
+          AND user_id = #{userId}
+        ORDER BY current_completion_date DESC, id DESC
+        LIMIT 1
+    </select>
+
     <!-- 查询用户未领取的完课记录列表 -->
     <select id="selectUnreceivedByUser" resultMap="LiveCompletionPointsRecordResult">
         SELECT * FROM live_completion_points_record

+ 293 - 0
fs-user-app/src/main/java/com/fs/app/controller/live/LiveCompletionPointsController.java

@@ -1,15 +1,29 @@
 package com.fs.app.controller.live;
 
 import com.fs.app.controller.AppBaseController;
+import com.fs.app.vo.ReceivePointsVO;
+import com.fs.app.vo.RemainingTimeVO;
+import com.fs.app.vo.UpdateWatchDurationVO;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.domain.R;
+import com.fs.common.exception.base.BaseException;
 import com.fs.his.domain.FsUser;
+import com.fs.his.domain.FsUserIntegralLogs;
+import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.his.service.IFsUserService;
+import com.fs.live.domain.Live;
 import com.fs.live.domain.LiveCompletionPointsRecord;
+import com.fs.live.mapper.LiveCompletionPointsRecordMapper;
 import com.fs.live.service.ILiveCompletionPointsRecordService;
+import com.fs.live.service.ILiveService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -27,6 +41,15 @@ public class LiveCompletionPointsController extends AppBaseController {
     @Autowired
     private IFsUserService fsUserService;
 
+    @Autowired
+    private ILiveService liveService;
+
+    @Autowired
+    private IFsUserIntegralLogsService fsUserIntegralLogsService;
+
+    @Autowired
+    private LiveCompletionPointsRecordMapper completionPointsRecordMapper;
+
     /**
      * 领取完课积分
      */
@@ -107,4 +130,274 @@ public class LiveCompletionPointsController extends AppBaseController {
             return R.error("创建失败: " + e.getMessage());
         }
     }
+
+    /**
+     * 第一个接口:查询当前用户当前直播间领取积分的剩余时长
+     * GET请求,传入直播间id
+     * 查询当前用户和当前直播间的积分记录(不限制日期),如果不存在就生成看课记录
+     */
+    @GetMapping("/remaining-time")
+    public R getRemainingTime(@RequestParam Long liveId) {
+        Long userId = Long.parseLong(getUserId());
+        
+        try {
+            // 1. 获取直播间信息
+            Live live = liveService.selectLiveByLiveId(liveId);
+            if (live == null) {
+                return R.error("直播间不存在");
+            }
+
+            // 2. 查询当前用户和当前直播间的最近一次完课记录(不限制日期)
+            LiveCompletionPointsRecord record = completionPointsRecordMapper.selectLatestByUserAndLiveId(liveId, userId);
+            
+            // 3. 如果没有记录,查询直播间配置并生成记录
+            if (record == null) {
+                completionPointsRecordService.checkAndCreateCompletionRecord(liveId, userId, null);
+                // 重新查询
+                record = completionPointsRecordMapper.selectLatestByUserAndLiveId(liveId, userId);
+            }
+
+            // 4. 计算剩余时长
+            RemainingTimeVO vo = new RemainingTimeVO();
+            Long videoDuration = live.getDuration() != null ? live.getDuration() : 0L;
+            Long watchDuration = record != null && record.getWatchDuration() != null 
+                    ? record.getWatchDuration() : 0L;
+            
+            vo.setVideoDuration(videoDuration);
+            vo.setWatchDuration(watchDuration);
+            vo.setRemainingTime(Math.max(0, videoDuration - watchDuration));
+            vo.setHasReceived(record != null && record.getReceiveStatus() != null && record.getReceiveStatus() == 1);
+            
+            return R.ok().put("data", vo);
+        } catch (Exception e) {
+            return R.error("查询失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 第二个接口:更新用户的看课时长
+     * POST请求,传入直播间id和看课时长
+     * 更新用户看课completionPointsRecordService看课记录里面的时长
+     */
+    @PostMapping("/update-watch-duration")
+    public R updateWatchDuration(@RequestParam Long liveId, @RequestParam Long watchDuration) {
+        Long userId = Long.parseLong(getUserId());
+        
+        try {
+            // 1. 获取直播间信息
+            Live live = liveService.selectLiveByLiveId(liveId);
+            if (live == null) {
+                return R.error("直播间不存在");
+            }
+
+            // 2. 判断当前时间是否在直播期间(状态为2,直播中)
+            boolean isLiveInProgress = false;
+            LocalDateTime now = LocalDateTime.now();
+            
+            if (live.getStatus() != null && live.getStatus() == 2) {
+                // status=2 表示直播中
+                isLiveInProgress = true;
+            } else if (live.getStartTime() != null && live.getFinishTime() != null) {
+                // 判断当前时间是否在开播时间和结束时间之间
+                isLiveInProgress = (now.isAfter(live.getStartTime()) || now.isEqual(live.getStartTime()))
+                        && (now.isBefore(live.getFinishTime()) || now.isEqual(live.getFinishTime()));
+            }
+
+            if (!isLiveInProgress) {
+                return R.error("当前不在直播期间,无法更新看课时长");
+            }
+
+            // 3. 查询当前直播间的完课记录(不限制日期)
+            LiveCompletionPointsRecord record = completionPointsRecordMapper.selectLatestByUserAndLiveId(liveId, userId);
+            
+            // 4. 计算看课时长
+            Date updateTime = null;
+            if (record != null && record.getUpdateTime() != null) {
+                updateTime = record.getUpdateTime();
+            }
+            
+            // 判断更新时间与直播间开始时间的关系
+            Date startTime = live.getStartTime() != null 
+                    ? java.sql.Timestamp.valueOf(live.getStartTime()) : null;
+            
+            Date currentTime = new Date();
+            long timeDiff = 0L;
+            
+            if (updateTime != null && startTime != null) {
+                if (updateTime.before(startTime)) {
+                    // 更新时间小于直播间开始时间,使用直播间开始时间进行计算
+                    timeDiff = (currentTime.getTime() - startTime.getTime()) / 1000; // 转换为秒
+                } else {
+                    // 更新时间大于等于开播时间,按照更新时间进行计算
+                    timeDiff = (currentTime.getTime() - updateTime.getTime()) / 1000; // 转换为秒
+                }
+            } else if (startTime != null) {
+                // 没有更新记录,使用直播间开始时间计算
+                timeDiff = (currentTime.getTime() - startTime.getTime()) / 1000; // 转换为秒
+            }
+            
+            // 5. 如果请求传入的时间大于这个时间差,就使用计算出的看课时长,否则使用请求传入的时长
+            Long finalWatchDuration;
+            if (watchDuration > timeDiff) {
+                // 请求传入的时间大于时间差,使用计算出的看课时长
+                finalWatchDuration = timeDiff;
+            } else {
+                // 否则使用请求传入的时长
+                finalWatchDuration = watchDuration;
+            }
+            
+            // 6. 更新完课记录中的看课时长
+            if (record == null) {
+                // 如果没有记录,先创建记录
+                completionPointsRecordService.checkAndCreateCompletionRecord(liveId, userId, finalWatchDuration);
+                record = completionPointsRecordMapper.selectLatestByUserAndLiveId(liveId, userId);
+            } else {
+                // 更新现有记录的看课时长
+                Long currentWatchDuration = record.getWatchDuration() != null 
+                        ? record.getWatchDuration() : 0L;
+                record.setWatchDuration(currentWatchDuration + finalWatchDuration);
+                
+                // 重新计算完课比例
+                Long videoDuration = live.getDuration();
+                if (videoDuration != null && videoDuration > 0) {
+                    BigDecimal completionRate = BigDecimal.valueOf(record.getWatchDuration())
+                            .multiply(BigDecimal.valueOf(100))
+                            .divide(BigDecimal.valueOf(videoDuration), 2, java.math.RoundingMode.HALF_UP);
+                    if (completionRate.compareTo(BigDecimal.valueOf(100)) > 0) {
+                        completionRate = BigDecimal.valueOf(100);
+                    }
+                    record.setCompletionRate(completionRate);
+                }
+                
+                completionPointsRecordMapper.updateRecord(record);
+            }
+
+            UpdateWatchDurationVO vo = new UpdateWatchDurationVO();
+            vo.setWatchDuration(finalWatchDuration);
+            vo.setTotalWatchDuration(record != null && record.getWatchDuration() != null 
+                    ? record.getWatchDuration() : finalWatchDuration);
+            
+            return R.ok().put("data", vo);
+        } catch (Exception e) {
+            return R.error("更新失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 第三个接口:用户领取看课积分
+     * POST请求,传入直播间id
+     * 只查询这个直播间的看课记录(不限制日期),检查是否达到了完课标准
+     * 达到了更新了看课记录里面的领取条件,给用户发积分
+     * 没达到,返回报错
+     */
+    @PostMapping("/receive-points")
+    @RepeatSubmit
+    public R receivePoints(@RequestParam Long liveId) {
+        Long userId = Long.parseLong(getUserId());
+        
+        try {
+            // 1. 查询当前用户和当前直播间的最近一次完课记录(不限制日期)
+            LiveCompletionPointsRecord record = completionPointsRecordMapper.selectLatestByUserAndLiveId(liveId, userId);
+            
+            if (record == null) {
+                return R.error("您还没有看课记录,无法领取积分");
+            }
+
+            // 2. 获取直播间信息和配置
+            Live live = liveService.selectLiveByLiveId(liveId);
+            if (live == null) {
+                return R.error("直播间不存在");
+            }
+
+            // 3. 检查看课记录里面的时长是否达到完课标准
+            Long watchDuration = record.getWatchDuration();
+            if (watchDuration == null || watchDuration <= 0) {
+                return R.error("您的看课时长不足,无法领取积分");
+            }
+
+            // 4. 检查完课比例是否达到标准
+            BigDecimal completionRate = record.getCompletionRate();
+            if (completionRate == null) {
+                // 重新计算完课比例
+                Long videoDuration = live.getDuration();
+                if (videoDuration == null || videoDuration <= 0) {
+                    return R.error("直播间视频时长配置错误");
+                }
+                completionRate = BigDecimal.valueOf(watchDuration)
+                        .multiply(BigDecimal.valueOf(100))
+                        .divide(BigDecimal.valueOf(videoDuration), 2, java.math.RoundingMode.HALF_UP);
+                if (completionRate.compareTo(BigDecimal.valueOf(100)) > 0) {
+                    completionRate = BigDecimal.valueOf(100);
+                }
+                record.setCompletionRate(completionRate);
+            }
+
+            // 5. 从直播间配置获取完课标准
+            String configJson = live.getConfigJson();
+            Integer requiredCompletionRate = null;
+            if (configJson != null && !configJson.isEmpty()) {
+                try {
+                    com.alibaba.fastjson.JSONObject jsonConfig = com.alibaba.fastjson.JSON.parseObject(configJson);
+                    requiredCompletionRate = jsonConfig.getInteger("completionRate");
+                } catch (Exception e) {
+                    // 解析失败,忽略
+                }
+            }
+
+            // 6. 判断是否达到完课标准
+            if (requiredCompletionRate != null && completionRate.compareTo(BigDecimal.valueOf(requiredCompletionRate)) < 0) {
+                return R.error("您的完课比例未达到标准(" + requiredCompletionRate + "%),当前完课比例:" + completionRate + "%");
+            }
+
+            // 7. 检查是否已领取
+            if (record.getReceiveStatus() != null && record.getReceiveStatus() == 1) {
+                return R.error("该完课积分已领取");
+            }
+
+            // 8. 领取积分(更新看课记录的领取状态,给用户加积分)
+            LiveCompletionPointsRecord receivedRecord = completionPointsRecordService.receiveCompletionPoints(record.getId(), userId);
+
+            ReceivePointsVO vo = new ReceivePointsVO();
+            vo.setRecord(receivedRecord);
+            vo.setPoints(receivedRecord.getPointsAwarded());
+            vo.setContinuousDays(receivedRecord.getContinuousDays());
+            
+            return R.ok().put("data", vo);
+        } catch (BaseException e) {
+            return R.error(e.getMessage());
+        } catch (Exception e) {
+            return R.error("领取失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 第四个接口:查询用户自己的积分记录
+     * GET请求
+     */
+    @GetMapping("/integral-logs")
+    public R getIntegralLogs(@RequestParam(required = false) Integer type) {
+        Long userId = Long.parseLong(getUserId());
+        
+        try {
+            FsUserIntegralLogs query = new FsUserIntegralLogs();
+            query.setUserId(userId);
+            
+            List<FsUserIntegralLogs> logs = fsUserIntegralLogsService.selectFsUserIntegralLogsList(query);
+            
+            // 如果指定了类型,进行过滤
+            if (type != null) {
+                if (type == 1) {
+                    // 获得积分(积分大于0)
+                    logs.removeIf(log -> log.getIntegral() == null || log.getIntegral() <= 0);
+                } else if (type == 2) {
+                    // 消耗积分(积分小于0)
+                    logs.removeIf(log -> log.getIntegral() == null || log.getIntegral() >= 0);
+                }
+            }
+            
+            return R.ok().put("data", logs);
+        } catch (Exception e) {
+            return R.error("查询失败: " + e.getMessage());
+        }
+    }
 }

+ 25 - 0
fs-user-app/src/main/java/com/fs/app/vo/ReceivePointsVO.java

@@ -0,0 +1,25 @@
+package com.fs.app.vo;
+
+import com.fs.live.domain.LiveCompletionPointsRecord;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 领取积分返回VO
+ */
+@Data
+public class ReceivePointsVO implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+    
+    /** 完课记录 */
+    private LiveCompletionPointsRecord record;
+    
+    /** 获得的积分 */
+    private Integer points;
+    
+    /** 连续天数 */
+    private Integer continuousDays;
+}
+

+ 27 - 0
fs-user-app/src/main/java/com/fs/app/vo/RemainingTimeVO.java

@@ -0,0 +1,27 @@
+package com.fs.app.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 剩余时长返回VO
+ */
+@Data
+public class RemainingTimeVO implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+    
+    /** 剩余时长(秒) */
+    private Long remainingTime;
+    
+    /** 已观看时长(秒) */
+    private Long watchDuration;
+    
+    /** 视频总时长(秒) */
+    private Long videoDuration;
+    
+    /** 是否领取过 */
+    private Boolean hasReceived;
+}
+

+ 21 - 0
fs-user-app/src/main/java/com/fs/app/vo/UpdateWatchDurationVO.java

@@ -0,0 +1,21 @@
+package com.fs.app.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 更新看课时长返回VO
+ */
+@Data
+public class UpdateWatchDurationVO implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+    
+    /** 本次更新的看课时长(秒) */
+    private Long watchDuration;
+    
+    /** 总看课时长(秒) */
+    private Long totalWatchDuration;
+}
+