소스 검색

直播开始更新直播自动化任务

xgb 2 주 전
부모
커밋
b85d2a4d3c

+ 2 - 2
fs-admin/src/main/java/com/fs/live/controller/LiveDataController.java

@@ -147,7 +147,7 @@ public class LiveDataController extends BaseController {
         }
 
         PageHelper.startPage(pageNum, pageSize);
-        return liveDataService.getLiveUserDetailListBySql(liveId,null,null);
+        return liveDataService.getLiveUserDetailListBySqlNew(liveId);
     }
 
     /**
@@ -181,7 +181,7 @@ public class LiveDataController extends BaseController {
     @Log(title = "直播间用户详情", businessType = BusinessType.EXPORT)
     @GetMapping("/exportLiveUserDetail")
     public AjaxResult exportLiveUserDetail(@RequestParam Long liveId) {
-        List<LiveUserDetailExportVO> list = liveDataService.exportLiveUserDetail(liveId,null,null);
+        List<LiveUserDetailExportVO> list = liveDataService.exportLiveUserDetailNew(liveId);
         if (list == null || list.isEmpty()) {
             return AjaxResult.error("未找到用户详情数据");
         }

+ 11 - 0
fs-live-app/src/main/java/com/fs/live/task/Task.java

@@ -373,6 +373,7 @@ public class Task {
     @DistributeLock(key = "liveAutoTask", scene = "task")
     public void liveAutoTask() {
         long currentTime = Instant.now().toEpochMilli(); // 当前时间戳(毫秒)
+        log.info("定时任务执行 - 当前时间戳: {}, 当前时间: {}", currentTime, new Date(currentTime));
 
         Set<String> allLiveKeys = redisCache.redisTemplate.keys("live:auto_task:*");
         if (allLiveKeys == null || allLiveKeys.isEmpty()) {
@@ -384,6 +385,7 @@ public class Task {
             // range方法:0表示第一个元素,-1表示最后一个元素,即获取全部
             Set<String> range = redisCache.redisTemplate.opsForZSet().rangeByScore(liveKey, 0, currentTime);
             if (range == null || range.isEmpty()) {
+                log.info("当前直播间没有数据,跳过处理");
                 continue; // 没有数据,直接返回
             }
             redisCache.redisTemplate.opsForZSet()
@@ -392,6 +394,15 @@ public class Task {
         }
     }
 
+    public static void main(String[] args) {
+        long currentTime = Instant.now().toEpochMilli();
+        System.out.println(currentTime);
+        long startTime = 1776219541000L;
+        System.out.println(new Date(startTime));
+        System.out.println(new Date(currentTime));
+
+    }
+
     private void processAutoTask(Set<String> range) {
         for (String liveAutoTask : range) {
             LiveAutoTask task = JSON.parseObject(liveAutoTask, LiveAutoTask.class);

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

@@ -91,4 +91,6 @@ public interface LiveAutoTaskMapper {
 
     @Select("select * from live_auto_task where live_id= #{liveId} and abs_value > #{nowDate} and task_type in (1,2,4) and finish_status = 1 order by abs_value ")
     List<LiveAutoTask> consoleList(@Param("liveId") Long liveId,@Param("nowDate") Date nowDate);
+
+    LiveAutoTask selectLastSignTaskByLiveId(Long liveId);
 }

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

@@ -176,4 +176,6 @@ public interface LiveDataMapper {
      */
     @DataSource(DataSourceType.SLAVE)
     List<LiveUserDetailVo> selectLiveUserDetailListBySql(@Param("liveId") Long liveId,@Param("companyId") Long companyId,@Param("companyUserId") Long companyUserId);
+
+    List<LiveUserDetailVo> selectLiveUserDetailListBySqlNew(Long liveId);
 }

+ 9 - 0
fs-service/src/main/java/com/fs/live/service/ILiveDataService.java

