Browse Source

优化代码上传

yuhongqi 4 ngày trước cách đây
mục cha
commit
6de197c3ea

+ 12 - 10
fs-admin/src/main/java/com/fs/task/LiveTask.java

@@ -1,42 +1,35 @@
 package com.fs.task;
 
 import com.fs.common.annotation.QuartzRunnable;
-import com.fs.common.core.redis.RedisCache;
-import com.fs.company.mapper.CompanyUserMapper;
 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.FsJstCodPushService;
-import com.fs.erp.service.IErpGoodsService;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.erp.utils.ErpContextHolder;
+import com.fs.live.utils.redis.RedisBatchHandler;
 import com.fs.live.domain.LiveAfterSales;
 import com.fs.live.domain.LiveOrder;
 import com.fs.live.service.*;
 import com.fs.store.domain.FsExpress;
-import com.fs.store.domain.FsStoreAfterSales;
-import com.fs.store.domain.FsStoreOrder;
 import com.fs.store.enums.OrderLogEnum;
 import com.fs.store.mapper.*;
-import com.fs.store.param.FsStoreAfterSalesAudit1Param;
 import com.fs.store.param.LiveAfterSalesAudit1Param;
 import com.fs.store.service.*;
-import com.fs.system.service.ISysConfigService;
-import com.fs.wx.mapper.FsWxExpressTaskMapper;
 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.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
 import java.text.ParseException;
 import java.util.List;
 
+import static com.fs.live.utils.redis.RedisBatchHandler.CONSUME_INTERVAL;
+
 /**
  * 定时任务调度
  * @author fs
@@ -70,6 +63,8 @@ public class LiveTask {
 
     @Autowired
     public FsJstAftersalePushService fsJstAftersalePushService;
+    @Autowired
+    public RedisBatchHandler redisBatchHandler;
 
     /**
      * 超时订单自动取消
@@ -199,4 +194,11 @@ public class LiveTask {
         }
 
     }
+    /**
+     * 更新发货状态
+     */
+    @Scheduled(fixedRate = CONSUME_INTERVAL)
+    public void insertLiveTrralog() {
+        redisBatchHandler.consumeBatchData();
+    }
 }

+ 1 - 0
fs-common/src/main/java/com/fs/common/constant/RedisConstant.java

