Преглед изворни кода

直播代码 websocket添加状态(主要用于直播信息传递

yuhongqi пре 1 дан
родитељ
комит
bf6b0687d5
24 измењених фајлова са 694 додато и 27 уклоњено
  1. 103 0
      fs-company/src/main/java/com/fs/company/controller/live/LiveUserFirstEntryController.java
  2. 10 1
      fs-live-app/src/main/java/com/fs/app/controller/LiveLotteryController.java
  3. 87 4
      fs-live-app/src/main/java/com/fs/app/task/Task.java
  4. 17 0
      fs-live-app/src/main/java/com/fs/app/vo/LotteryVo.java
  5. 1 0
      fs-live-app/src/main/java/com/fs/app/websocket/bean/SendMsgVo.java
  6. 21 1
      fs-live-app/src/main/java/com/fs/app/websocket/service/WebSocketServer.java
  7. 43 0
      fs-service/src/main/java/com/fs/live/domain/LiveUserFirstEntry.java
  8. 6 0
      fs-service/src/main/java/com/fs/live/mapper/LiveLotteryConfMapper.java
  9. 2 0
      fs-service/src/main/java/com/fs/live/mapper/LiveLotteryRegistrationMapper.java
  10. 67 0
      fs-service/src/main/java/com/fs/live/mapper/LiveUserFirstEntryMapper.java
  11. 5 0
      fs-service/src/main/java/com/fs/live/mapper/LiveWatchUserMapper.java
  12. 8 0
      fs-service/src/main/java/com/fs/live/service/ILiveLotteryConfService.java
  13. 63 0
      fs-service/src/main/java/com/fs/live/service/ILiveUserFirstEntryService.java
  14. 3 0
      fs-service/src/main/java/com/fs/live/service/ILiveWatchUserService.java
  15. 1 2
      fs-service/src/main/java/com/fs/live/service/impl/LiveAutoTaskServiceImpl.java
  16. 0 11
      fs-service/src/main/java/com/fs/live/service/impl/LiveDataServiceImpl.java
  17. 44 7
      fs-service/src/main/java/com/fs/live/service/impl/LiveLotteryConfServiceImpl.java
  18. 1 1
      fs-service/src/main/java/com/fs/live/service/impl/LiveRedConfServiceImpl.java
  19. 101 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveUserFirstEntryServiceImpl.java
  20. 5 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java
  21. 11 0
      fs-service/src/main/resources/mapper/live/LiveLotteryConfMapper.xml
  22. 15 0
      fs-service/src/main/resources/mapper/live/LiveLotteryRegistrationMapper.xml
  23. 1 0
      fs-service/src/main/resources/mapper/live/LiveRedConfMapper.xml
  24. 79 0
      fs-service/src/main/resources/mapper/live/LiveUserFirstEntryMapper.xml

+ 103 - 0
fs-company/src/main/java/com/fs/company/controller/live/LiveUserFirstEntryController.java

@@ -0,0 +1,103 @@
+package com.fs.company.controller.live;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.live.domain.LiveUserFirstEntry;
+import com.fs.live.service.ILiveUserFirstEntryService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 用户每日首次进入直播间记录Controller
+ *
+ * @author fs
+ * @date 2025-09-04
+ */
+@RestController
+@RequestMapping("/live/entry")
+public class LiveUserFirstEntryController extends BaseController
+{
+    @Autowired
+    private ILiveUserFirstEntryService liveUserFirstEntryService;
+
+    /**
+     * 查询用户每日首次进入直播间记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:entry:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveUserFirstEntry liveUserFirstEntry)
+    {
+        startPage();
+        List<LiveUserFirstEntry> list = liveUserFirstEntryService.selectLiveUserFirstEntryList(liveUserFirstEntry);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户每日首次进入直播间记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:entry:export')")
+    @Log(title = "用户每日首次进入直播间记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveUserFirstEntry liveUserFirstEntry)
+    {
+        List<LiveUserFirstEntry> list = liveUserFirstEntryService.selectLiveUserFirstEntryList(liveUserFirstEntry);
+        ExcelUtil<LiveUserFirstEntry> util = new ExcelUtil<LiveUserFirstEntry>(LiveUserFirstEntry.class);
+        return util.exportExcel(list, "用户每日首次进入直播间记录数据");
+    }
+
+    /**
+     * 获取用户每日首次进入直播间记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:entry:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveUserFirstEntryService.selectLiveUserFirstEntryById(id));
+    }
+
+    /**
+     * 新增用户每日首次进入直播间记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:entry:add')")
+    @Log(title = "用户每日首次进入直播间记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveUserFirstEntry liveUserFirstEntry)
+    {
+        return toAjax(liveUserFirstEntryService.insertLiveUserFirstEntry(liveUserFirstEntry));
+    }
+
+    /**
+     * 修改用户每日首次进入直播间记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:entry:edit')")
+    @Log(title = "用户每日首次进入直播间记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveUserFirstEntry liveUserFirstEntry)
+    {
+        return toAjax(liveUserFirstEntryService.updateLiveUserFirstEntry(liveUserFirstEntry));
+    }
+
+    /**
+     * 删除用户每日首次进入直播间记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:entry:remove')")
+    @Log(title = "用户每日首次进入直播间记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveUserFirstEntryService.deleteLiveUserFirstEntryByIds(ids));
+    }
+}

+ 10 - 1
fs-live-app/src/main/java/com/fs/app/controller/LiveLotteryController.java

@@ -27,7 +27,7 @@ public class LiveLotteryController extends AppBaseController{
     }
 
     /**
-     * 领取红包
+     * 参与抽奖
      * */
     @Login
     @PostMapping("/claim")
@@ -36,4 +36,13 @@ public class LiveLotteryController extends AppBaseController{
         return liveLotteryConfService.claimLotteryPacket(lottery);
     }
 
+    /**
+     * 查询抽奖信息
+     * */
+    @Login
+    @PostMapping("/detail")
+    public R detail(@RequestBody LotteryPO lottery) {
+        return liveLotteryConfService.detail(lottery);
+    }
+
 }

+ 87 - 4
fs-live-app/src/main/java/com/fs/app/task/Task.java

@@ -1,27 +1,33 @@
 package com.fs.app.task;
 
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fs.app.vo.LotteryVo;
+import com.fs.app.websocket.bean.SendMsgVo;
 import com.fs.app.websocket.service.WebSocketServer;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.spring.SpringUtils;
 import com.fs.his.service.IFsUserService;
 import com.fs.live.domain.*;
+import com.fs.live.mapper.LiveLotteryRegistrationMapper;
 import com.fs.live.service.*;
+import com.fs.live.vo.LiveLotteryConfVo;
+import com.fs.live.vo.LiveLotteryProductListVo;
 import lombok.AllArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.websocket.Session;
 import java.math.BigDecimal;
 import java.time.Instant;
 import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
 @Component
@@ -44,6 +50,12 @@ public class Task {
     private WebSocketServer webSocketServer;
     @Autowired
     private ILiveAutoTaskService liveAutoTaskService;
+    @Autowired
+    private ILiveLotteryConfService liveLotteryConfService;
+    @Autowired
+    private ILiveUserLotteryRecordService liveUserLotteryRecordService;
+    @Autowired
+    private LiveLotteryRegistrationMapper liveLotteryRegistrationMapper;
 
     @Scheduled(cron = "0 0/1 * * * ?")
     //public void selectSopUserLogsListByTime() {
@@ -92,6 +104,77 @@ public class Task {
             liveService.updateBatchById(list);
         }
     }
+    @Scheduled(cron = "0/1 * * * * ?")
+    public void liveLotteryTask() {
+        long currentTime = Instant.now().toEpochMilli(); // 当前时间戳(毫秒)
+        String key = "live:lottery_task";
+
+        Set<String> range = redisCache.redisTemplate.opsForZSet().rangeByScore(key, 0, currentTime);
+        if (range == null || range.isEmpty()) {
+            return;
+        }
+        redisCache.redisTemplate.opsForZSet()
+                .removeRangeByScore(key, 0, currentTime);
+        processLotteryTask(range);
+    }
+
+    private void processLotteryTask(Set<String> range) {
+        List<LiveLotteryConfVo> liveLotteries = liveLotteryConfService.selectVoListByLotteryIds(range);
+        if(liveLotteries.isEmpty()) return;
+        Date now = new Date();
+        for (LiveLotteryConfVo liveLottery : liveLotteries) {
+            // 查询抽奖数量
+            List<LiveLotteryProductListVo> products = liveLottery.getProducts();
+            Integer totalLots = products.stream().mapToInt(liveLotteryProductListVo -> Math.toIntExact(liveLotteryProductListVo.getTotalLots())).sum();
+            if(totalLots <= 0) continue;
+            // 查询在线用户 并且参与了抽奖的用户
+            List<LiveWatchUser> liveWatchUsers = liveWatchUserService.selectLiveWatchAndRegisterUser(liveLottery.getLiveId(),liveLottery.getLotteryId(), totalLots);
+            if(liveWatchUsers.isEmpty()) continue;
+            LiveLotteryRegistration liveLotteryRegistration;
+            // 收集中奖信息
+            List<LotteryVo> lotteryVos = new ArrayList<>();
+            for (LiveLotteryProductListVo liveLotteryProductListVo : products) {
+                // 随机抽奖一个用户获取奖品
+                Long totalLotsPerProduct = liveLotteryProductListVo.getTotalLots();
+                for (int i = 0; i < totalLotsPerProduct && !liveWatchUsers.isEmpty(); i++) {
+                    // 随机选择一个用户
+                    int randomIndex = new java.util.Random().nextInt(liveWatchUsers.size());
+                    LiveWatchUser winningUser = liveWatchUsers.get(randomIndex);
+
+                    // 创建中奖记录
+                    LiveUserLotteryRecord record = new LiveUserLotteryRecord();
+                    record.setLotteryId(liveLottery.getLotteryId());
+                    record.setLiveId(liveLottery.getLiveId());
+                    record.setUserId(winningUser.getUserId());
+                    record.setProductId(liveLotteryProductListVo.getProductId());
+                    record.setCreateTime(new Date());
+
+                    // 保存中奖记录
+                    liveUserLotteryRecordService.insertLiveUserLotteryRecord(record);
+                    liveLotteryRegistration = new LiveLotteryRegistration();
+                    liveLotteryRegistration.setLotteryId(liveLottery.getLotteryId());
+                    liveLotteryRegistration.setLiveId(liveLottery.getLotteryId());
+                    liveLotteryRegistration.setUserId(winningUser.getUserId());
+                    liveLotteryRegistration.setIsWin(1L);
+                    liveLotteryRegistration.setUpdateTime(now);
+                    liveLotteryRegistration.setRizeLevel(liveLotteryProductListVo.getPrizeLevel());
+                    liveLotteryRegistrationMapper.updateLiveLotteryRegistrationNoId(liveLotteryRegistration);
+                    // 从候选列表中移除该用户,确保每人只能中奖一次
+                    liveWatchUsers.remove(randomIndex);
+                    LotteryVo lotteryVo = new LotteryVo();
+                    lotteryVo.setUserId(winningUser.getUserId());
+                    lotteryVo.setPrizeLevel(liveLotteryProductListVo.getPrizeLevel());
+                    lotteryVo.setProductName(liveLotteryProductListVo.getProductName());
+                    lotteryVos.add(lotteryVo);
+                }
+            }
+            SendMsgVo sendMsgVo = new SendMsgVo();
+            sendMsgVo.setLiveId(liveLottery.getLiveId());
+            sendMsgVo.setCmd("LotteryDetail");
+            sendMsgVo.setData(JSON.toJSONString(lotteryVos));
+            webSocketServer.broadcastMessage(liveLottery.getLotteryId(), JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+        }
+    }
 
     @Scheduled(cron = "0/1 * * * * ?")
     public void liveAutoTask() {

+ 17 - 0
fs-live-app/src/main/java/com/fs/app/vo/LotteryVo.java

@@ -0,0 +1,17 @@
+package com.fs.app.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class LotteryVo {
+    // 中奖信息
+    private String userName;
+    private Long userId;
+    private String productName;
+    private Long prizeLevel;
+
+}

+ 1 - 0
fs-live-app/src/main/java/com/fs/app/websocket/bean/SendMsgVo.java

@@ -32,5 +32,6 @@ public class SendMsgVo {
     @ApiModelProperty("头像")
     private String avatar;
     private boolean on = false;
+    private Integer status;
 
 }

+ 21 - 1
fs-live-app/src/main/java/com/fs/app/websocket/service/WebSocketServer.java

@@ -51,6 +51,7 @@ public class WebSocketServer {
     private final ILiveRedConfService liveRedConfService =  SpringUtils.getBean(ILiveRedConfService.class);
     private final ILiveLotteryConfService liveLotteryConfService =  SpringUtils.getBean(ILiveLotteryConfService.class);
     private final ILiveGoodsService liveGoodsService =  SpringUtils.getBean(ILiveGoodsService.class);
+    private final ILiveUserFirstEntryService liveUserFirstEntryService =  SpringUtils.getBean(ILiveUserFirstEntryService.class);
     // 直播间在线用户缓存
 //    private static final ConcurrentHashMap<Long, Integer> liveOnlineUsers = new ConcurrentHashMap<>();
 
@@ -107,7 +108,8 @@ public class WebSocketServer {
             if (isFirstViewer) {
                 redisCache.increment(UNIQUE_VIEWERS_KEY + liveId, 1);
             }
-
+            LiveWatchUser liveWatchUser = liveWatchUserService.getByLiveIdAndUserId(liveId, userId);
+            liveWatchUserVO.setMsgStatus(liveWatchUser.getMsgStatus());
             SendMsgVo sendMsgVo = new SendMsgVo();
             sendMsgVo.setLiveId(liveId);
             sendMsgVo.setUserId(userId);
@@ -117,6 +119,17 @@ public class WebSocketServer {
             sendMsgVo.setData(JSONObject.toJSONString(liveWatchUserVO));
             sendMsgVo.setNickName(fsUser.getNickName());
             sendMsgVo.setAvatar(fsUser.getAvatar());
+            int i = liveUserFirstEntryService.selectTodayEntry(userId);
+            if (!(i > 0)) {
+                Date date = new Date();
+                LiveUserFirstEntry liveUserFirstEntry = new LiveUserFirstEntry();
+                liveUserFirstEntry.setUserId(userId);
+                liveUserFirstEntry.setLiveId(liveId);
+                liveUserFirstEntry.setEntryDate(date);
+                liveUserFirstEntry.setFirstEntryTime(date);
+                liveUserFirstEntry.setUpdateTime( date);
+                liveUserFirstEntryService.insertLiveUserFirstEntry(liveUserFirstEntry);
+            }
 
             // 广播连接消息
             broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
@@ -246,6 +259,8 @@ public class WebSocketServer {
         JSONObject jsonObject = JSON.parseObject(msg.getData());
         Long goodsId = jsonObject.getLong("goodsId");
         Long liveId = jsonObject.getLong("liveId");
+        Integer status = jsonObject.getInteger("status");
+        msg.setStatus(status);
         LiveGoodsVo liveGoods = liveGoodsService.selectLiveGoodsVoByGoodsId(goodsId);
         if(liveGoods == null) return;
         msg.setLiveId(liveId);
@@ -259,6 +274,8 @@ public class WebSocketServer {
     private void processRed(Long liveId, SendMsgVo msg) {
         log.debug("redData: {}", msg);
         JSONObject jsonObject = JSON.parseObject(msg.getData());
+        Integer status = jsonObject.getInteger("status");
+        msg.setStatus( status);
         LiveRedConf liveRedConf = liveRedConfService.selectLiveRedConfByRedId(jsonObject.getLong("redId"));
         if (Objects.nonNull(liveRedConf)) {
             msg.setData(JSONObject.toJSONString(liveRedConf));
@@ -272,6 +289,8 @@ public class WebSocketServer {
     private void processLottery(Long liveId, SendMsgVo msg) {
         log.debug("lotteryData: {}", msg);
         JSONObject jsonObject = JSON.parseObject(msg.getData());
+        Integer status = jsonObject.getInteger("status");
+        msg.setStatus( status);
         LiveLotteryConf liveLotteryConf = liveLotteryConfService.selectLiveLotteryConfByLotteryId(jsonObject.getLong("lotteryId"));
         if (Objects.nonNull(liveLotteryConf)) {
             msg.setData(JSONObject.toJSONString(liveLotteryConf));
@@ -414,6 +433,7 @@ public class WebSocketServer {
             } catch (Exception e) {
                 log.error("定时任务执行异常:{}", e.getMessage());
             }
+            msg.setStatus(1);
             broadcastMessage(task.getLiveId(), JSONObject.toJSONString(R.ok().put("data", msg)));
         }
     }

+ 43 - 0
fs-service/src/main/java/com/fs/live/domain/LiveUserFirstEntry.java

@@ -0,0 +1,43 @@
+package com.fs.live.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 用户每日首次进入直播间记录对象 live_user_first_entry
+ *
+ * @author fs
+ * @date 2025-09-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class LiveUserFirstEntry extends BaseEntity{
+
+    /** 主键ID */
+    private Long id;
+
+    /** 用户ID */
+    @Excel(name = "用户ID")
+    private Long userId;
+
+    /** 直播间ID */
+    @Excel(name = "直播间ID")
+    private Long liveId;
+
+    /** 进入日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "进入日期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date entryDate;
+
+    /** 当天首次进入时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "当天首次进入时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date firstEntryTime;
+
+
+}

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

@@ -1,6 +1,8 @@
 package com.fs.live.mapper;
 
 import java.util.List;
+import java.util.Set;
+
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.live.domain.LiveLotteryConf;
 import com.fs.live.vo.LiveLotteryConfVo;
@@ -90,4 +92,8 @@ public interface LiveLotteryConfMapper extends BaseMapper<LiveLotteryConf>{
     @Select("SELECT * FROM live_lottery_conf WHERE live_id = #{liveId} AND lottery_status = 1 " +
             "AND lottery_id NOT IN (SELECT live_id FROM live_lottery_registration WHERE user_id = #{userId} AND is_win = 1)")
     List<LiveLotteryConfVo> selectActivedLottery(@Param("liveId") Long liveId, @Param("userId") String userId);
+
+    List<LiveLotteryConfVo> selectByLotteryIds(@Param("ids") Set<String> ids);
+
+    LiveLotteryConfVo selectLiveLotteryConfVoByLotteryId(@Param("lotteryId") Long lotteryId);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveLotteryRegistrationMapper.java

@@ -63,4 +63,6 @@ public interface LiveLotteryRegistrationMapper extends BaseMapper<LiveLotteryReg
 
     @Select("select count(1) from live_lottery_registration where user_id=#{userId} and lottery_id=#{lotteryId}")
     int selectRecord(@Param("userId") Long userId,@Param("lotteryId") Long lotteryId);
+
+    int updateLiveLotteryRegistrationNoId(LiveLotteryRegistration liveLotteryRegistration);
 }

+ 67 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveUserFirstEntryMapper.java

@@ -0,0 +1,67 @@
+package com.fs.live.mapper;
+
+import java.util.Date;
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.live.domain.LiveUserFirstEntry;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+/**
+ * 用户每日首次进入直播间记录Mapper接口
+ *
+ * @author fs
+ * @date 2025-09-04
+ */
+public interface LiveUserFirstEntryMapper extends BaseMapper<LiveUserFirstEntry>{
+    /**
+     * 查询用户每日首次进入直播间记录
+     *
+     * @param id 用户每日首次进入直播间记录主键
+     * @return 用户每日首次进入直播间记录
+     */
+    LiveUserFirstEntry selectLiveUserFirstEntryById(Long id);
+
+    /**
+     * 查询用户每日首次进入直播间记录列表
+     *
+     * @param liveUserFirstEntry 用户每日首次进入直播间记录
+     * @return 用户每日首次进入直播间记录集合
+     */
+    List<LiveUserFirstEntry> selectLiveUserFirstEntryList(LiveUserFirstEntry liveUserFirstEntry);
+
+    /**
+     * 新增用户每日首次进入直播间记录
+     *
+     * @param liveUserFirstEntry 用户每日首次进入直播间记录
+     * @return 结果
+     */
+    int insertLiveUserFirstEntry(LiveUserFirstEntry liveUserFirstEntry);
+
+    /**
+     * 修改用户每日首次进入直播间记录
+     *
+     * @param liveUserFirstEntry 用户每日首次进入直播间记录
+     * @return 结果
+     */
+    int updateLiveUserFirstEntry(LiveUserFirstEntry liveUserFirstEntry);
+
+    /**
+     * 删除用户每日首次进入直播间记录
+     *
+     * @param id 用户每日首次进入直播间记录主键
+     * @return 结果
+     */
+    int deleteLiveUserFirstEntryById(Long id);
+
+    /**
+     * 批量删除用户每日首次进入直播间记录
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteLiveUserFirstEntryByIds(Long[] ids);
+
+    @Select("select count(*) from live_user_first_entry where user_id=#{userId} and DATE(entry_date)=DATE(#{now})")
+    int selectTodayEntry(@Param("userId") long userId,@Param("now") Date now);
+}

+ 5 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveWatchUserMapper.java

@@ -94,4 +94,9 @@ public interface LiveWatchUserMapper extends BaseMapper<LiveWatchUser>{
     List<LiveWatchUserVO> selectOnlineUserList(LiveWatchUser param);
 
     List<LiveWatchUser> checkOnlineNoRewardUser(@Param("liveId") Long liveId,@Param("now") Date now);
+
+    @Select("select * from live_watch_user where live_id=#{liveId} and online = 1 and " +
+            "user_id in (select user_id from live_lottery_registration where live_id = #{liveId} and lottery_id=#{lotteryId} and registration_id >= " +
+            "(SELECT FLOOR(RAND() * (SELECT MAX(registration_id) FROM live_lottery_registration)))) limit #{totalLots}")
+    List<LiveWatchUser> selectLiveWatchAndRegisterUser(@Param("liveId") Long liveId,@Param("lotteryId") Long lotteryId,@Param("totalLots") Integer totalLots);
 }

+ 8 - 0
fs-service/src/main/java/com/fs/live/service/ILiveLotteryConfService.java

@@ -1,6 +1,8 @@
 package com.fs.live.service;
 
 import java.util.List;
+import java.util.Set;
+
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.common.core.domain.R;
 import com.fs.live.domain.LiveLotteryConf;
@@ -85,4 +87,10 @@ public interface ILiveLotteryConfService extends IService<LiveLotteryConf>{
     R claimLotteryPacket(LotteryPO lottery);
 
     List<LiveLotteryConfVo> selectActivedLottery(Long liveId, String userId);
+
+    List<LiveLotteryConfVo> selectByLotteryIds(Set<String> range);
+
+    List<LiveLotteryConfVo> selectVoListByLotteryIds(Set<String> range);
+
+    R detail(LotteryPO lottery);
 }

+ 63 - 0
fs-service/src/main/java/com/fs/live/service/ILiveUserFirstEntryService.java

@@ -0,0 +1,63 @@
+package com.fs.live.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.live.domain.LiveUserFirstEntry;
+
+/**
+ * 用户每日首次进入直播间记录Service接口
+ *
+ * @author fs
+ * @date 2025-09-04
+ */
+public interface ILiveUserFirstEntryService extends IService<LiveUserFirstEntry>{
+    /**
+     * 查询用户每日首次进入直播间记录
+     *
+     * @param id 用户每日首次进入直播间记录主键
+     * @return 用户每日首次进入直播间记录
+     */
+    LiveUserFirstEntry selectLiveUserFirstEntryById(Long id);
+
+    /**
+     * 查询用户每日首次进入直播间记录列表
+     *
+     * @param liveUserFirstEntry 用户每日首次进入直播间记录
+     * @return 用户每日首次进入直播间记录集合
+     */
+    List<LiveUserFirstEntry> selectLiveUserFirstEntryList(LiveUserFirstEntry liveUserFirstEntry);
+
+    /**
+     * 新增用户每日首次进入直播间记录
+     *
+     * @param liveUserFirstEntry 用户每日首次进入直播间记录
+     * @return 结果
+     */
+    int insertLiveUserFirstEntry(LiveUserFirstEntry liveUserFirstEntry);
+
+    /**
+     * 修改用户每日首次进入直播间记录
+     *
+     * @param liveUserFirstEntry 用户每日首次进入直播间记录
+     * @return 结果
+     */
+    int updateLiveUserFirstEntry(LiveUserFirstEntry liveUserFirstEntry);
+
+    /**
+     * 批量删除用户每日首次进入直播间记录
+     *
+     * @param ids 需要删除的用户每日首次进入直播间记录主键集合
+     * @return 结果
+     */
+    int deleteLiveUserFirstEntryByIds(Long[] ids);
+
+    /**
+     * 删除用户每日首次进入直播间记录信息
+     *
+     * @param id 用户每日首次进入直播间记录主键
+     * @return 结果
+     */
+    int deleteLiveUserFirstEntryById(Long id);
+
+    int selectTodayEntry(long userId);
+}

+ 3 - 0
fs-service/src/main/java/com/fs/live/service/ILiveWatchUserService.java

@@ -105,4 +105,7 @@ public interface ILiveWatchUserService extends IService<LiveWatchUser>{
     List<LiveWatchUser> checkOnlineNoRewardUser(Long liveId, Date now);
 
     int blockUser(Long userId);
+
+
+    List<LiveWatchUser> selectLiveWatchAndRegisterUser(Long liveId, Long lotteryId,Integer totalLots);
 }

+ 1 - 2
fs-service/src/main/java/com/fs/live/service/impl/LiveAutoTaskServiceImpl.java

@@ -174,8 +174,7 @@ public class LiveAutoTaskServiceImpl extends ServiceImpl<LiveAutoTaskMapper, Liv
         LiveAutoTask existTask = baseMapper.selectLiveAutoTaskById(liveAutoTask.getId());
         redisCache.redisTemplate.opsForZSet().removeRangeByScore("live:auto_task:" + existTask.getLiveId(), existTask.getAbsValue().getTime(), existTask.getAbsValue().getTime());
 
-        baseMapper.deleteLiveAutoTaskById(liveAutoTask.getId());
-        return baseMapper.insertLiveAutoTask(liveAutoTask);
+        return baseMapper.updateLiveAutoTask(liveAutoTask);
     }
 
     /**

+ 0 - 11
fs-service/src/main/java/com/fs/live/service/impl/LiveDataServiceImpl.java

@@ -364,17 +364,6 @@ public class LiveDataServiceImpl extends ServiceImpl<LiveDataMapper, LiveData> i
     public R updateLikeByLiveId(Long liveId, Long userId) {
         //一个用户一天只能点赞十次
         String key = "live:like:" + liveId + ":user:" + userId+":date:"+ DateUtils.getDate();
-        Integer count =redisCache.getCacheObject(key);
-        if((count==null?0: count)>=10) {
-            //当前时间
-            LocalDateTime now = LocalDateTime.now();
-            //明天0点
-            LocalDateTime tomorrow = now.plusDays(1).withHour(0).withMinute(0).withSecond(0);
-            //间隔秒
-            long seconds = ChronoUnit.SECONDS.between(now, tomorrow);
-            redisCache.expire(key, (int)seconds, TimeUnit.SECONDS);
-            return R.ok("每天最多为直播间点赞10次哟");
-        }
         LiveUserLike liveUserLike;
         boolean firstLike = redisCache.setIfAbsent(key, 1, 1, TimeUnit.DAYS);
         //用户直播间第一次点赞

+ 44 - 7
fs-service/src/main/java/com/fs/live/service/impl/LiveLotteryConfServiceImpl.java

@@ -1,9 +1,8 @@
 package com.fs.live.service.impl;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
 
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
@@ -16,6 +15,7 @@ import com.fs.live.param.LiveLotteryProduct;
 import com.fs.live.param.LiveLotteryProductSaveParam;
 import com.fs.live.param.LotteryPO;
 import com.fs.live.vo.LiveLotteryConfVo;
+import com.fs.live.vo.LiveLotteryProductListVo;
 import com.fs.live.vo.LiveLotteryProductVO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -89,12 +89,17 @@ public class LiveLotteryConfServiceImpl extends ServiceImpl<LiveLotteryConfMappe
     @Override
     public int updateLiveLotteryConf(LiveLotteryConf liveLotteryConf)
     {
-        String cacheKey = "live:lottery:" + liveLotteryConf.getLotteryId();
-        if("1".equals(liveLotteryConf.getLotteryStatus())){
+        String cacheKey = "live:lottery_task";
+        if ("1".equals(liveLotteryConf.getLotteryStatus())) {
             List<LiveLotteryProduct> prizes = productMapper.selectLiveLotteryProductConfByLotteryId(liveLotteryConf.getLotteryId());
-            if (prizes == null || prizes.isEmpty()){
+            if (prizes == null || prizes.isEmpty()) {
                 throw new RuntimeException("请先添加奖品");
             }
+            LocalDateTime localDateTime = LocalDateTime.now().plusMinutes(liveLotteryConf.getDuration());
+            double score = localDateTime.atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli();
+            redisCache.redisTemplate.opsForZSet().add(cacheKey, String.valueOf(liveLotteryConf.getLotteryId()), score);
+        } else {
+            redisCache.deleteObject(cacheKey);
         }
         return baseMapper.updateLiveLotteryConf(liveLotteryConf);
 
@@ -219,4 +224,36 @@ public class LiveLotteryConfServiceImpl extends ServiceImpl<LiveLotteryConfMappe
     public List<LiveLotteryConfVo> selectActivedLottery(Long liveId, String userId) {
         return baseMapper.selectActivedLottery(liveId, userId);
     }
+
+    @Override
+    public List<LiveLotteryConfVo> selectByLotteryIds(Set<String> range) {
+        return baseMapper.selectByLotteryIds(range);
+    }
+
+    @Override
+    public List<LiveLotteryConfVo> selectVoListByLotteryIds(Set<String> range) {
+        List<LiveLotteryConfVo> liveLotteryConfVos = baseMapper.selectByLotteryIds(range);
+        List<Long> lotteryIds = liveLotteryConfVos.stream().map(LiveLotteryConfVo::getLotteryId).collect(Collectors.toList());
+        if (!lotteryIds.isEmpty()) {
+            List<LiveLotteryProductListVo> products = productMapper.selectLiveLotteryProductConfByLotteryIds(lotteryIds);
+            for (LiveLotteryConfVo liveLotteryConf : liveLotteryConfVos) {
+                liveLotteryConf.setProducts(products.stream().filter(product -> product.getLotteryId().equals(liveLotteryConf.getLotteryId())).collect(Collectors.toList()));
+            }
+        }
+        return liveLotteryConfVos;
+    }
+
+    @Override
+    public R detail(LotteryPO lottery) {
+        LiveLotteryConfVo liveLotteryConf = baseMapper.selectLiveLotteryConfVoByLotteryId(lottery.getLotteryId());
+        if (liveLotteryConf == null) {
+            return R.error("抽奖不存在!");
+        }
+        if(!liveLotteryConf.getLotteryStatus().equals("1")) return R.error("抽奖未开始!");
+        List<Long> lotteryIds = new ArrayList<>();
+        lotteryIds.add(lottery.getLotteryId());
+        List<LiveLotteryProductListVo> prizes = productMapper.selectLiveLotteryProductConfByLotteryIds(lotteryIds);
+        liveLotteryConf.setProducts(prizes);
+        return R.ok().put("data", liveLotteryConf);
+    }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/live/service/impl/LiveRedConfServiceImpl.java

@@ -291,7 +291,7 @@ public class LiveRedConfServiceImpl extends ServiceImpl<LiveRedConfMapper, LiveR
     }
 
     public boolean tryLock(String lockKey, String clientId, long expireTime) {
-        Boolean success = redisCache.setIfAbsent(lockKey + ":" + clientId, clientId, expireTime, TimeUnit.SECONDS);
+        Boolean success = redisCache.setIfAbsent(lockKey + ":" + clientId, clientId, expireTime, TimeUnit.MINUTES);
         return Boolean.TRUE.equals(success);
     }
 

+ 101 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveUserFirstEntryServiceImpl.java

@@ -0,0 +1,101 @@
+package com.fs.live.service.impl;
+
+import java.util.Date;
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.live.mapper.LiveUserFirstEntryMapper;
+import com.fs.live.domain.LiveUserFirstEntry;
+import com.fs.live.service.ILiveUserFirstEntryService;
+
+/**
+ * 用户每日首次进入直播间记录Service业务层处理
+ *
+ * @author fs
+ * @date 2025-09-04
+ */
+@Service
+public class LiveUserFirstEntryServiceImpl extends ServiceImpl<LiveUserFirstEntryMapper, LiveUserFirstEntry> implements ILiveUserFirstEntryService {
+
+    /**
+     * 查询用户每日首次进入直播间记录
+     *
+     * @param id 用户每日首次进入直播间记录主键
+     * @return 用户每日首次进入直播间记录
+     */
+    @Override
+    public LiveUserFirstEntry selectLiveUserFirstEntryById(Long id)
+    {
+        return baseMapper.selectLiveUserFirstEntryById(id);
+    }
+
+    /**
+     * 查询用户每日首次进入直播间记录列表
+     *
+     * @param liveUserFirstEntry 用户每日首次进入直播间记录
+     * @return 用户每日首次进入直播间记录
+     */
+    @Override
+    public List<LiveUserFirstEntry> selectLiveUserFirstEntryList(LiveUserFirstEntry liveUserFirstEntry)
+    {
+        return baseMapper.selectLiveUserFirstEntryList(liveUserFirstEntry);
+    }
+
+    /**
+     * 新增用户每日首次进入直播间记录
+     *
+     * @param liveUserFirstEntry 用户每日首次进入直播间记录
+     * @return 结果
+     */
+    @Override
+    public int insertLiveUserFirstEntry(LiveUserFirstEntry liveUserFirstEntry)
+    {
+        liveUserFirstEntry.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertLiveUserFirstEntry(liveUserFirstEntry);
+    }
+
+    /**
+     * 修改用户每日首次进入直播间记录
+     *
+     * @param liveUserFirstEntry 用户每日首次进入直播间记录
+     * @return 结果
+     */
+    @Override
+    public int updateLiveUserFirstEntry(LiveUserFirstEntry liveUserFirstEntry)
+    {
+        liveUserFirstEntry.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateLiveUserFirstEntry(liveUserFirstEntry);
+    }
+
+    /**
+     * 批量删除用户每日首次进入直播间记录
+     *
+     * @param ids 需要删除的用户每日首次进入直播间记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteLiveUserFirstEntryByIds(Long[] ids)
+    {
+        return baseMapper.deleteLiveUserFirstEntryByIds(ids);
+    }
+
+    /**
+     * 删除用户每日首次进入直播间记录信息
+     *
+     * @param id 用户每日首次进入直播间记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteLiveUserFirstEntryById(Long id)
+    {
+        return baseMapper.deleteLiveUserFirstEntryById(id);
+    }
+
+    @Override
+    public int selectTodayEntry(long userId) {
+        Date now = DateUtils.getNowDate();
+        return baseMapper.selectTodayEntry(userId, now);
+    }
+}

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

@@ -205,4 +205,9 @@ public class LiveWatchUserServiceImpl extends ServiceImpl<LiveWatchUserMapper, L
         return fsUserService.updateFsUser(fsUser);
     }
 
+    @Override
+    public List<LiveWatchUser> selectLiveWatchAndRegisterUser(Long liveId, Long lotteryId,Integer totalLots) {
+        return baseMapper.selectLiveWatchAndRegisterUser(liveId, lotteryId,totalLots);
+    }
+
 }

+ 11 - 0
fs-service/src/main/resources/mapper/live/LiveLotteryConfMapper.xml

@@ -93,4 +93,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{lotteryId}
         </foreach>
     </delete>
+
+    <select id="selectByLotteryIds" resultType="com.fs.live.vo.LiveLotteryConfVo">
+        select * from live_lottery_conf where lottery_id in
+        <foreach item="lotteryId" collection="ids" open="(" separator="," close=")">
+            #{lotteryId}
+        </foreach>
+    </select>
+
+    <select id="selectLiveLotteryConfVoByLotteryId" resultType="com.fs.live.vo.LiveLotteryConfVo">
+        select * from live_lottery_conf where lottery_id = #{lotteryId}
+    </select>
 </mapper>

+ 15 - 0
fs-service/src/main/resources/mapper/live/LiveLotteryRegistrationMapper.xml

@@ -73,6 +73,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </trim>
         where registration_id = #{registrationId}
     </update>
+    <update id="updateLiveLotteryRegistrationNoId" parameterType="LiveLotteryRegistration">
+        update live_lottery_registration
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="liveId != null">live_id = #{liveId},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="lotteryId != null">lottery_id = #{lotteryId},</if>
+            <if test="isWin != null">is_win = #{isWin},</if>
+            <if test="rizeLevel != null">rize_level = #{rizeLevel},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+        </trim>
+        where live_id = #{liveId} and user_id = #{userId} and lottery_id = #{lotteryId}
+    </update>
 
     <delete id="deleteLiveLotteryRegistrationByRegistrationId" parameterType="Long">
         delete from live_lottery_registration where registration_id = #{registrationId}

+ 1 - 0
fs-service/src/main/resources/mapper/live/LiveRedConfMapper.xml

@@ -34,6 +34,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createTime != null "> and create_time = #{createTime}</if>
             <if test="updateTime != null "> and update_time = #{updateTime}</if>
         </where>
+        order by create_time  desc
     </select>
 
     <select id="selectLiveRedConfByRedId" parameterType="Long" resultMap="LiveRedConfResult">

+ 79 - 0
fs-service/src/main/resources/mapper/live/LiveUserFirstEntryMapper.xml

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.live.mapper.LiveUserFirstEntryMapper">
+    
+    <resultMap type="LiveUserFirstEntry" id="LiveUserFirstEntryResult">
+        <result property="id"    column="id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="liveId"    column="live_id"    />
+        <result property="entryDate"    column="entry_date"    />
+        <result property="firstEntryTime"    column="first_entry_time"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectLiveUserFirstEntryVo">
+        select id, user_id, live_id, entry_date, first_entry_time, create_time, update_time from live_user_first_entry
+    </sql>
+
+    <select id="selectLiveUserFirstEntryList" parameterType="LiveUserFirstEntry" resultMap="LiveUserFirstEntryResult">
+        <include refid="selectLiveUserFirstEntryVo"/>
+        <where>  
+            <if test="userId != null  and userId != ''"> and user_id = #{userId}</if>
+            <if test="liveId != null  and liveId != ''"> and live_id = #{liveId}</if>
+            <if test="entryDate != null "> and entry_date = #{entryDate}</if>
+            <if test="firstEntryTime != null "> and first_entry_time = #{firstEntryTime}</if>
+        </where>
+    </select>
+    
+    <select id="selectLiveUserFirstEntryById" parameterType="Long" resultMap="LiveUserFirstEntryResult">
+        <include refid="selectLiveUserFirstEntryVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertLiveUserFirstEntry" parameterType="LiveUserFirstEntry" useGeneratedKeys="true" keyProperty="id">
+        insert into live_user_first_entry
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="userId != null and userId != ''">user_id,</if>
+            <if test="liveId != null and liveId != ''">live_id,</if>
+            <if test="entryDate != null">entry_date,</if>
+            <if test="firstEntryTime != null">first_entry_time,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="userId != null and userId != ''">#{userId},</if>
+            <if test="liveId != null and liveId != ''">#{liveId},</if>
+            <if test="entryDate != null">#{entryDate},</if>
+            <if test="firstEntryTime != null">#{firstEntryTime},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateLiveUserFirstEntry" parameterType="LiveUserFirstEntry">
+        update live_user_first_entry
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="userId != null and userId != ''">user_id = #{userId},</if>
+            <if test="liveId != null and liveId != ''">live_id = #{liveId},</if>
+            <if test="entryDate != null">entry_date = #{entryDate},</if>
+            <if test="firstEntryTime != null">first_entry_time = #{firstEntryTime},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteLiveUserFirstEntryById" parameterType="Long">
+        delete from live_user_first_entry where id = #{id}
+    </delete>
+
+    <delete id="deleteLiveUserFirstEntryByIds" parameterType="String">
+        delete from live_user_first_entry where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>