@@ -169,4 +169,13 @@ public interface ILiveDataService {
     List<LiveUserDetailExportVO> exportLiveUserDetail(Long liveId, Long companyId, Long companyUserId);
 
     List<LiveDataListVo> exportLiveData(LiveDataParam param);
+
+    /**
+     * 获取直播间用户详情列表(SQL方式)
+     * @param liveId 直播间ID
+     * @return 用户详情列表
+     */
+    R getLiveUserDetailListBySqlNew(Long liveId);
+
+    List<LiveUserDetailExportVO> exportLiveUserDetailNew(Long liveId);
 }

+ 73 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveAutoTaskServiceImpl.java

@@ -4,10 +4,12 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
@@ -18,9 +20,11 @@ import com.fs.live.service.ILiveAutoTaskService;
 import com.fs.live.service.ILiveGoodsService;
 import com.fs.live.vo.LiveGoodsVo;
 import com.fs.live.vo.LiveLotteryProductListVo;
+import org.apache.commons.lang3.StringUtils;
 import org.checkerframework.checker.units.qual.A;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -179,6 +183,37 @@ public class LiveAutoTaskServiceImpl implements ILiveAutoTaskService {
             baseMapper.insertLiveAutoTask(liveAutoTask);
 
         }else if(liveAutoTask.getTaskType() == 7L){
+            // 查询最新序号
+            LiveAutoTask task = baseMapper.selectLastSignTaskByLiveId(liveAutoTask.getLiveId());
+            int nextSignNo = 1; // 默认第一次签到
+
+            if(task != null && StringUtils.isNotEmpty(task.getContent())){
+                try {
+                    // 解析 content 获取 signNo
+                    JSONObject contentObj = JSON.parseObject(task.getContent());
+                    String currentSignNo = contentObj.getString("signNo");
+
+                    if ("1".equals(currentSignNo)) {
+                        nextSignNo = 2;
+                    } else if ("2".equals(currentSignNo)) {
+                        nextSignNo = 3;
+                    } else if ("3".equals(currentSignNo)) {
+                        return R.error("最多只能设置三次签到任务");
+                    }else {
+                        return R.error("签到任务配置错误");
+                    }
+                } catch (Exception e) {
+                    log.error("解析签到任务content失败", e);
+                    return R.error("签到任务配置错误");
+                }
+            }
+
+            // 设置新的签到序号
+            JSONObject content = new JSONObject();
+            content.put("signNo", nextSignNo);
+            liveAutoTask.setContent(content.toJSONString());
+
+
             baseMapper.insertLiveAutoTask(liveAutoTask);
 
         } else {
@@ -398,6 +433,44 @@ public class LiveAutoTaskServiceImpl implements ILiveAutoTaskService {
         if (!updateList.isEmpty()) {
             baseMapper.batchUpdateLiveAutoTask(updateList);
         }
+
+        // 重新计算后,需要清理并重建Redis缓存
+        // 因为任务的触发时间(score)已经改变,旧的缓存已失效
+        try {
+            String cacheKey = "live:auto_task:" + live.getLiveId();
+
+            // 1. 删除旧的缓存
+            redisCache.deleteObject(cacheKey);
+
+            // 2. 如果直播间正在直播,重新构建缓存
+            if (live.getStatus() != null && live.getStatus() == 2) {
+                for (LiveAutoTask task : liveAutoTasks) {
+                    // 只缓存状态为启用且未完成的任务
+                    if (task.getStatus() != null && task.getStatus() == 1L
+                            && task.getFinishStatus() != null && task.getFinishStatus() == 0L) {
+                        LiveAutoTask cacheTask = new LiveAutoTask();
+                        BeanUtils.copyProperties(task, cacheTask);
+                        cacheTask.setCreateTime(null);
+                        cacheTask.setUpdateTime(null);
+
+                        redisCache.zSetAdd(cacheKey, JSON.toJSONString(cacheTask), task.getAbsValue().getTime());
+                    }
+                }
+
+                // 设置过期时间
+                if (!liveAutoTasks.isEmpty()) {
+                    redisCache.expire(cacheKey, 1, TimeUnit.DAYS);
+                }
+
+                log.info("直播间开始时间变化,已重新构建自动化任务缓存: liveId={}, 任务数={}",
+                        live.getLiveId(), liveAutoTasks.size());
+            } else {
+                log.info("直播间未开播,已清理自动化任务缓存: liveId={}", live.getLiveId());
+            }
+        } catch (Exception e) {
+            log.error("重新构建自动化任务缓存失败: liveId={}, error={}",
+                    live.getLiveId(), e.getMessage(), e);
+        }
     }
 
     @Override

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

@@ -222,6 +222,9 @@ public class LiveDataServiceImpl implements ILiveDataService {
         }
         return liveDataList;
     }
+
+
+
     /**
      * 查询直播数据
      *
@@ -738,6 +741,38 @@ public class LiveDataServiceImpl implements ILiveDataService {
         return data;
     }
 
+    @Override
+    public R getLiveUserDetailListBySqlNew(Long liveId) {
+        List<LiveUserDetailVo> userDetailList = liveDataMapper.selectLiveUserDetailListBySqlNew(liveId);
+        for (LiveUserDetailVo liveUserDetailVo : userDetailList) {
+            if(liveUserDetailVo.getSignTime1()!=null){
+                liveUserDetailVo.setSignFirst("已打卡");
+            }else {
+                liveUserDetailVo.setSignFirst("未打卡");
+            }
+
+            if(liveUserDetailVo.getSignTime2()!=null){
+                liveUserDetailVo.setSignSecond("已打卡");
+            }else {
+                liveUserDetailVo.setSignSecond("未打卡");
+            }
+
+            if(liveUserDetailVo.getSignTime3()!=null){
+                liveUserDetailVo.setSignThird("已打卡");
+            }else {
+                liveUserDetailVo.setSignThird("未打卡");
+            }
+        }
+        // 使用 PageInfo 获取分页信息
+        PageInfo<LiveUserDetailVo> pageInfo = new PageInfo<>(userDetailList);
+        R data = R.ok().put("data", userDetailList);
+        if (pageInfo != null) {
+            data.put("total", pageInfo.getTotal());
+        }
+        return data;
+    }
+
+
     @Override
     public R getLiveDataDetailByServer(Long liveId) {
         // 查询数据服务器处理方式:通过查询各个表的数据,在内存中计算统计
@@ -1113,6 +1148,64 @@ public class LiveDataServiceImpl implements ILiveDataService {
         return result;
     }
 
+    @Override
+    public List<LiveUserDetailExportVO> exportLiveUserDetailNew(Long liveId) {
+        // 查询用户详情列表
+        List<LiveUserDetailVo> userDetailList = liveDataMapper.selectLiveUserDetailListBySqlNew(liveId);
+        if (userDetailList == null || userDetailList.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        // 转换为导出VO列表
+        List<LiveUserDetailExportVO> exportList = new ArrayList<>();
+        for (LiveUserDetailVo userDetail : userDetailList) {
+            LiveUserDetailExportVO exportVO = new LiveUserDetailExportVO();
+
+            // 用户基本信息
+            exportVO.setUserId(userDetail.getUserId());
+            exportVO.setUserName(userDetail.getUserName());
+
+            // 观看时长(秒转分钟)
+            exportVO.setLiveWatchDuration(formatSecondsToMinutes(userDetail.getLiveWatchDuration()));
+            exportVO.setPlaybackWatchDuration(formatSecondsToMinutes(userDetail.getPlaybackWatchDuration()));
+
+            // 计算总观看时长
+            Long totalSeconds = (userDetail.getLiveWatchDuration() != null ? userDetail.getLiveWatchDuration() : 0L) +
+                    (userDetail.getPlaybackWatchDuration() != null ? userDetail.getPlaybackWatchDuration() : 0L);
+//            exportVO.setTotalWatchDuration(formatSecondsToMinutes(totalSeconds));
+
+            // 订单信息
+            exportVO.setOrderCount(Math.toIntExact(userDetail.getOrderCount()));
+            exportVO.setOrderAmount(formatMoney(userDetail.getOrderAmount()));
+
+            // 公司和销售信息
+            exportVO.setCompanyName(userDetail.getCompanyName());
+            exportVO.setSalesName(userDetail.getSalesName());
+
+            if(userDetail.getSignTime1()!=null){
+                exportVO.setSignFirst("已打卡");
+            }else {
+                exportVO.setSignFirst("未打卡");
+            }
+
+            if(userDetail.getSignTime2()!=null){
+                exportVO.setSignSecond("已打卡");
+            }else {
+                exportVO.setSignSecond("未打卡");
+            }
+
+            if(userDetail.getSignTime3()!=null){
+                exportVO.setSignThird("已打卡");
+            }else {
+                exportVO.setSignThird("未打卡");
+            }
+
+
+            exportList.add(exportVO);
+        }
+        return exportList;
+    }
+
     /**
      * 导出直播间用户详情数据
      * @param liveId 直播间ID

+ 9 - 7
fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java

@@ -1021,13 +1021,15 @@ public class LiveServiceImpl implements ILiveService
         baseMapper.updateLive(exist);
         // 清除缓存
         clearLiveCache(live.getLiveId());
-        List<LiveAutoTask> liveAutoTasks = liveAutoTaskService.selectNoActivedByLiveId(exist.getLiveId(), new Date());
-        liveAutoTasks.forEach(liveAutoTask -> {
-            liveAutoTask.setCreateTime(null);
-            liveAutoTask.setUpdateTime(null);
-            redisCache.redisTemplate.opsForZSet().add("live:auto_task:" + live.getLiveId(), JSON.toJSONString(liveAutoTask),liveAutoTask.getAbsValue().getTime());
-            redisCache.redisTemplate.expire("live:auto_task:"+live.getLiveId(), 1, TimeUnit.DAYS);
-        });
+//        List<LiveAutoTask> liveAutoTasks = liveAutoTaskService.selectNoActivedByLiveId(exist.getLiveId(), new Date());
+//        liveAutoTasks.forEach(liveAutoTask -> {
+//            liveAutoTask.setCreateTime(null);
+//            liveAutoTask.setUpdateTime(null);
+//            redisCache.redisTemplate.opsForZSet().add("live:auto_task:" + live.getLiveId(), JSON.toJSONString(liveAutoTask),liveAutoTask.getAbsValue().getTime());
+//            redisCache.redisTemplate.expire("live:auto_task:"+live.getLiveId(), 1, TimeUnit.DAYS);
+//        });
+        // 充值
+        liveAutoTaskService.recalcLiveAutoTask(exist);
         String cacheKey = String.format(LiveKeysConstant.LIVE_DATA_CACHE, live.getLiveId());
         redisCache.deleteObject(cacheKey);
         String cacheKey2 = String.format(LiveKeysConstant.LIVE_FLAG_CACHE, live.getLiveId());

+ 15 - 4
fs-service/src/main/java/com/fs/live/vo/LiveUserDetailExportVO.java

@@ -16,6 +16,15 @@ public class LiveUserDetailExportVO {
     @Excel(name = "用户ID")
     private Long userId;
 
+    @Excel(name = "打卡1")
+    private String signFirst;
+
+    @Excel(name = "打卡2")
+    private String signSecond;
+
+    @Excel(name = "打卡3")
+    private String signThird;
+
     /** 用户名称 */
     @Excel(name = "用户名称")
     private String userName;
@@ -40,13 +49,15 @@ public class LiveUserDetailExportVO {
     @Excel(name = "订单金额(元)")
     private String orderAmount;
 
+    /** 销售 */
+    @Excel(name = "邀请销售")
+    private String salesName;
+
     /** 分公司 */
-    @Excel(name = "分公司")
+    @Excel(name = "销售公司")
     private String companyName;
 
-    /** 销售 */
-    @Excel(name = "销售")
-    private String salesName;
+
 
     /** 是否完课 */
 //    @Excel(name = "是否完课")

+ 12 - 0
fs-service/src/main/java/com/fs/live/vo/LiveUserDetailVo.java

@@ -3,6 +3,7 @@ package com.fs.live.vo;
 import lombok.Data;
 
 import java.math.BigDecimal;
+import java.util.Date;
 
 /**
  * 直播间用户详情VO
@@ -35,6 +36,17 @@ public class LiveUserDetailVo {
 
     /** 分公司的销售是谁 */
     private String salesName;
+
+    // 签到时间
+    private Date signTime1;
+    private Date signTime2;
+    private Date signTime3;
+
+    private String signFirst;
+
+    private String signSecond;
+
+    private String signThird;
 }
 
 

+ 3 - 0
fs-service/src/main/resources/mapper/live/LiveAutoTaskMapper.xml

