|
|
@@ -25,6 +25,7 @@ import com.fs.live.service.ILiveLotteryConfService;
|
|
|
import com.fs.live.service.ILiveRedConfService;
|
|
|
import com.fs.live.utils.LiveCompletionConfigUtils;
|
|
|
import com.fs.live.vo.LiveConsoleOpLogRecordVo;
|
|
|
+import com.fs.live.vo.LiveUserClaimRecordVo;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
@@ -768,4 +769,244 @@ public class LiveConsoleOpLogServiceImpl implements ILiveConsoleOpLogService {
|
|
|
return StringUtils.isNotEmpty(typeLabel)
|
|
|
&& (typeLabel.contains("核销") || typeLabel.contains("核销券"));
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 管理端已领取明细:与 App listUserOpLogRecords 同一套领取判定,券类再关联 live_coupon_user 核销状态。
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<LiveUserClaimRecordVo> listUserClaimRecords(Long liveId, Long userId) {
|
|
|
+ List<LiveConsoleOpLogRecordVo> opRecords = listUserOpLogRecords(liveId, userId);
|
|
|
+ if (opRecords == null || opRecords.isEmpty()) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ List<LiveConsoleOpLogRecordVo> claimed = opRecords.stream()
|
|
|
+ .filter(r -> r.getStatus() != null && r.getStatus() == LiveConsoleOpLogRecordVo.STATUS_CLAIMED)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ if (claimed.isEmpty()) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ List<LiveConsoleOpLogUser> relations = liveConsoleOpLogUserMapper.selectByLiveIdAndUserId(liveId, userId);
|
|
|
+ Map<Long, List<Long>> couponUserIdsByOpLogId = buildCouponUserIdsByOpLogId(relations);
|
|
|
+ Map<Long, LiveCouponUser> couponUserMap = loadCouponUserMap(couponUserIdsByOpLogId);
|
|
|
+
|
|
|
+ List<LiveUserClaimRecordVo> result = new ArrayList<>();
|
|
|
+ for (LiveConsoleOpLogRecordVo opRecord : claimed) {
|
|
|
+ if (opRecord == null || opRecord.getOpType() == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (isCouponClaimOpType(opRecord.getOpType())) {
|
|
|
+ result.addAll(buildCouponClaimRows(opRecord, couponUserIdsByOpLogId, couponUserMap, liveId, userId));
|
|
|
+ } else {
|
|
|
+ result.add(buildNonCouponClaimRow(opRecord));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isCouponClaimOpType(int opType) {
|
|
|
+ return opType == LiveConsoleOpLog.OP_COUPON_SHOW
|
|
|
+ || opType == LiveConsoleOpLog.OP_VERIFY_COUPON_SHOW
|
|
|
+ || opType == LiveConsoleOpLog.OP_COMPLETION_COUPON
|
|
|
+ || opType == LiveConsoleOpLog.OP_WATCH_REWARD_COUPON;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<Long, List<Long>> buildCouponUserIdsByOpLogId(List<LiveConsoleOpLogUser> relations) {
|
|
|
+ Map<Long, List<Long>> map = new HashMap<>();
|
|
|
+ if (relations == null || relations.isEmpty()) {
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+ for (LiveConsoleOpLogUser relation : relations) {
|
|
|
+ if (relation == null || relation.getOpLogId() == null || relation.getCouponUserId() == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ map.computeIfAbsent(relation.getOpLogId(), key -> new ArrayList<>()).add(relation.getCouponUserId());
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<Long, LiveCouponUser> loadCouponUserMap(Map<Long, List<Long>> couponUserIdsByOpLogId) {
|
|
|
+ Map<Long, LiveCouponUser> map = new HashMap<>();
|
|
|
+ if (couponUserIdsByOpLogId == null || couponUserIdsByOpLogId.isEmpty()) {
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+ List<Long> ids = couponUserIdsByOpLogId.values().stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .flatMap(List::stream)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ if (ids.isEmpty()) {
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+ // 详情查询带核销人姓名,与优惠券用户列表页一致
|
|
|
+ List<com.fs.live.vo.LiveCouponUserDetailVo> details =
|
|
|
+ liveCouponUserService.selectLiveCouponUserDetailByIds(ids);
|
|
|
+ if (details == null || details.isEmpty()) {
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+ for (com.fs.live.vo.LiveCouponUserDetailVo detail : details) {
|
|
|
+ if (detail == null || detail.getId() == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ LiveCouponUser couponUser = new LiveCouponUser();
|
|
|
+ couponUser.setId(detail.getId());
|
|
|
+ couponUser.setCouponId(detail.getCouponId());
|
|
|
+ couponUser.setUserId(detail.getUserId());
|
|
|
+ couponUser.setCouponTitle(detail.getCouponTitle());
|
|
|
+ couponUser.setCouponPrice(detail.getCouponPrice());
|
|
|
+ couponUser.setCreateTime(detail.getCreateTime());
|
|
|
+ couponUser.setUseTime(detail.getUseTime());
|
|
|
+ couponUser.setStatus(detail.getStatus());
|
|
|
+ couponUser.setVerifyTime(detail.getVerifyTime());
|
|
|
+ couponUser.setVerifyUserId(detail.getVerifyUserId());
|
|
|
+ couponUser.setVerifyUserName(detail.getVerifyUserName());
|
|
|
+ couponUser.setIsDel(0);
|
|
|
+ map.put(detail.getId(), couponUser);
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ private LiveUserClaimRecordVo buildNonCouponClaimRow(LiveConsoleOpLogRecordVo opRecord) {
|
|
|
+ LiveUserClaimRecordVo vo = new LiveUserClaimRecordVo();
|
|
|
+ vo.setOpLogId(opRecord.getId());
|
|
|
+ vo.setOpType(opRecord.getOpType());
|
|
|
+ vo.setOpTypeName(LiveUserClaimRecordVo.resolveOpTypeName(opRecord.getOpType()));
|
|
|
+ vo.setBizId(opRecord.getBizId());
|
|
|
+ vo.setBizName(opRecord.getBizName());
|
|
|
+ vo.setCreateTime(opRecord.getCreateTime());
|
|
|
+ vo.setCouponCount(opRecord.getCouponCount() != null && opRecord.getCouponCount() > 0
|
|
|
+ ? opRecord.getCouponCount() : 1);
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 券类按 live_coupon_user 展开为多行,保证核销状态与领取明细一致;无绑定记录时兜底查本场领取券。
|
|
|
+ */
|
|
|
+ private List<LiveUserClaimRecordVo> buildCouponClaimRows(LiveConsoleOpLogRecordVo opRecord,
|
|
|
+ Map<Long, List<Long>> couponUserIdsByOpLogId,
|
|
|
+ Map<Long, LiveCouponUser> couponUserMap,
|
|
|
+ Long liveId, Long userId) {
|
|
|
+ List<LiveCouponUser> couponUsers = resolveCouponUsersForClaim(
|
|
|
+ opRecord, couponUserIdsByOpLogId, couponUserMap, liveId, userId);
|
|
|
+ if (couponUsers.isEmpty()) {
|
|
|
+ // 已判定领取但暂无券明细时,仍返回留存行,核销状态留空
|
|
|
+ LiveUserClaimRecordVo vo = buildNonCouponClaimRow(opRecord);
|
|
|
+ return Collections.singletonList(vo);
|
|
|
+ }
|
|
|
+ List<LiveUserClaimRecordVo> rows = new ArrayList<>(couponUsers.size());
|
|
|
+ for (LiveCouponUser couponUser : couponUsers) {
|
|
|
+ LiveUserClaimRecordVo vo = new LiveUserClaimRecordVo();
|
|
|
+ vo.setOpLogId(opRecord.getId());
|
|
|
+ vo.setOpType(opRecord.getOpType());
|
|
|
+ vo.setOpTypeName(LiveUserClaimRecordVo.resolveOpTypeName(opRecord.getOpType()));
|
|
|
+ vo.setBizId(opRecord.getBizId());
|
|
|
+ vo.setBizName(StringUtils.isNotEmpty(couponUser.getCouponTitle())
|
|
|
+ ? couponUser.getCouponTitle() : opRecord.getBizName());
|
|
|
+ vo.setCreateTime(couponUser.getCreateTime() != null
|
|
|
+ ? couponUser.getCreateTime() : opRecord.getCreateTime());
|
|
|
+ vo.setCouponCount(1);
|
|
|
+ vo.setCouponUserId(couponUser.getId());
|
|
|
+ vo.setCouponPrice(couponUser.getCouponPrice());
|
|
|
+ vo.setVerifyStatus(couponUser.getStatus());
|
|
|
+ vo.setVerifyStatusName(LiveUserClaimRecordVo.resolveVerifyStatusName(couponUser.getStatus()));
|
|
|
+ vo.setVerifyTime(couponUser.getVerifyTime() != null
|
|
|
+ ? couponUser.getVerifyTime() : couponUser.getUseTime());
|
|
|
+ vo.setVerifyUserName(couponUser.getVerifyUserName());
|
|
|
+ rows.add(vo);
|
|
|
+ }
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<LiveCouponUser> resolveCouponUsersForClaim(LiveConsoleOpLogRecordVo opRecord,
|
|
|
+ Map<Long, List<Long>> couponUserIdsByOpLogId,
|
|
|
+ Map<Long, LiveCouponUser> couponUserMap,
|
|
|
+ Long liveId, Long userId) {
|
|
|
+ List<LiveCouponUser> result = new ArrayList<>();
|
|
|
+ List<Long> boundIds = couponUserIdsByOpLogId != null
|
|
|
+ ? couponUserIdsByOpLogId.get(opRecord.getId()) : null;
|
|
|
+ if (boundIds != null && !boundIds.isEmpty()) {
|
|
|
+ for (Long id : boundIds) {
|
|
|
+ LiveCouponUser couponUser = couponUserMap.get(id);
|
|
|
+ if (couponUser == null) {
|
|
|
+ com.fs.live.vo.LiveCouponUserDetailVo detail =
|
|
|
+ liveCouponUserService.selectLiveCouponUserDetailById(id);
|
|
|
+ if (detail != null) {
|
|
|
+ couponUser = new LiveCouponUser();
|
|
|
+ couponUser.setId(detail.getId());
|
|
|
+ couponUser.setCouponId(detail.getCouponId());
|
|
|
+ couponUser.setUserId(detail.getUserId());
|
|
|
+ couponUser.setCouponTitle(detail.getCouponTitle());
|
|
|
+ couponUser.setCouponPrice(detail.getCouponPrice());
|
|
|
+ couponUser.setCreateTime(detail.getCreateTime());
|
|
|
+ couponUser.setUseTime(detail.getUseTime());
|
|
|
+ couponUser.setStatus(detail.getStatus());
|
|
|
+ couponUser.setVerifyTime(detail.getVerifyTime());
|
|
|
+ couponUser.setVerifyUserId(detail.getVerifyUserId());
|
|
|
+ couponUser.setVerifyUserName(detail.getVerifyUserName());
|
|
|
+ couponUser.setIsDel(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (couponUser != null && (couponUser.getIsDel() == null || couponUser.getIsDel() == 0)) {
|
|
|
+ result.add(couponUser);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!result.isEmpty()) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 兜底:与 listUserOpLogRecords 一致,按本场 type + couponId 对齐领取券
|
|
|
+ return loadFallbackCouponUsers(opRecord, liveId, userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<LiveCouponUser> loadFallbackCouponUsers(LiveConsoleOpLogRecordVo opRecord,
|
|
|
+ Long liveId, Long userId) {
|
|
|
+ if (opRecord == null || opRecord.getOpType() == null || userId == null) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ String type = resolveCouponUserType(opRecord.getOpType(), liveId);
|
|
|
+ if (StringUtils.isEmpty(type)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ Long couponId = resolveCouponIdForOpRecord(opRecord);
|
|
|
+ LiveCouponUser query = new LiveCouponUser();
|
|
|
+ query.setUserId(userId.intValue());
|
|
|
+ query.setType(type);
|
|
|
+ query.setIsDel(0);
|
|
|
+ if (couponId != null) {
|
|
|
+ query.setCouponId(couponId);
|
|
|
+ }
|
|
|
+ List<LiveCouponUser> list = liveCouponUserService.selectLiveCouponUserList(query);
|
|
|
+ return list != null ? list : Collections.emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String resolveCouponUserType(int opType, Long liveId) {
|
|
|
+ if (liveId == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (opType == LiveConsoleOpLog.OP_COUPON_SHOW || opType == LiveConsoleOpLog.OP_VERIFY_COUPON_SHOW) {
|
|
|
+ return LIVE_COUPON_USER_TYPE_PREFIX + liveId;
|
|
|
+ }
|
|
|
+ if (opType == LiveConsoleOpLog.OP_COMPLETION_COUPON) {
|
|
|
+ return COMPLETION_COUPON_USER_TYPE_PREFIX + liveId;
|
|
|
+ }
|
|
|
+ // 观看奖励优惠券 type 无直播间维度,不做跨场兜底
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Long resolveCouponIdForOpRecord(LiveConsoleOpLogRecordVo opRecord) {
|
|
|
+ if (opRecord == null || opRecord.getOpType() == null || opRecord.getBizId() == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ int opType = opRecord.getOpType();
|
|
|
+ if (opType == LiveConsoleOpLog.OP_COMPLETION_COUPON
|
|
|
+ || opType == LiveConsoleOpLog.OP_WATCH_REWARD_COUPON) {
|
|
|
+ return opRecord.getBizId();
|
|
|
+ }
|
|
|
+ if (opType == LiveConsoleOpLog.OP_COUPON_SHOW || opType == LiveConsoleOpLog.OP_VERIFY_COUPON_SHOW) {
|
|
|
+ LiveCouponIssue issue = liveCouponIssueService.selectLiveCouponIssueById(opRecord.getBizId());
|
|
|
+ return issue != null ? issue.getCouponId() : null;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
}
|