@@ -5,6 +5,7 @@ package com.fs.common.constant;
 public class RedisConstant {
     // 库存Key前缀
     public static final String STOCK_KEY_PREFIX = "product:stock:";
+    public static final String SALE_KEY_PREFIX = "product:sale:";
     // 分布式锁Key前缀
     public static final String LOCK_KEY_PREFIX = "product:lock:";
     // 锁过期时间(30秒,避免死锁,大于业务执行时间)

+ 37 - 4
fs-common/src/main/java/com/fs/common/core/redis/RedisUtil.java

@@ -1,14 +1,13 @@
 package com.fs.common.core.redis;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.Cursor;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ScanOptions;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Component;
 
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -233,6 +232,40 @@ public class RedisUtil {
         return redisTemplate.opsForHash().entries(key);
     }
 
+    /**
+     * 优化版:切片查询 Redis Hash 所有条目(分批 hscan)
+     * @param key Redis Hash 的 key
+     * @param batchSize 每次扫描的条数(建议 100-1000,根据业务调整)
+     * @return 完整的 Hash 键值对
+     */
+    public Map<Object, Object> hashEntriesByScan(String key, int batchSize) {
+        // 最终返回的完整Map(按需可改为边遍历边处理,不一次性存储)
+        Map<Object, Object> resultMap = new HashMap<>();
+
+        // 1. 构建 Scan 配置:count 指定每次扫描的建议条数(非绝对,Redis 内部优化)
+        ScanOptions scanOptions = ScanOptions.scanOptions()
+                .count(batchSize) // 每次扫描最多返回 batchSize 条
+                .match("*")       // 匹配所有字段(可指定前缀,如 "user_*" 过滤)
+                .build();
+
+        // 2. 获取游标,开始分批遍历(必须关闭游标,否则会泄漏 Redis 连接)
+        try (Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(key, scanOptions)) {
+            // 3. 迭代游标,分批读取数据
+            while (cursor.hasNext()) {
+                Map.Entry<Object, Object> entry = cursor.next();
+                resultMap.put(entry.getKey(), entry.getValue());
+
+                // 【可选】若不需要完整返回,可在此处边遍历边处理(比如写入数据库/缓存)
+                // processEntry(entry.getKey(), entry.getValue());
+            }
+        } catch (Exception e) {
+            // 异常处理:记录日志、告警,避免游标泄漏
+            throw new RuntimeException("Redis Hash 切片查询失败,key=" + key, e);
+        }
+
+        return resultMap;
+    }
+
     /**
      * 获取哈希表中数量
      *

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

@@ -83,4 +83,6 @@ public interface LiveTrafficLogMapper
     List<LiveTrafficLogListVO> selectTrafficByCompany(@Param("maps") LiveTrafficLogParam param);
 
     void insertOrUpdateLiveTrafficLog(LiveTrafficLog trafficLog);
+
+    void batchInsert(@Param("list") List<LiveTrafficLog> list);
 }

+ 3 - 0
fs-service-system/src/main/java/com/fs/live/mapper/LiveVideoMapper.java

@@ -1,6 +1,8 @@
 package com.fs.live.mapper;
 
 
+import com.fs.common.annotation.DataSource;
+import com.fs.common.enums.DataSourceType;
 import com.fs.live.domain.LiveVideo;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
@@ -83,6 +85,7 @@ public interface LiveVideoMapper
     List<LiveVideo> selectByLiveId(@Param("liveId")Long liveId);
 
     @Select("select * from live_video where live_id = #{liveId} and video_type = #{videoType}")
+    @DataSource(DataSourceType.SLAVE)
     List<LiveVideo> selectByLiveIdAndType(@Param("liveId")Long liveId,@Param("videoType") Integer videoType);
 
     @Select("select * from live_video where live_id = #{liveId}")

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 223 - 305
fs-service-system/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java


+ 7 - 2
fs-service-system/src/main/java/com/fs/live/service/impl/LiveTrafficLogServiceImpl.java

@@ -13,6 +13,7 @@ import com.fs.live.domain.LiveVideo;
 import com.fs.live.mapper.LiveVideoMapper;
 import com.fs.live.param.LiveFinishUParam;
 import com.fs.live.param.LiveTrafficLogParam;
+import com.fs.live.utils.redis.RedisBatchHandler;
 import com.fs.live.vo.LiveTrafficLogListVO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
@@ -37,6 +38,8 @@ public class LiveTrafficLogServiceImpl implements ILiveTrafficLogService
     private LiveTrafficLogMapper liveTrafficLogMapper;
     @Autowired
     private LiveVideoMapper liveVideoMapper;
+    @Autowired
+    public RedisBatchHandler redisBatchHandler;
 
     /**
      * 查询直播流量记录
@@ -140,7 +143,8 @@ public class LiveTrafficLogServiceImpl implements ILiveTrafficLogService
             if (StringUtils.isNotEmpty(trafficLog.getUuId())) {
                 // 直接插入或更新
 //                logger.error("zyp \n【插入或更新流量】:{}",trafficLog);
-                liveTrafficLogMapper.insertOrUpdateLiveTrafficLog(trafficLog);
+                redisBatchHandler.addDataToRedis(trafficLog);
+//                liveTrafficLogMapper.insertOrUpdateLiveTrafficLog(trafficLog);
             }
         } catch (Exception e) {
             e.printStackTrace();
@@ -165,7 +169,8 @@ public class LiveTrafficLogServiceImpl implements ILiveTrafficLogService
             if (StringUtils.isNotEmpty(trafficLog.getUuId())) {
                 // 直接插入或更新
 //                logger.error("zyp \n【插入或更新流量】:{}",trafficLog);
-                liveTrafficLogMapper.insertOrUpdateLiveTrafficLog(trafficLog);
+                redisBatchHandler.addDataToRedis(trafficLog);
+//                liveTrafficLogMapper.insertOrUpdateLiveTrafficLog(trafficLog);
             }
         } catch (Exception e) {
             e.printStackTrace();

+ 63 - 0
fs-service-system/src/main/java/com/fs/live/utils/redis/RedisBatchHandler.java

@@ -0,0 +1,63 @@
+package com.fs.live.utils.redis;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.live.domain.LiveTrafficLog;
+import com.fs.live.mapper.LiveTrafficLogMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+public class RedisBatchHandler {
+    @Autowired
+    public RedisTemplate redisTemplate;
+    @Autowired
+    public LiveTrafficLogMapper liveTrafficLogMapper;
+    // Redis队列key
+    private static final String BATCH_QUEUE_KEY = "live_traffic:batch:queue";
+    // 批量拉取条数
+    private static final int BATCH_PULL_SIZE = 500;
+    // 定时消费间隔
+    public static final long CONSUME_INTERVAL = 500;
+
+    // 1. 入队:多服务实例写入Redis List
+    public void addDataToRedis(LiveTrafficLog data) {
+        try {
+            // 序列化数据(用JSON)
+            String json = JSON.toJSONString(data);
+            redisTemplate.opsForList().rightPush(BATCH_QUEUE_KEY, json);
+        } catch (Exception e) {
+            // 降级为本地队列/单条插入
+            log.error("Redis入队失败,降级处理", e);
+        }
+    }
+
+    // 2. 定时消费:独立线程拉取批量数据写入MySQL
+    public void consumeBatchData() {
+        // 批量拉取Redis List中的数据(非阻塞)
+        List<String> jsonList = redisTemplate.opsForList().range(BATCH_QUEUE_KEY, 0, BATCH_PULL_SIZE - 1);
+        if (jsonList.isEmpty()) {
+            return;
+        }
+        // 转换为实体类
+        List<LiveTrafficLog> batchList = jsonList.stream()
+                .map(json -> JSON.parseObject(json, LiveTrafficLog.class))
+                .collect(Collectors.toList());
+        try {
+            // 批量写入数据库
+            liveTrafficLogMapper.batchInsert(batchList);
+            // 删除已消费的数据
+            redisTemplate.opsForList().trim(BATCH_QUEUE_KEY, batchList.size(), -1);
+        } catch (Exception e) {
+            // 消费失败:记录日志,不删除Redis数据(重试)
+            log.error("Redis批量消费失败,将重试", e);
+        }
+    }
+}

+ 11 - 1
fs-service-system/src/main/java/com/fs/store/service/impl/FsCityServiceImpl.java

@@ -1,6 +1,8 @@
 package com.fs.store.service.impl;
 
 import java.util.List;
+
+import com.fs.common.core.redis.RedisCache;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
@@ -19,6 +21,8 @@ public class FsCityServiceImpl implements IFsCityService
 {
     @Autowired
     private FsCityMapper fsCityMapper;
+    @Autowired
+    private RedisCache redisCache;
 
     /**
      * 查询城市
@@ -94,6 +98,12 @@ public class FsCityServiceImpl implements IFsCityService
 
     @Override
     public List<FsCity> selectFsCitys() {
-        return fsCityMapper.selectFsCitys();
+        List<FsCity> redisList = redisCache.getCacheObject("city");
+        if(redisList != null){
+            return redisList;
+        }
+        List<FsCity> list = fsCityMapper.selectFsCitys();
+        redisCache.setCacheObject("city", list);
+        return list;
     }
 }

+ 21 - 10
fs-service-system/src/main/resources/mapper/live/LiveTrafficLogMapper.xml

@@ -120,16 +120,27 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                      #{companyId},
                      #{videoId},
                      #{uuId}
-                 ) ON DUPLICATE KEY UPDATE
-                     user_id = VALUES(user_id),
-            live_id = VALUES(live_id),
-            create_time = VALUES(create_time),
-            qw_external_contact_id = VALUES(qw_external_contact_id),
-            internet_traffic = VALUES(internet_traffic),
-            qw_user_id = VALUES(qw_user_id),
-            company_user_id = VALUES(company_user_id),
-            company_id = VALUES(company_id),
-            video_id = VALUES(video_id)
+                 )
+        on duplicate key update
+        <trim suffixOverrides=",">
+            <if test="internetTraffic != null">internet_traffic = #{internetTraffic},</if>
+        </trim>
+    </insert>
+
+    <insert id="batchInsert" parameterType="java.util.List">
+        INSERT INTO live_traffic_log (
+        user_id, live_id, create_time, qw_external_contact_id,
+        internet_traffic, qw_user_id, company_user_id, company_id, video_id, uu_id
+        ) VALUES
+        <foreach collection="list" item="item" separator=",">
+            (
+            #{item.userId}, #{item.liveId}, #{item.createTime}, #{item.qwExternalContactId},
+            #{item.internetTraffic}, #{item.qwUserId}, #{item.companyUserId},
+            #{item.companyId}, #{item.videoId}, #{item.uuId}
+            )
+        </foreach>
+        ON DUPLICATE KEY UPDATE
+        internet_traffic = VALUES(internet_traffic)
     </insert>
 
 </mapper>

+ 1 - 1
fs-user-app/src/main/java/com/fs/app/facade/impl/LiveFacadeServiceImpl.java

@@ -114,7 +114,7 @@ public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeS
 
         List<LiveWatchUserVO> liveWatchUserVOS;
         String setKey = String.format(LiveKeysConstant.LIVE_WATCH_USERS, param.getLiveId());
-        Map<Object, Object> hashEntries = redisUtil.hashEntries(setKey);
+        Map<Object, Object> hashEntries = redisUtil.hashEntriesByScan(setKey,50);
         if (CollUtil.isEmpty(hashEntries)) {
             liveWatchUserVOS = liveWatchUserService.asyncToCache(param.getLiveId());
         } else {

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

@@ -1,392 +1,15 @@
-//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();
-//    }
-//}
+package com.fs.app.task;
+
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+@AllArgsConstructor
+@Slf4j
+public class Task {
+
+
+}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác