yys 1 тиждень тому
батько
коміт
dbe5cfb0ec

+ 1 - 1
fs-admin/src/main/java/com/fs/live/controller/LiveConsoleOpLogController.java

@@ -30,4 +30,4 @@ public class LiveConsoleOpLogController extends BaseController {
         List<LiveConsoleOpLog> list = liveConsoleOpLogService.selectLiveConsoleOpLogList(liveConsoleOpLog);
         return getDataTable(list);
     }
-}
+}

+ 2 - 2
fs-service/src/main/java/com/fs/live/domain/LiveConsoleOpLogUser.java

@@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
 
 /**
  * 中控台操作留存与用户关联
- * <p>对应表:live_console_op_log_user,用于记录某留存涉及的用户(如定时自动发券)</p>
+ * <p>对应表:live_console_op_log_user,用于记录某留存涉及的用户(如定时自动发券)</p>
  */
 @Data
 @NoArgsConstructor
@@ -43,4 +43,4 @@ public class LiveConsoleOpLogUser extends BaseEntity {
         this.liveId = liveId;
         this.couponUserId = couponUserId;
     }
-}
+}

+ 1 - 1
fs-service/src/main/java/com/fs/live/mapper/LiveConsoleOpLogMapper.java

@@ -17,4 +17,4 @@ public interface LiveConsoleOpLogMapper {
 
     /** 新增留存记录 */
     int insertLiveConsoleOpLog(LiveConsoleOpLog liveConsoleOpLog);
-}
+}

+ 4 - 1
fs-service/src/main/java/com/fs/live/mapper/LiveConsoleOpLogUserMapper.java

@@ -15,4 +15,7 @@ public interface LiveConsoleOpLogUserMapper {
 
     /** 根据留存记录ID查询关联用户 */
     List<LiveConsoleOpLogUser> selectByOpLogId(@Param("opLogId") Long opLogId);
-}
+
+    /** 查询用户在指定直播间的留存关联 */
+    List<LiveConsoleOpLogUser> selectByLiveIdAndUserId(@Param("liveId") Long liveId, @Param("userId") Long userId);
+}

+ 1 - 1
fs-service/src/main/java/com/fs/live/param/LiveCompletionCouponAnswerItem.java

@@ -17,4 +17,4 @@ public class LiveCompletionCouponAnswerItem {
      * 多选:如 A,B 或 JSON 数组字符串 ["A","B"]
      */
     private String answer;
-}
+}

+ 1 - 1
fs-service/src/main/java/com/fs/live/param/LiveCompletionCouponClaimParam.java

@@ -13,4 +13,4 @@ public class LiveCompletionCouponClaimParam {
 
     /** 中控台操作留存 ID(WebSocket opLog.id) */
     private Long opLogId;
-}
+}

+ 6 - 34
fs-service/src/main/java/com/fs/live/service/ILiveConsoleOpLogService.java

@@ -3,6 +3,7 @@ package com.fs.live.service;
 import com.fs.live.domain.LiveConsoleOpLog;
 import com.fs.live.domain.LiveConsoleOpLogUser;
 import com.fs.live.domain.LiveCoupon;
+import com.fs.live.vo.LiveConsoleOpLogRecordVo;
 
 import java.util.List;
 
