Просмотр исходного кода

屏蔽掉原来的task 添加直播积分数据统计

yuhongqi 1 неделя назад
Родитель
Сommit
a0ff02b77b

+ 30 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveRewardRecordController.java

@@ -3,15 +3,20 @@ package com.fs.live.controller;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.core.security.SecurityUtils;
 import com.fs.live.domain.LiveRewardRecord;
 import com.fs.live.service.ILiveRewardRecordService;
+import com.fs.live.vo.LiveRewardRecordStatisticsVo;
+import com.fs.live.vo.LiveRewardRecordVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -94,4 +99,29 @@ public class LiveRewardRecordController extends BaseController
     {
         return toAjax(liveRewardRecordService.deleteLiveRewardRecordByIds(ids));
     }
+
+    /**
+     * 删除用户直播间奖励记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:record:query')")
+    @PostMapping("/statistics")
+    public R statistics(@RequestBody LiveRewardRecordVo param)
+    {
+        return liveRewardRecordService.statistics(param);
+        // 可惜了 我华丽的实现
+        //        return liveRewardRecordService.count(step,companyId);
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:record:export')")
+    @PostMapping("/export")
+    public AjaxResult export(@RequestBody LiveRewardRecordVo param)
+    {
+        List<LiveRewardRecordStatisticsVo> list = liveRewardRecordService.selectRewardSummary(param);
+
+        ExcelUtil<LiveRewardRecordStatisticsVo> util = new ExcelUtil<LiveRewardRecordStatisticsVo>(LiveRewardRecordStatisticsVo.class);
+        return util.exportExcel(list, "liveIntegralLogs");
+
+//        return liveRewardRecordService.export(param);
+//        return R.ok();
+    }
 }

+ 34 - 0
fs-company/src/main/java/com/fs/company/controller/live/LiveRewardRecordController.java

@@ -3,16 +3,25 @@ package com.fs.company.controller.live;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.vo.CompanySmsLogsStatisticsVO;
+import com.fs.core.security.SecurityUtils;
 import com.fs.live.domain.LiveRewardRecord;
 import com.fs.live.service.ILiveRewardRecordService;
+import com.fs.live.vo.LiveRewardRecordStatisticsVo;
+import com.fs.live.vo.LiveRewardRecordVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.Date;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 用户直播间奖励记录Controller
@@ -94,4 +103,29 @@ public class LiveRewardRecordController extends BaseController
     {
         return toAjax(liveRewardRecordService.deleteLiveRewardRecordByIds(ids));
     }
+
+
+    @PreAuthorize("@ss.hasPermi('live:record:query')")
+    @PostMapping("/statistics")
+    public R statistics(@RequestBody LiveRewardRecordVo param)
+    {
+        Long companyId = SecurityUtils.getLoginUser().getUser().getCompanyId();
+        param.setCompanyId(companyId);
+        return liveRewardRecordService.statistics(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:record:export')")
+    @PostMapping("/export")
+    public AjaxResult export(@RequestBody LiveRewardRecordVo param)
+    {
+        Long companyId = SecurityUtils.getLoginUser().getUser().getCompanyId();
+        param.setCompanyId(companyId);
+        List<LiveRewardRecordStatisticsVo> list = liveRewardRecordService.selectRewardSummary(param);
+
+        ExcelUtil<LiveRewardRecordStatisticsVo> util = new ExcelUtil<LiveRewardRecordStatisticsVo>(LiveRewardRecordStatisticsVo.class);
+        return util.exportExcel(list, "liveIntegralLogs");
+
+//        return liveRewardRecordService.export(param);
+//        return R.ok();
+    }
 }

+ 2 - 0
fs-service-system/src/main/java/com/fs/live/domain/LiveRewardRecord.java

@@ -56,5 +56,7 @@ public class LiveRewardRecord extends BaseEntity{
     @Excel(name = "奖励后数量")
     private BigDecimal afterNum;
 
+    private String liveName;
+
 
 }

+ 31 - 0
fs-service-system/src/main/java/com/fs/live/mapper/LiveRewardRecordMapper.java

@@ -2,7 +2,12 @@ package com.fs.live.mapper;
 
 
 import com.fs.live.domain.LiveRewardRecord;
+import com.fs.live.vo.LiveRewardRecordStatisticsVo;
+import com.fs.live.vo.LiveRewardRecordVo;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -59,4 +64,30 @@ public interface LiveRewardRecordMapper {
      * @return 结果
      */
     int deleteLiveRewardRecordByIds(Long[] ids);
+
+    @Select({
+            "<script> SELECT lrr.*, l.live_name ",
+            "FROM live_reward_record lrr ",
+            "LEFT JOIN live l ON lrr.live_id = l.live_id ",
+            "WHERE lrr.source_id = #{companyId} ",
+            "AND DATE_FORMAT(lrr.create_time, '%Y-%m') IN ",
+            "<foreach collection='step' item='date' open='(' separator=',' close=')'>",
+            "DATE_FORMAT(#{date}, '%Y-%m')",
+            "</foreach> </script> "
+    })
+    List<LiveRewardRecord> selectLiveRewardRecordListByCompanyId(@Param("step") List<Date> step,@Param("companyId") Long companyId);
+
+    @Select({
+            "<script> SELECT lrr.*, l.live_name ",
+            "FROM live_reward_record lrr ",
+            "LEFT JOIN live l ON lrr.live_id = l.live_id ",
+            "WHERE ",
+            " DATE_FORMAT(lrr.create_time, '%Y-%m') IN ",
+            "<foreach collection='step' item='date' open='(' separator=',' close=')'>",
+            "DATE_FORMAT(#{date}, '%Y-%m')",
+            "</foreach> </script> "
+    })
+    List<LiveRewardRecord> selectLiveRewardRecordListByStep(@Param("step") List<Date> step);
+
+    List<LiveRewardRecordStatisticsVo> selectRewardSummary(LiveRewardRecordVo param);
 }