@@ -129,6 +129,9 @@
         </foreach>
         and status=1 and finish_status = 0 and abs_value>#{now} order by abs_value
     </select>
+    <select id="selectLastSignTaskByLiveId" resultType="com.fs.live.domain.LiveAutoTask">
+        <include refid="selectLiveAutoTaskVo"/>  where live_id=#{liveId} and task_type=7 order by create_time desc limit 1
+    </select>
     <insert id="batchInsertLiveAutoTask" parameterType="java.util.List">
         INSERT INTO live_auto_task (
         live_id,

+ 43 - 0
fs-service/src/main/resources/mapper/live/LiveDataMapper.xml

@@ -565,4 +565,47 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         GROUP BY u.user_id, u.nick_name, u.nickname, order_info.orderCount, order_info.orderAmount, c.company_name, cu.user_name
         ORDER BY order_info.orderAmount DESC, liveWatchDuration DESC
     </select>
+    <select id="selectLiveUserDetailListBySqlNew" resultType="com.fs.live.vo.LiveUserDetailVo">
+        SELECT
+            u.user_id AS userId,
+            COALESCE(MAX(u.nickname), MAX(u.nick_name), '未知用户') AS userName,
+            COALESCE(SUM(CASE WHEN lwu.live_flag = 1 AND lwu.replay_flag = 0 THEN lwu.online_seconds ELSE 0 END), 0) AS liveWatchDuration,
+            COALESCE(SUM(CASE WHEN lwu.live_flag = 0 AND lwu.replay_flag = 1 THEN lwu.online_seconds ELSE 0 END), 0) AS playbackWatchDuration,
+            COALESCE(MAX(order_info.orderCount), 0) AS orderCount,
+            COALESCE(MAX(order_info.orderAmount), 0) AS orderAmount,
+            COALESCE(MAX(c.company_name), '') AS companyName,
+            COALESCE(MAX(cu.user_name), '') AS salesName,
+            MAX(CASE WHEN lsr.sign_no = '1' THEN lsr.create_time END) AS signTime1,
+            MAX(CASE WHEN lsr.sign_no = '2' THEN lsr.create_time END) AS signTime2,
+            MAX(CASE WHEN lsr.sign_no = '3' THEN lsr.create_time END) AS signTime3
+        FROM live_watch_user lwu
+                 LEFT JOIN fs_user u ON lwu.user_id = u.user_id
+                 LEFT JOIN (
+            SELECT
+                CAST(user_id AS UNSIGNED) AS user_id,
+                COUNT(DISTINCT order_id) AS orderCount,
+                SUM(CASE WHEN is_pay = '1' THEN pay_price ELSE 0 END) AS orderAmount
+            FROM live_order
+            WHERE live_id = #{liveId}
+              AND user_id IS NOT NULL
+              AND user_id != ''
+            GROUP BY user_id
+        ) order_info ON lwu.user_id = order_info.user_id
+                 LEFT JOIN fs_user_company_user fucu ON lwu.user_id = fucu.user_id
+            AND fucu.status = 1
+            AND fucu.create_time = (
+                SELECT MIN(fucu_min.create_time)
+                FROM fs_user_company_user fucu_min
+                WHERE fucu_min.user_id = fucu.user_id
+                  AND fucu_min.status = 1
+            )
+                 LEFT JOIN company c ON fucu.company_id = c.company_id
+                 LEFT JOIN company_user cu ON fucu.company_user_id = cu.user_id
+                 LEFT JOIN live_sign_record lsr ON lwu.live_id = lsr.live_id
+            AND lwu.user_id = lsr.user_id
+            AND lsr.sign_no IN ('1', '2', '3')
+        WHERE lwu.live_id = #{liveId}
+        GROUP BY u.user_id
+        ORDER BY orderAmount DESC, liveWatchDuration DESC
+    </select>
 </mapper>