@@ -11,51 +12,22 @@ import java.util.List;
  */
 public interface ILiveConsoleOpLogService {
 
-    /**
-     * 查询留存记录列表
-     */
     List<LiveConsoleOpLog> selectLiveConsoleOpLogList(LiveConsoleOpLog liveConsoleOpLog);
 
-    /**
-     * 保存操作留存
-     *
-     * @param liveId     直播间ID
-     * @param opType     操作类型,见 {@link LiveConsoleOpLog} 中 OP_* 常量
-     * @param handleType 触发类型,见 {@link LiveConsoleOpLog#HANDLE_CONSOLE} / {@link LiveConsoleOpLog#HANDLE_AUTO}
-     * @param bizId      业务ID
-     * @param bizName    业务名称
-     * @return 已入库的留存记录(含自增 id)
-     */
     LiveConsoleOpLog saveLog(Long liveId, Integer opType, Integer handleType, Long bizId, String bizName);
 
-    /**
-     * 保存优惠券展示类留存(自动区分普通券 / 核销券)
-     *
-     * @param couponIssueId 优惠券发布记录ID
-     */
     LiveConsoleOpLog saveCouponShowLog(Long liveId, Long couponIssueId, LiveCoupon coupon, Integer handleType);
 
-    /**
-     * 批量绑定留存记录与用户(定时自动发券等场景)
-     *
-     * @param opLogId   留存记录ID
-     * @param liveId    直播间ID
-     * @param relations 用户关联列表(opLogId 可为空,方法内会补全)
-     */
     void bindOpLogUsers(Long opLogId, Long liveId, List<LiveConsoleOpLogUser> relations);
 
-    /**
-     * 根据留存记录ID查询关联用户
-     */
     List<LiveConsoleOpLogUser> selectOpLogUsers(Long opLogId);
 
-    /**
-     * 绑定单个用户与留存记录(App 领取等场景)
-     */
     void bindOpLogUser(Long opLogId, Long liveId, Long userId);
 
+    void bindOpLogUser(Long opLogId, Long liveId, Long userId, Long couponUserId);
+
     /**
-     * 绑定单个用户与留存记录,可附带用户优惠券记录 ID
+     * 查询用户在指定直播间的留存记录(含领取/结束状态)
      */
-    void bindOpLogUser(Long opLogId, Long liveId, Long userId, Long couponUserId);
-}
+    List<LiveConsoleOpLogRecordVo> listUserOpLogRecords(Long liveId, Long userId);
+}

+ 153 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveConsoleOpLogServiceImpl.java

@@ -8,16 +8,29 @@ import com.fs.common.utils.StringUtils;
 import com.fs.live.domain.LiveConsoleOpLog;
 import com.fs.live.domain.LiveConsoleOpLogUser;
 import com.fs.live.domain.LiveCoupon;
+import com.fs.live.domain.LiveCouponIssue;
+import com.fs.live.domain.LiveLotteryConf;
+import com.fs.live.domain.LiveRedConf;
 import com.fs.live.mapper.LiveConsoleOpLogMapper;
 import com.fs.live.mapper.LiveConsoleOpLogUserMapper;
 import com.fs.live.service.ILiveConsoleOpLogService;
+import com.fs.live.service.ILiveCouponIssueService;
+import com.fs.live.service.ILiveLotteryConfService;
+import com.fs.live.service.ILiveRedConfService;
+import com.fs.live.vo.LiveConsoleOpLogRecordVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
+import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * 直播中控台操作留存 Service 实现
@@ -34,6 +47,15 @@ public class LiveConsoleOpLogServiceImpl implements ILiveConsoleOpLogService {
     @Autowired
     private LiveConsoleOpLogUserMapper liveConsoleOpLogUserMapper;
 
+    @Autowired
+    private ILiveRedConfService liveRedConfService;
+
+    @Autowired
+    private ILiveLotteryConfService liveLotteryConfService;
+
+    @Autowired
+    private ILiveCouponIssueService liveCouponIssueService;
+
     @Override
     public List<LiveConsoleOpLog> selectLiveConsoleOpLogList(LiveConsoleOpLog liveConsoleOpLog) {
         return liveConsoleOpLogMapper.selectLiveConsoleOpLogList(liveConsoleOpLog);
@@ -115,6 +137,137 @@ public class LiveConsoleOpLogServiceImpl implements ILiveConsoleOpLogService {
                 Collections.singletonList(new LiveConsoleOpLogUser(opLogId, userId, liveId, couponUserId)));
     }
 
+    @Override
+    public List<LiveConsoleOpLogRecordVo> listUserOpLogRecords(Long liveId, Long userId) {
+        if (liveId == null || userId == null) {
+            return Collections.emptyList();
+        }
+        LiveConsoleOpLog query = new LiveConsoleOpLog();
+        query.setLiveId(liveId);
+        List<LiveConsoleOpLog> opLogs = liveConsoleOpLogMapper.selectLiveConsoleOpLogList(query);
+        if (opLogs == null || opLogs.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        Set<Long> claimedOpLogIds = new HashSet<>();
+        List<LiveConsoleOpLogUser> relations = liveConsoleOpLogUserMapper.selectByLiveIdAndUserId(liveId, userId);
+        if (relations != null) {
+            claimedOpLogIds = relations.stream()
+                    .map(LiveConsoleOpLogUser::getOpLogId)
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toSet());
+        }
+
+        Date now = DateUtils.getNowDate();
+        List<LiveConsoleOpLogRecordVo> result = new ArrayList<>(opLogs.size());
+        for (LiveConsoleOpLog opLog : opLogs) {
+            boolean claimed = opLog.getId() != null && claimedOpLogIds.contains(opLog.getId());
+            int status = resolveOpLogStatus(opLog, claimed, now);
+            result.add(LiveConsoleOpLogRecordVo.from(opLog, status));
+        }
+        return result;
+    }
+
+    /**
+     * 状态优先级:已领取 > 已结束 > 待领取
+     */
+    private int resolveOpLogStatus(LiveConsoleOpLog opLog, boolean claimed, Date now) {
+        if (claimed) {
+            return LiveConsoleOpLogRecordVo.STATUS_CLAIMED;
+        }
+        if (isOpLogEnded(opLog, now)) {
+            return LiveConsoleOpLogRecordVo.STATUS_ENDED;
+        }
+        return LiveConsoleOpLogRecordVo.STATUS_PENDING;
+    }
+
+    private boolean isOpLogEnded(LiveConsoleOpLog opLog, Date now) {
+        Date expireTime = resolveExpireTime(opLog);
+        if (expireTime != null && !now.before(expireTime)) {
+            return true;
+        }
+        return isBizEnded(opLog);
+    }
+
+    private Date resolveExpireTime(LiveConsoleOpLog opLog) {
+        if (opLog == null || opLog.getCreateTime() == null || opLog.getOpType() == null) {
+            return null;
+        }
+        Integer opType = opLog.getOpType();
+        Long bizId = opLog.getBizId();
+        if (bizId == null) {
+            return null;
+        }
+
+        Long durationMinutes = null;
+        Date limitTime = null;
+
+        switch (opType) {
+            case LiveConsoleOpLog.OP_COUPON_SHOW:
+            case LiveConsoleOpLog.OP_VERIFY_COUPON_SHOW:
+                LiveCouponIssue issue = liveCouponIssueService.selectLiveCouponIssueById(bizId);
+                if (issue != null) {
+                    limitTime = issue.getLimitTime();
+                }
+                break;
+            case LiveConsoleOpLog.OP_RED_SETTLE:
+            case LiveConsoleOpLog.OP_RED_SEND:
+                LiveRedConf redConf = liveRedConfService.selectLiveRedConfByRedId(bizId);
+                if (redConf != null) {
+                    durationMinutes = redConf.getDuration();
+                }
+                break;
+            case LiveConsoleOpLog.OP_LOTTERY_SETTLE:
+            case LiveConsoleOpLog.OP_LOTTERY_SEND:
+                LiveLotteryConf lotteryConf = liveLotteryConfService.selectLiveLotteryConfByLotteryId(bizId);
+                if (lotteryConf != null) {
+                    durationMinutes = lotteryConf.getDuration();
+                }
+                break;
+            default:
+                break;
+        }
+
+        if (limitTime != null) {
+            return limitTime;
+        }
+        if (durationMinutes != null && durationMinutes > 0) {
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(opLog.getCreateTime());
+            calendar.add(Calendar.MINUTE, durationMinutes.intValue());
+            return calendar.getTime();
+        }
+        return null;
+    }
+
+    private boolean isBizEnded(LiveConsoleOpLog opLog) {
+        if (opLog == null || opLog.getOpType() == null || opLog.getBizId() == null) {
+            return false;
+        }
+        Integer opType = opLog.getOpType();
+        Long bizId = opLog.getBizId();
+
+        switch (opType) {
+            case LiveConsoleOpLog.OP_COUPON_SHOW:
+            case LiveConsoleOpLog.OP_VERIFY_COUPON_SHOW:
+                LiveCouponIssue issue = liveCouponIssueService.selectLiveCouponIssueById(bizId);
+                return issue == null
+                        || issue.getStatus() == null
+                        || issue.getStatus() != 1
+                        || (issue.getRemainCount() != null && issue.getRemainCount() <= 0);
+            case LiveConsoleOpLog.OP_RED_SETTLE:
+            case LiveConsoleOpLog.OP_RED_SEND:
+                LiveRedConf redConf = liveRedConfService.selectLiveRedConfByRedId(bizId);
+                return redConf != null && redConf.getRedStatus() != null && redConf.getRedStatus() == 2L;
+            case LiveConsoleOpLog.OP_LOTTERY_SETTLE:
+            case LiveConsoleOpLog.OP_LOTTERY_SEND:
+                LiveLotteryConf lotteryConf = liveLotteryConfService.selectLiveLotteryConfByLotteryId(bizId);
+                return lotteryConf != null && "2".equals(lotteryConf.getLotteryStatus());
+            default:
+                return false;
+        }
+    }
+
     /**
      * 判断是否为核销券 / 核销代金券类型
      */

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

@@ -10,4 +10,4 @@ public class LiveCompletionCouponAnswerResult {
 
     /** 是否全部答对 */
     private boolean allCorrect;
-}
+}

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

@@ -5,7 +5,7 @@ import lombok.Data;
 import java.math.BigDecimal;
 
 /**
- * Íê¿ÎÓÅ»ÝȯÐÅÏ¢
+ * 完课优惠券信�
  */
 @Data
 public class LiveCompletionCouponInfoVO {

+ 67 - 0
fs-service/src/main/java/com/fs/live/vo/LiveConsoleOpLogRecordVo.java

@@ -0,0 +1,67 @@
+package com.fs.live.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.live.domain.LiveConsoleOpLog;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * App 端直播间留存记录(含领取状态)
+ */
+@Data
+public class LiveConsoleOpLogRecordVo {
+
+    /** 状态:0待领取 1已领取 2已结束 */
+    public static final int STATUS_PENDING = 0;
+    public static final int STATUS_CLAIMED = 1;
+    public static final int STATUS_ENDED = 2;
+
+    private Long id;
+    private Long liveId;
+    private Integer opType;
+    private Integer handleType;
+    private Long bizId;
+    private String bizName;
+    private Long operatorId;
+    private String operatorName;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** 状态:0待领取 1已领取 2已结束 */
+    private Integer status;
+
+    /** 状态名称 */
+    private String statusName;
+
+    public static LiveConsoleOpLogRecordVo from(LiveConsoleOpLog log, int status) {
+        LiveConsoleOpLogRecordVo vo = new LiveConsoleOpLogRecordVo();
+        if (log == null) {
+            return vo;
+        }
+        vo.setId(log.getId());
+        vo.setLiveId(log.getLiveId());
+        vo.setOpType(log.getOpType());
+        vo.setHandleType(log.getHandleType());
+        vo.setBizId(log.getBizId());
+        vo.setBizName(log.getBizName());
+        vo.setOperatorId(log.getOperatorId());
+        vo.setOperatorName(log.getOperatorName());
+        vo.setCreateTime(log.getCreateTime());
+        vo.setStatus(status);
+        vo.setStatusName(resolveStatusName(status));
+        return vo;
+    }
+
+    public static String resolveStatusName(int status) {
+        switch (status) {
+            case STATUS_CLAIMED:
+                return "已领取";
+            case STATUS_ENDED:
+                return "已结束";
+            default:
+                return "待领取";
+        }
+    }
+}

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

@@ -63,4 +63,4 @@ public class LiveConsoleOpLogVo {
         vo.setCreateTime(log.getCreateTime());
         return vo;
     }
-}
+}

+ 8 - 1
fs-service/src/main/resources/mapper/live/LiveConsoleOpLogUserMapper.xml

@@ -28,4 +28,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where op_log_id = #{opLogId}
         order by id asc
     </select>
-</mapper>
+
+    <select id="selectByLiveIdAndUserId" resultMap="LiveConsoleOpLogUserResult">
+        select id, op_log_id, user_id, live_id, coupon_user_id, create_time
+        from live_console_op_log_user
+        where live_id = #{liveId} and user_id = #{userId}
+        order by id desc
+    </select>
+</mapper>

+ 6 - 68
fs-user-app/src/main/java/com/fs/app/controller/live/LiveController.java