+ 10 - 0
fs-service-system/src/main/java/com/fs/live/service/ILiveRewardRecordService.java

@@ -1,8 +1,12 @@
 package com.fs.live.service;
 
+import java.util.Date;
 import java.util.List;
 
+import com.fs.common.core.domain.R;
 import com.fs.live.domain.LiveRewardRecord;
+import com.fs.live.vo.LiveRewardRecordStatisticsVo;
+import com.fs.live.vo.LiveRewardRecordVo;
 
 /**
  * 用户直播间奖励记录Service接口
@@ -58,4 +62,10 @@ public interface ILiveRewardRecordService {
      * @return 结果
      */
     int deleteLiveRewardRecordById(Long id);
+
+
+
+    R statistics(LiveRewardRecordVo param);
+
+    List<LiveRewardRecordStatisticsVo> selectRewardSummary(LiveRewardRecordVo param);
 }

+ 26 - 3
fs-service-system/src/main/java/com/fs/live/service/impl/LiveRedConfServiceImpl.java

@@ -9,10 +9,10 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisUtil;
 import com.fs.common.utils.DateUtils;
-import com.fs.live.domain.LiveLotteryRegistration;
-import com.fs.live.domain.LiveRedConf;
-import com.fs.live.domain.LiveUserRedRecord;
+import com.fs.live.domain.*;
+import com.fs.live.mapper.LiveMapper;
 import com.fs.live.mapper.LiveRedConfMapper;
+import com.fs.live.mapper.LiveRewardRecordMapper;
 import com.fs.live.mapper.LiveUserRedRecordMapper;
 import com.fs.live.param.RedPO;
 import com.fs.live.service.ILiveRedConfService;
@@ -24,6 +24,7 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.concurrent.ThreadLocalRandom;
@@ -50,6 +51,10 @@ public class LiveRedConfServiceImpl implements ILiveRedConfService {
 
     @Autowired
     private IFsUserService userService;
+    @Autowired
+    private LiveMapper liveMapper;
+    @Autowired
+    private LiveRewardRecordMapper liveRewardRecordMapper;
 
     private static final String REDPACKET_REMAININGLOTS_KEY = "live:red:remainingLots:";
     private static final String REDPACKET_REMAININGNUM_KEY = "live:red:remainingNum:";
@@ -295,12 +300,30 @@ public class LiveRedConfServiceImpl implements ILiveRedConfService {
                 userRedRecordMapper.insertLiveUserRedRecordBatch(liveUserRedRecords);
                 for (LiveUserRedRecord liveUserRedRecord : liveUserRedRecords) {
                     userService.incrIntegral(Collections.singletonList(liveUserRedRecord.getUserId()), liveUserRedRecord.getIntegral());
+                    // 保存用户领取芳华币记录 方便统计计算
+                    saveUserRewardRecord(liveUserRedRecord);
                 }
             }
             redisUtil.delete(hashKey);
         }
     }
 
+    private void saveUserRewardRecord(LiveUserRedRecord liveUserRedRecord) {
+        Live live = liveMapper.selectLiveByLiveId(liveUserRedRecord.getLiveId());
+        LiveRewardRecord record = new LiveRewardRecord();
+        record.setLiveId(live.getLiveId());
+        record.setUserId(liveUserRedRecord.getUserId());
+        record.setIncomeType(1L);
+        record.setSourceType(1L);
+        record.setSourceId(live.getCompanyId() == null ? 0L : live.getCompanyId());
+        record.setRewardType(2L);
+        record.setNum(BigDecimal.valueOf(liveUserRedRecord.getIntegral()));
+        record.setRewardType(2L);
+        record.setCreateTime(new Date());
+        record.setCreateBy(String.valueOf(liveUserRedRecord.getUserId()));
+        liveRewardRecordMapper.insertLiveRewardRecord(record);
+    }
+
     @Override
     public void updateRedQuantityNum() {
         LiveRedConf redConf = new LiveRedConf();

+ 62 - 1
fs-service-system/src/main/java/com/fs/live/service/impl/LiveRewardRecordServiceImpl.java

@@ -1,14 +1,20 @@
 package com.fs.live.service.impl;
 
 
+import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.fs.live.domain.LiveRewardRecord;
 import com.fs.live.mapper.LiveRewardRecordMapper;
 import com.fs.live.service.ILiveRewardRecordService;
+import com.fs.live.vo.LiveRewardRecordStatisticsVo;
+import com.fs.live.vo.LiveRewardRecordVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.List;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 用户直播间奖励记录Service业务层处理
@@ -93,4 +99,59 @@ public class LiveRewardRecordServiceImpl implements ILiveRewardRecordService {
     {
         return baseMapper.deleteLiveRewardRecordById(id);
     }
+
+
+    @Override
+    public R statistics(LiveRewardRecordVo param) {
+        SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM");
+        List<LiveRewardRecord> liveRewardRecords;
+        if (param.getCompanyId() == 0L) {
+            liveRewardRecords = baseMapper.selectLiveRewardRecordListByStep(param.getStep());
+        } else {
+            liveRewardRecords = baseMapper.selectLiveRewardRecordListByCompanyId(param.getStep(), param.getCompanyId());
+        }
+        Map<String, Map<String, BigDecimal>> monthLiveMap = liveRewardRecords.stream()
+                // 第一层:按liveId分组
+                .collect(Collectors.groupingBy(
+                        LiveRewardRecord::getLiveName,
+                        // 第二层:在每个liveId分组内按天统计
+                        Collectors.groupingBy(
+                                record -> dayFormat.format(record.getCreateTime()),
+                                Collectors.reducing(BigDecimal.ZERO, LiveRewardRecord::getNum, BigDecimal::add)
+                        )
+                ));
+        // 1. 生成完整的时间序列(天或月)
+        List<String> timeSeries = generateMonthTimeSeries(param.getStep(), dayFormat);
+        List<LiveRewardRecordVo> dayLiveList = formatNestedMap(monthLiveMap, timeSeries);
+        return R.ok().put("data", dayLiveList).put("timeSeries",timeSeries);
+    }
+
+    @Override
+    public List<LiveRewardRecordStatisticsVo> selectRewardSummary(LiveRewardRecordVo param) {
+        return baseMapper.selectRewardSummary(param);
+    }
+
+
+    // 将嵌套Map(liveId -> 时间->数值)转换为List<LiveTimeData>(每个liveId对应完整时间序列)
+    private List<LiveRewardRecordVo> formatNestedMap(Map<String, Map<String, BigDecimal>> nestedMap, List<String> timeSeries) {
+        return nestedMap.entrySet().stream()
+                .map(entry -> {
+                    String key = entry.getKey();
+                    Map<String, BigDecimal> timeDataMap = entry.getValue();
+                    // 为当前liveId生成完整时间序列的数值列表(缺失补0)
+                    List<BigDecimal> dataList = timeSeries.stream()
+                            .map(time -> timeDataMap.getOrDefault(time, BigDecimal.ZERO))
+                            .collect(Collectors.toList());
+                    return new LiveRewardRecordVo(key, dataList);
+                })
+                .collect(Collectors.toList());
+    }
+    // 生成从start到end的所有月份(yyyy-MM)
+    private List<String> generateMonthTimeSeries(List<Date> step, SimpleDateFormat format) {
+        List<String> timeSeries = new ArrayList<>();
+        for (Date date : step) {
+            timeSeries.add(format.format(date));
+        }
+        return timeSeries;
+    }
 }

+ 20 - 0
fs-service-system/src/main/java/com/fs/live/vo/LiveRewardRecordStatisticsVo.java

@@ -0,0 +1,20 @@
+package com.fs.live.vo;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class LiveRewardRecordStatisticsVo implements Serializable
+{
+    @Excel(name = "直播间ID")
+    Long liveId;
+    @Excel(name = "直播间名称")
+    String liveName;
+    @Excel(name = "月份")
+    String monthString;
+    @Excel(name = "积分数量")
+    Integer integralCount;
+}

+ 32 - 0
fs-service-system/src/main/java/com/fs/live/vo/LiveRewardRecordVo.java

@@ -0,0 +1,32 @@
+package com.fs.live.vo;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 用户直播间奖励记录对象 live_reward_record
+ *
+ * @author fs
+ * @date 2025-08-27
+ */
+@Data
+public class LiveRewardRecordVo {
+    private String liveNameAndId;
+    private List<BigDecimal> dataList;
+    private List<Date> step;
+    private Long companyId;
+
+    public LiveRewardRecordVo() {
+    }
+
+    public LiveRewardRecordVo(String liveNameAndId, List<BigDecimal> dataList) {
+        this.liveNameAndId = liveNameAndId;
+        this.dataList = dataList;
+    }
+}

+ 24 - 0
fs-service-system/src/main/resources/mapper/live/LiveRewardRecordMapper.xml

@@ -101,4 +101,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{id}
         </foreach>
     </delete>
+    <select id="selectRewardSummary" parameterType="com.fs.live.vo.LiveRewardRecordVo"  resultType="com.fs.live.vo.LiveRewardRecordStatisticsVo">
+        SELECT
+            CAST(lrr.live_id AS CHAR) AS liveId,
+            l.live_name AS liveName,
+            DATE_FORMAT(lrr.create_time, '%Y-%m') AS monthString,
+            SUM(CASE WHEN lrr.reward_type = 2 THEN num ELSE 0 END) AS integralCount
+        FROM
+            live_reward_record lrr
+                left join live l on lrr.live_id=l.live_id
+        WHERE
+            1=1
+          AND lrr.reward_type = 2
+        <if test="companyId != null">
+            and lrr.source_id = #{companyId}
+        </if>
+        <if test="step != null">
+            and DATE_FORMAT(lrr.create_time, '%Y-%m') in
+            <foreach item="dateStr" collection="step" open="(" separator="," close=")">
+                DATE_FORMAT(#{dateStr}, '%Y-%m')
+            </foreach>
+        </if>
+        GROUP BY
+            lrr.live_id, l.live_name, DATE_FORMAT(lrr.create_time, '%Y-%m')
+    </select>
 </mapper>

+ 392 - 392
fs-user-app/src/main/java/com/fs/app/task/Task.java

@@ -1,392 +1,392 @@
-package com.fs.app.task;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.json.JSONUtil;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.fs.app.facade.LiveFacadeService;
-import com.fs.app.vo.LotteryVo;
-import com.fs.app.websocket.bean.SendMsgVo;
-import com.fs.app.websocket.service.WebSocketServer;
-import com.fs.common.annotation.QuartzRunnable;
-import com.fs.common.constant.LiveKeysConstant;
-import com.fs.common.core.domain.R;
-import com.fs.common.core.redis.RedisCache;
-import com.fs.common.core.redis.RedisUtil;
-import com.fs.common.utils.StringUtils;
-import com.fs.core.aspectj.lock.DistributeLock;
-import com.fs.erp.domain.ErpDeliverys;
-import com.fs.erp.domain.ErpOrderQuery;
-import com.fs.erp.dto.ErpOrderQueryRequert;
-import com.fs.erp.dto.ErpOrderQueryResponse;
-import com.fs.erp.service.FsJstAftersalePushService;
-import com.fs.erp.service.IErpOrderService;
-import com.fs.erp.utils.ErpContextHolder;
-import com.fs.live.domain.*;
-import com.fs.live.mapper.LiveLotteryRegistrationMapper;
-import com.fs.live.param.LiveReplayParam;
-import com.fs.live.service.*;
-import com.fs.live.vo.LiveConfigVo;
-import com.fs.live.vo.LiveLotteryConfVo;
-import com.fs.live.vo.LiveLotteryProductListVo;
-import com.fs.store.domain.FsExpress;
-import com.fs.store.enums.OrderLogEnum;
-import com.fs.store.mapper.FsWarehousesMapper;
-import com.fs.store.param.LiveAfterSalesAudit1Param;
-import com.fs.store.service.IFsExpressService;
-import com.fs.store.service.IFsUserService;
-import lombok.AllArgsConstructor;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang.ObjectUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-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 java.math.BigDecimal;
-import java.text.ParseException;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.stream.Collectors;
-
-@Component
-@AllArgsConstructor
-public class Task {
-
-    private static final Logger log = LoggerFactory.getLogger(Task.class);
-    private final ILiveService liveService;
-
-    private final ILiveDataService liveDataService;
-
-    private final RedisCache redisCache;
-
-    @Autowired
-    private ILiveWatchUserService liveWatchUserService;
-    @Autowired
-    private IFsUserService fsUserService;
-    @Autowired
-    private ILiveRewardRecordService liveRewardRecordService;
-    @Autowired
-    private WebSocketServer webSocketServer;
-    @Autowired
-    private ILiveAutoTaskService liveAutoTaskService;
-    @Autowired
-    private ILiveLotteryConfService liveLotteryConfService;
-    @Autowired
-    private ILiveUserLotteryRecordService liveUserLotteryRecordService;
-    @Autowired
-    private LiveLotteryRegistrationMapper liveLotteryRegistrationMapper;
-    @Autowired
-    private ILiveRedConfService liveRedConfService;
-//1111
-    @Autowired
-    private ILiveOrderService liveOrderService;
-
-    @Autowired
-    private ILiveAfterSalesService afterSalesService;
-
-
-    @Autowired
-    private IErpOrderService erpOrderService;
-
-
-    @Autowired
-    private IFsExpressService expressService;
-
-
-    @Autowired
-    private ILiveOrderLogsService orderLogsService;
-
-
-    @Autowired
-    private FsWarehousesMapper fsWarehousesMapper;
-
-    @Autowired
-    public FsJstAftersalePushService fsJstAftersalePushService;
-    @Autowired
-    public RedisUtil redisUtil;
-    @Scheduled(cron = "0 0/1 * * * ?")
-    @DistributeLock(key = "updateLiveStatusByTime", scene = "task")
-    //public void selectSopUserLogsListByTime() {
-    public void updateLiveStatusByTime() {
-        List<Live> list = liveService.selectNoEndLiveList();
-        if (list.isEmpty())
-            return;
-        List<Long> liveIdLists = list.stream().map(Live::getLiveId).collect(Collectors.toList());
-        List<LiveAutoTask> liveAutoTasks = liveAutoTaskService.selectLiveAutoTaskByLiveIds(liveIdLists);
-        List<Live> activeLiveList = new ArrayList<>();
-        LocalDateTime now = LocalDateTime.now();
-        list.forEach(live -> {
-            if (live.getLiveType() != 3) {
-                if (live.getFinishTime() == null) {
-                    if (now.isAfter(live.getStartTime().minusSeconds(2L))){
-                        live.setStatus(2);
-                        activeLiveList.add( live);
-                    } else if (now.isBefore(live.getStartTime())) {
-                        live.setStatus(1);
-                    }
-                } else {
-                    if (now.isAfter(live.getStartTime().minusSeconds(2L)) && now.isBefore(live.getFinishTime())) {
-                        live.setStatus(2);
-                        activeLiveList.add( live);
-                    } else if (now.isBefore(live.getStartTime().minusSeconds(2L))) {
-                        live.setStatus(1);
-                    } else if (now.isAfter(live.getFinishTime().minusSeconds(2L))) {
-                        live.setStatus(3);
-                    }
-                }
-            } else {
-                // 直播回放只需要检测结束时间就好了
-                LiveReplayParam liveReplayParam = JSON.parseObject(live.getLiveConfig(), LiveReplayParam.class);
-                if (liveReplayParam.getIsPlaybackOpen()) {
-                    if (liveReplayParam.getFinishTime() != null) {
-                        if (now.isAfter(live.getFinishTime().minusSeconds(2L))) {
-                            live.setStatus(3);
-                        }
-                    }
-                }
-            }
-
-        });
-        String key = "live:auto_task:";
-        if(!activeLiveList.isEmpty()){
-            activeLiveList.forEach(live -> {
-                List<LiveAutoTask> collect = liveAutoTasks.stream().filter(liveAutoTask -> liveAutoTask.getLiveId().equals(live.getLiveId())).collect(Collectors.toList());
-                if (!collect.isEmpty()) {
-                    collect.forEach(liveAutoTask -> {
-                        liveAutoTask.setCreateTime(null);
-                        liveAutoTask.setUpdateTime(null);
-                        redisCache.redisTemplate.opsForZSet().add(key + live.getLiveId(), JSON.toJSONString(liveAutoTask),liveAutoTask.getAbsValue().getTime());
-                        redisCache.redisTemplate.expire(key+live.getLiveId(), 30, java.util.concurrent.TimeUnit.MINUTES);
-                    });
-                }
-            });
-        }
-
-        if(!list.isEmpty()){
-            for (Live live : list) {
-                liveService.updateLive(live);
-            }
-        }
-    }
-    @Scheduled(cron = "0/1 * * * * ?")
-    @DistributeLock(key = "liveLotteryTask", scene = "task")
-    public void liveLotteryTask() {
-        long currentTime = Instant.now().toEpochMilli(); // 当前时间戳(毫秒)
-        String lotteryKey = "live:lottery_task:*";
-        Set<String> allLiveKeys = redisCache.redisTemplate.keys(lotteryKey);
-        if (allLiveKeys != null && !allLiveKeys.isEmpty()) {
-            for (String liveKey : allLiveKeys) {
-                Set<String> range = redisCache.redisTemplate.opsForZSet().rangeByScore(liveKey, 0, currentTime);
-                if (range == null || range.isEmpty()) {
-                    continue;
-                }
-                processLotteryTask(range);
-                redisCache.redisTemplate.opsForZSet()
-                        .removeRangeByScore(liveKey, 0, currentTime);
-            }
-        }
-
-        String redKey = "live:red_task:*";
-        allLiveKeys = redisCache.redisTemplate.keys(redKey);
-        if (allLiveKeys == null || allLiveKeys.isEmpty()) {
-            return;
-        }
-        for (String liveKey : allLiveKeys) {
-            Set<String> range = redisCache.redisTemplate.opsForZSet().rangeByScore(liveKey, 0, currentTime);
-            if (range == null || range.isEmpty()) {
-                continue;
-            }
-
-            updateRedStatus(range);
-            redisCache.redisTemplate.opsForZSet()
-                    .removeRangeByScore(liveKey, 0, currentTime);
-            try {
-                // 广播红包关闭消息
-                SendMsgVo sendMsgVo = new SendMsgVo();
-                sendMsgVo.setLiveId(Long.valueOf(liveKey));
-                sendMsgVo.setCmd("red");
-                sendMsgVo.setStatus(-1);
-                webSocketServer.broadcastMessage(Long.valueOf(liveKey), JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
-            } catch (Exception e) {
-                log.error("更新红包状态异常", e);
-            }
-        }
-    }
-
-    private void updateRedStatus(Set<String> range) {
-
-        liveRedConfService.finishRedStatusBySetIds(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;
-            // 先将参与记录插入数据库
-            String hashKey = String.format(LiveKeysConstant.LIVE_HOME_PAGE_CONFIG_DRAW, liveLottery.getLiveId(), liveLottery.getLotteryId());
-            Map<Object, Object> hashEntries = redisUtil.hashEntries(hashKey);
-            List<LiveLotteryRegistration> registrationList = new ArrayList<>();
-            if (CollUtil.isNotEmpty(hashEntries)) {
-                registrationList = hashEntries.values().stream()
-                        .map(value -> JSONUtil.toBean(JSONUtil.parseObj(value), LiveLotteryRegistration.class))
-                        .collect(Collectors.toList());
-                liveLotteryRegistrationMapper.insertLiveLotteryRegistrationBatch(registrationList);
-            }
-
-            // 查询在线用户 并且参与了抽奖的用户
-            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 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.setUserName(winningUser.getNickName());
-                    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.getLiveId(), JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
-
-            // 删除缓存 同步抽奖记录
-            redisUtil.delete(hashKey);
-        }
-
-        List<Long> collect = liveLotteries.stream().map(LiveLotteryConfVo::getLotteryId).collect(Collectors.toList());
-        liveLotteryConfService.finishStatusByLotteryIds(collect);
-    }
-
-    @Scheduled(cron = "0/1 * * * * ?")
-    @DistributeLock(key = "liveAutoTask", scene = "task")
-    public void liveAutoTask() {
-        long currentTime = Instant.now().toEpochMilli(); // 当前时间戳(毫秒)
-
-        Set<String> allLiveKeys = redisCache.redisTemplate.keys("live:auto_task:*");
-        if (allLiveKeys == null || allLiveKeys.isEmpty()) {
-            return; // 没有数据,直接返回
-        }
-        // 2. 遍历每个直播间的ZSet键
-        for (String liveKey : allLiveKeys) {
-            // 3. 获取当前直播间ZSet中所有元素(按score排序)
-            // range方法:0表示第一个元素,-1表示最后一个元素,即获取全部
-            Set<String> range = redisCache.redisTemplate.opsForZSet().rangeByScore(liveKey, 0, currentTime);
-            if (range == null || range.isEmpty()) {
-                continue; // 没有数据,直接返回
-            }
-            redisCache.redisTemplate.opsForZSet()
-                    .removeRangeByScore(liveKey, 0, currentTime);
-            processAutoTask(range);
-        }
-    }
-
-    private void processAutoTask(Set<String> range) {
-        for (String liveAutoTask : range) {
-            LiveAutoTask task = JSON.parseObject(liveAutoTask, LiveAutoTask.class);
-            webSocketServer.handleAutoTask(task);
-            task.setFinishStatus(1L);
-            liveAutoTaskService.finishLiveAutoTask(task);
-        }
-    }
-
-    @Scheduled(cron = "0 0/1 * * * ?")
-    @DistributeLock(key = "autoUpdateWatchReward", scene = "task")
-    @Transactional
-    public void autoUpdateWatchReward() {
-
-        // 1.查询所有直播中的直播间
-        List<Live> lives = liveService.liveList();
-
-
-        // 2.检查是否开启观看奖励
-        List<Live> openRewardLives = lives.stream().filter(live -> StringUtils.isNotEmpty(live.getConfigJson())).collect(Collectors.toList());
-        Date now = new Date();
-
-        for (Live openRewardLive : openRewardLives) {
-            String configJson = openRewardLive.getConfigJson();
-            LiveWatchConfig config = JSON.parseObject(configJson, LiveWatchConfig.class);
-            if (config.getEnabled()) {
-                // 3.检查当前直播间的在线用户(可以传入一个时间,然后查出来当天没领取奖励的用户)
-                List<LiveWatchUser> onlineUser = liveWatchUserService.checkOnlineNoRewardUser(openRewardLive.getLiveId(), now)
-                        .stream().filter(user -> now.getTime() - user.getUpdateTime().getTime() > config.getWatchDuration() * 60 * 1000)
-                        .collect(Collectors.toList());
-                if(onlineUser.isEmpty()) continue;
-
-                List<Long> userIds = onlineUser.stream().map(LiveWatchUser::getUserId).collect(Collectors.toList());
-                // 4.保存用户领取记录
-                saveUserRewardRecord(openRewardLive.getLiveId(), userIds,config.getScoreAmount());
-                // 5.更新用户积分(芳华币
-                fsUserService.incrIntegral(userIds,config.getScoreAmount());
-                // 6.发送websocket事件消息 通知用户自动领取成功
-                userIds.forEach(userId -> webSocketServer.sendIntegralMessage(openRewardLive.getLiveId(),userId,config.getScoreAmount()));
-
-            }
-        }
-    }
-    private void saveUserRewardRecord(Long liveId, List<Long> userIds,Long scoreAmount) {
-        for (Long userId : userIds) {
-            LiveRewardRecord record = new LiveRewardRecord();
-            record.setLiveId(liveId);
-            record.setUserId(userId);
-            record.setIncomeType(1L);
-            record.setSourceType(1L);
-            record.setSourceId(0L);
-            record.setRewardType(2L);
-            record.setNum(BigDecimal.valueOf(scoreAmount));
-            record.setRewardType(2L);
-            record.setCreateTime(new Date());
-            record.setCreateBy(String.valueOf(userId));
-            liveRewardRecordService.insertLiveRewardRecord(record);
-        }
-    }
-
-    /**
-     * 更新红包领取数量
-     */
-    @Scheduled(cron = "0/5 * * * * ?")
-    @DistributeLock(key = "updateRedQuantityNum", scene = "task")
-    public void updateRedQuantityNum() {
-        liveRedConfService.updateRedQuantityNum();
-    }
-}
+//package com.fs.app.task;
+//
+//import cn.hutool.core.collection.CollUtil;
+//import cn.hutool.json.JSONUtil;
+//import com.alibaba.fastjson.JSON;
+//import com.alibaba.fastjson.JSONObject;
+//import com.fs.app.facade.LiveFacadeService;
+//import com.fs.app.vo.LotteryVo;
+//import com.fs.app.websocket.bean.SendMsgVo;
+//import com.fs.app.websocket.service.WebSocketServer;
+//import com.fs.common.annotation.QuartzRunnable;
+//import com.fs.common.constant.LiveKeysConstant;
+//import com.fs.common.core.domain.R;
+//import com.fs.common.core.redis.RedisCache;
+//import com.fs.common.core.redis.RedisUtil;
+//import com.fs.common.utils.StringUtils;
+//import com.fs.core.aspectj.lock.DistributeLock;
+//import com.fs.erp.domain.ErpDeliverys;
+//import com.fs.erp.domain.ErpOrderQuery;
+//import com.fs.erp.dto.ErpOrderQueryRequert;
+//import com.fs.erp.dto.ErpOrderQueryResponse;
+//import com.fs.erp.service.FsJstAftersalePushService;
+//import com.fs.erp.service.IErpOrderService;
+//import com.fs.erp.utils.ErpContextHolder;
+//import com.fs.live.domain.*;
+//import com.fs.live.mapper.LiveLotteryRegistrationMapper;
+//import com.fs.live.param.LiveReplayParam;
+//import com.fs.live.service.*;
+//import com.fs.live.vo.LiveConfigVo;
+//import com.fs.live.vo.LiveLotteryConfVo;
+//import com.fs.live.vo.LiveLotteryProductListVo;
+//import com.fs.store.domain.FsExpress;
+//import com.fs.store.enums.OrderLogEnum;
+//import com.fs.store.mapper.FsWarehousesMapper;
+//import com.fs.store.param.LiveAfterSalesAudit1Param;
+//import com.fs.store.service.IFsExpressService;
+//import com.fs.store.service.IFsUserService;
+//import lombok.AllArgsConstructor;
+//import org.apache.commons.collections4.CollectionUtils;
+//import org.apache.commons.lang.ObjectUtils;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//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 java.math.BigDecimal;
+//import java.text.ParseException;
+//import java.time.Instant;
+//import java.time.LocalDateTime;
+//import java.util.*;
+//import java.util.stream.Collectors;
+//
+//@Component
+//@AllArgsConstructor
+//public class Task {
+//
+//    private static final Logger log = LoggerFactory.getLogger(Task.class);
+//    private final ILiveService liveService;
+//
+//    private final ILiveDataService liveDataService;
+//
+//    private final RedisCache redisCache;
+//
+//    @Autowired
+//    private ILiveWatchUserService liveWatchUserService;
+//    @Autowired
+//    private IFsUserService fsUserService;
+//    @Autowired
+//    private ILiveRewardRecordService liveRewardRecordService;
+//    @Autowired
+//    private WebSocketServer webSocketServer;
+//    @Autowired
+//    private ILiveAutoTaskService liveAutoTaskService;
+//    @Autowired
+//    private ILiveLotteryConfService liveLotteryConfService;
+//    @Autowired
+//    private ILiveUserLotteryRecordService liveUserLotteryRecordService;
+//    @Autowired
+//    private LiveLotteryRegistrationMapper liveLotteryRegistrationMapper;
+//    @Autowired
+//    private ILiveRedConfService liveRedConfService;
+////1111
+//    @Autowired
+//    private ILiveOrderService liveOrderService;
+//
+//    @Autowired
+//    private ILiveAfterSalesService afterSalesService;
+//
+//
+//    @Autowired
+//    private IErpOrderService erpOrderService;
+//
+//
+//    @Autowired
+//    private IFsExpressService expressService;
+//
+//
+//    @Autowired
+//    private ILiveOrderLogsService orderLogsService;
+//
+//
+//    @Autowired
+//    private FsWarehousesMapper fsWarehousesMapper;
+//
+//    @Autowired
+//    public FsJstAftersalePushService fsJstAftersalePushService;
+//    @Autowired
+//    public RedisUtil redisUtil;
+//    @Scheduled(cron = "0 0/1 * * * ?")
+//    @DistributeLock(key = "updateLiveStatusByTime", scene = "task")
+//    //public void selectSopUserLogsListByTime() {
+//    public void updateLiveStatusByTime() {
+//        List<Live> list = liveService.selectNoEndLiveList();
+//        if (list.isEmpty())
+//            return;
+//        List<Long> liveIdLists = list.stream().map(Live::getLiveId).collect(Collectors.toList());
+//        List<LiveAutoTask> liveAutoTasks = liveAutoTaskService.selectLiveAutoTaskByLiveIds(liveIdLists);
+//        List<Live> activeLiveList = new ArrayList<>();
+//        LocalDateTime now = LocalDateTime.now();
+//        list.forEach(live -> {
+//            if (live.getLiveType() != 3) {
+//                if (live.getFinishTime() == null) {
+//                    if (now.isAfter(live.getStartTime().minusSeconds(2L))){
+//                        live.setStatus(2);
+//                        activeLiveList.add( live);
+//                    } else if (now.isBefore(live.getStartTime())) {
+//                        live.setStatus(1);
+//                    }
+//                } else {
+//                    if (now.isAfter(live.getStartTime().minusSeconds(2L)) && now.isBefore(live.getFinishTime())) {
+//                        live.setStatus(2);
+//                        activeLiveList.add( live);
+//                    } else if (now.isBefore(live.getStartTime().minusSeconds(2L))) {
+//                        live.setStatus(1);
+//                    } else if (now.isAfter(live.getFinishTime().minusSeconds(2L))) {
+//                        live.setStatus(3);
+//                    }
+//                }
+//            } else {
+//                // 直播回放只需要检测结束时间就好了
+//                LiveReplayParam liveReplayParam = JSON.parseObject(live.getLiveConfig(), LiveReplayParam.class);
+//                if (liveReplayParam.getIsPlaybackOpen()) {
+//                    if (liveReplayParam.getFinishTime() != null) {
+//                        if (now.isAfter(live.getFinishTime().minusSeconds(2L))) {
+//                            live.setStatus(3);
+//                        }
+//                    }
+//                }
+//            }
+//
+//        });
+//        String key = "live:auto_task:";
+//        if(!activeLiveList.isEmpty()){
+//            activeLiveList.forEach(live -> {
+//                List<LiveAutoTask> collect = liveAutoTasks.stream().filter(liveAutoTask -> liveAutoTask.getLiveId().equals(live.getLiveId())).collect(Collectors.toList());
+//                if (!collect.isEmpty()) {
+//                    collect.forEach(liveAutoTask -> {
+//                        liveAutoTask.setCreateTime(null);
+//                        liveAutoTask.setUpdateTime(null);
+//                        redisCache.redisTemplate.opsForZSet().add(key + live.getLiveId(), JSON.toJSONString(liveAutoTask),liveAutoTask.getAbsValue().getTime());
+//                        redisCache.redisTemplate.expire(key+live.getLiveId(), 30, java.util.concurrent.TimeUnit.MINUTES);
+//                    });
+//                }
+//            });
+//        }
+//
+//        if(!list.isEmpty()){
+//            for (Live live : list) {
+//                liveService.updateLive(live);
+//            }
+//        }
+//    }
+//    @Scheduled(cron = "0/1 * * * * ?")
+//    @DistributeLock(key = "liveLotteryTask", scene = "task")
+//    public void liveLotteryTask() {
+//        long currentTime = Instant.now().toEpochMilli(); // 当前时间戳(毫秒)
+//        String lotteryKey = "live:lottery_task:*";
+//        Set<String> allLiveKeys = redisCache.redisTemplate.keys(lotteryKey);
+//        if (allLiveKeys != null && !allLiveKeys.isEmpty()) {
+//            for (String liveKey : allLiveKeys) {
+//                Set<String> range = redisCache.redisTemplate.opsForZSet().rangeByScore(liveKey, 0, currentTime);
+//                if (range == null || range.isEmpty()) {
+//                    continue;
+//                }
+//                processLotteryTask(range);
+//                redisCache.redisTemplate.opsForZSet()
+//                        .removeRangeByScore(liveKey, 0, currentTime);
+//            }
+//        }
+//
+//        String redKey = "live:red_task:*";
+//        allLiveKeys = redisCache.redisTemplate.keys(redKey);
+//        if (allLiveKeys == null || allLiveKeys.isEmpty()) {
+//            return;
+//        }
+//        for (String liveKey : allLiveKeys) {
+//            Set<String> range = redisCache.redisTemplate.opsForZSet().rangeByScore(liveKey, 0, currentTime);
+//            if (range == null || range.isEmpty()) {
+//                continue;
+//            }
+//
+//            updateRedStatus(range);
+//            redisCache.redisTemplate.opsForZSet()
+//                    .removeRangeByScore(liveKey, 0, currentTime);
+//            try {
+//                // 广播红包关闭消息
+//                SendMsgVo sendMsgVo = new SendMsgVo();
+//                sendMsgVo.setLiveId(Long.valueOf(liveKey));
+//                sendMsgVo.setCmd("red");
+//                sendMsgVo.setStatus(-1);
+//                webSocketServer.broadcastMessage(Long.valueOf(liveKey), JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+//            } catch (Exception e) {
+//                log.error("更新红包状态异常", e);
+//            }
+//        }
+//    }
+//
+//    private void updateRedStatus(Set<String> range) {
+//
+//        liveRedConfService.finishRedStatusBySetIds(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;
+//            // 先将参与记录插入数据库
+//            String hashKey = String.format(LiveKeysConstant.LIVE_HOME_PAGE_CONFIG_DRAW, liveLottery.getLiveId(), liveLottery.getLotteryId());
+//            Map<Object, Object> hashEntries = redisUtil.hashEntries(hashKey);
+//            List<LiveLotteryRegistration> registrationList = new ArrayList<>();
+//            if (CollUtil.isNotEmpty(hashEntries)) {
+//                registrationList = hashEntries.values().stream()
+//                        .map(value -> JSONUtil.toBean(JSONUtil.parseObj(value), LiveLotteryRegistration.class))
+//                        .collect(Collectors.toList());
+//                liveLotteryRegistrationMapper.insertLiveLotteryRegistrationBatch(registrationList);
+//            }
+//
+//            // 查询在线用户 并且参与了抽奖的用户
+//            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 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.setUserName(winningUser.getNickName());
+//                    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.getLiveId(), JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+//
+//            // 删除缓存 同步抽奖记录
+//            redisUtil.delete(hashKey);
+//        }
+//
+//        List<Long> collect = liveLotteries.stream().map(LiveLotteryConfVo::getLotteryId).collect(Collectors.toList());
+//        liveLotteryConfService.finishStatusByLotteryIds(collect);
+//    }
+//
+//    @Scheduled(cron = "0/1 * * * * ?")
+//    @DistributeLock(key = "liveAutoTask", scene = "task")
+//    public void liveAutoTask() {
+//        long currentTime = Instant.now().toEpochMilli(); // 当前时间戳(毫秒)
+//
+//        Set<String> allLiveKeys = redisCache.redisTemplate.keys("live:auto_task:*");
+//        if (allLiveKeys == null || allLiveKeys.isEmpty()) {
+//            return; // 没有数据,直接返回
+//        }
+//        // 2. 遍历每个直播间的ZSet键
+//        for (String liveKey : allLiveKeys) {
+//            // 3. 获取当前直播间ZSet中所有元素(按score排序)
+//            // range方法:0表示第一个元素,-1表示最后一个元素,即获取全部
+//            Set<String> range = redisCache.redisTemplate.opsForZSet().rangeByScore(liveKey, 0, currentTime);
+//            if (range == null || range.isEmpty()) {
+//                continue; // 没有数据,直接返回
+//            }
+//            redisCache.redisTemplate.opsForZSet()
+//                    .removeRangeByScore(liveKey, 0, currentTime);
+//            processAutoTask(range);
+//        }
+//    }
+//
+//    private void processAutoTask(Set<String> range) {
+//        for (String liveAutoTask : range) {
+//            LiveAutoTask task = JSON.parseObject(liveAutoTask, LiveAutoTask.class);
+//            webSocketServer.handleAutoTask(task);
+//            task.setFinishStatus(1L);
+//            liveAutoTaskService.finishLiveAutoTask(task);
+//        }
+//    }
+//
+//    @Scheduled(cron = "0 0/1 * * * ?")
+//    @DistributeLock(key = "autoUpdateWatchReward", scene = "task")
+//    @Transactional
+//    public void autoUpdateWatchReward() {
+//
+//        // 1.查询所有直播中的直播间
+//        List<Live> lives = liveService.liveList();
+//
+//
+//        // 2.检查是否开启观看奖励
+//        List<Live> openRewardLives = lives.stream().filter(live -> StringUtils.isNotEmpty(live.getConfigJson())).collect(Collectors.toList());
+//        Date now = new Date();
+//
+//        for (Live openRewardLive : openRewardLives) {
+//            String configJson = openRewardLive.getConfigJson();
+//            LiveWatchConfig config = JSON.parseObject(configJson, LiveWatchConfig.class);
+//            if (config.getEnabled()) {
+//                // 3.检查当前直播间的在线用户(可以传入一个时间,然后查出来当天没领取奖励的用户)
+//                List<LiveWatchUser> onlineUser = liveWatchUserService.checkOnlineNoRewardUser(openRewardLive.getLiveId(), now)
+//                        .stream().filter(user -> now.getTime() - user.getUpdateTime().getTime() > config.getWatchDuration() * 60 * 1000)
+//                        .collect(Collectors.toList());
+//                if(onlineUser.isEmpty()) continue;
+//
+//                List<Long> userIds = onlineUser.stream().map(LiveWatchUser::getUserId).collect(Collectors.toList());
+//                // 4.保存用户领取记录
+//                saveUserRewardRecord(openRewardLive, userIds,config.getScoreAmount());
+//                // 5.更新用户积分(芳华币
+//                fsUserService.incrIntegral(userIds,config.getScoreAmount());
+//                // 6.发送websocket事件消息 通知用户自动领取成功
+//                userIds.forEach(userId -> webSocketServer.sendIntegralMessage(openRewardLive.getLiveId(),userId,config.getScoreAmount()));
+//
+//            }
+//        }
+//    }
+//    private void saveUserRewardRecord(Live live, List<Long> userIds,Long scoreAmount) {
+//        for (Long userId : userIds) {
+//            LiveRewardRecord record = new LiveRewardRecord();
+//            record.setLiveId(live.getLiveId());
+//            record.setUserId(userId);
+//            record.setIncomeType(1L);
+//            record.setSourceType(1L);
+//            record.setSourceId(live.getCompanyId() == null ? 0L : live.getCompanyId());
+//            record.setRewardType(2L);
+//            record.setNum(BigDecimal.valueOf(scoreAmount));
+//            record.setRewardType(2L);
+//            record.setCreateTime(new Date());
+//            record.setCreateBy(String.valueOf(userId));
+//            liveRewardRecordService.insertLiveRewardRecord(record);
+//        }
+//    }
+//
+//    /**
+//     * 更新红包领取数量
+//     */
+//    @Scheduled(cron = "0/5 * * * * ?")
+//    @DistributeLock(key = "updateRedQuantityNum", scene = "task")
+//    public void updateRedQuantityNum() {
+//        liveRedConfService.updateRedQuantityNum();
+//    }
+//}