@@ -98,6 +98,8 @@ public class LiveController extends AppBaseController {
     private ILiveCouponUserService liveCouponUserService;
     @Autowired
     private ILiveUserRedRecordService liveUserRedRecordService;
+    @Autowired
+    private ILiveConsoleOpLogService liveConsoleOpLogService;
 
 	/**
 	 * 查询未结束直播间(销售专用)
@@ -408,9 +410,9 @@ public class LiveController extends AppBaseController {
 	}
 
 	/**
-	 * 查询当前用户在当前直播间获得的奖品记录
+	 * 查询当前用户在当前直播间的奖品留存记录
 	 * @param liveId 直播间ID
-	 * @return 奖品记录列表(积分、优惠券、红包等
+	 * @return 留存记录列表(含待领取/已领取/已结束状态
 	 */
 	@Login
 	@ApiOperation("查询我的直播间奖品记录")
@@ -418,73 +420,9 @@ public class LiveController extends AppBaseController {
 	public R myRewardRecords(@RequestParam Long liveId) {
 		try {
 			Long userId = Long.valueOf(getUserId());
-
-			// 查询奖励记录(积分、现金、优惠券等)
-			LiveRewardRecord rewardQuery = new LiveRewardRecord();
-			rewardQuery.setLiveId(liveId);
-			rewardQuery.setUserId(userId);
-			rewardQuery.setIncomeType(1L); // 收入类型
-			List<LiveRewardRecord> rewardRecords = liveRewardRecordService.selectLiveRewardRecordList(rewardQuery);
-
-			// 从奖励记录中提取优惠券ID(rewardType=3时,sourceId为couponId)
-			List<Long> couponIds = rewardRecords.stream()
-					.filter(r -> r.getRewardType() != null && r.getRewardType() == 3)
-					.map(LiveRewardRecord::getSourceId)
-					.filter(Objects::nonNull)
-					.distinct()
-					.collect(Collectors.toList());
-
-			// 查询优惠券详情
-			List<LiveCouponUser> liveCoupons = new ArrayList<>();
-			if (!couponIds.isEmpty()) {
-				LiveCouponUser couponQuery = new LiveCouponUser();
-				couponQuery.setUserId(userId.intValue());
-				List<LiveCouponUser> allUserCoupons = liveCouponUserService.selectLiveCouponUserList(couponQuery);
-				// 过滤出当前直播间获得的优惠券
-				liveCoupons = allUserCoupons.stream()
-						.filter(c -> c.getCouponId() != null && couponIds.contains(c.getCouponId()))
-						.collect(Collectors.toList());
-			}
-
-			// 查询红包记录
-			LiveUserRedRecord redQuery = new LiveUserRedRecord();
-			redQuery.setLiveId(liveId);
-			redQuery.setUserId(userId);
-			List<LiveUserRedRecord> redRecords = liveUserRedRecordService.selectLiveUserRedRecordList(redQuery);
-
-			// 整合结果
-			Map<String, Object> result = new HashMap<>();
-			result.put("rewardRecords", rewardRecords);  // 积分、现金奖励记录
-			result.put("couponRecords", liveCoupons);     // 优惠券记录
-			result.put("redRecords", redRecords);          // 红包记录
-
-			// 统计
-			Map<String, Object> statistics = new HashMap<>();
-			statistics.put("totalRewards", rewardRecords.size());
-			statistics.put("totalCoupons", liveCoupons.size());
-			statistics.put("totalReds", redRecords.size());
-
-			// 计算总积分
-			BigDecimal totalPoints = rewardRecords.stream()
-					.filter(r -> r.getRewardType() != null && r.getRewardType() == 2)
-					.map(LiveRewardRecord::getNum)
-					.filter(Objects::nonNull)
-					.reduce(BigDecimal.ZERO, BigDecimal::add);
-			statistics.put("totalPoints", totalPoints);
-
-			// 计算总现金
-			BigDecimal totalCash = rewardRecords.stream()
-					.filter(r -> r.getRewardType() != null && r.getRewardType() == 1)
-					.map(LiveRewardRecord::getNum)
-					.filter(Objects::nonNull)
-					.reduce(BigDecimal.ZERO, BigDecimal::add);
-			statistics.put("totalCash", totalCash);
-
-			result.put("statistics", statistics);
-
-			return R.ok().put("data", result);
+			return R.ok().put("data", liveConsoleOpLogService.listUserOpLogRecords(liveId, userId));
 		} catch (Exception e) {
-			log.error("查询奖品记录失败, liveId={}, userId={}", liveId, getUserId(), e);
+			log.error("查询奖品留存记录失败, liveId={}, userId={}", liveId, getUserId(), e);
 			return R.error("查询奖品记录失败: " + e.getMessage());
 		}
 	}