From e429c291995f3f20184079e480031533ae5c03e6 Mon Sep 17 00:00:00 2001
From: zjk <852185829@qq.com>
Date: 星期五, 18 九月 2026 17:24:28 +0800
Subject: [PATCH] refactor(全项目): 综合优化全端业务与修复各类问题

---
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/LiveSessionStatusSyncService.java |   65 +++++++++++++++++++++++++++++++-
 1 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/LiveSessionStatusSyncService.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/LiveSessionStatusSyncService.java
index 67a38ee..86e8ea7 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/LiveSessionStatusSyncService.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/LiveSessionStatusSyncService.java
@@ -10,8 +10,10 @@
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 @Service
@@ -46,7 +48,8 @@
                 .orderByAsc(LiveSession::getId));
         int startedCount = 0;
         if (dueSessions != null && !dueSessions.isEmpty()) {
-            for (LiveSession dueSession : dueSessions) {
+            List<LiveSession> effectiveDueSessions = pickEffectiveDueSessions(dueSessions);
+            for (LiveSession dueSession : effectiveDueSessions) {
                 // 定时任务与人工开播共用同一套状态迁移逻辑,避免状态口径分叉。
                 LiveSessionStatusVO statusVO = liveSessionAppService.autoStart(dueSession.getId(), now);
                 if (statusVO == null) {
@@ -58,7 +61,8 @@
             }
 
             if (startedCount > 0) {
-                log.info("live session auto start finished, scanned={}, started={}", dueSessions.size(), startedCount);
+                log.info("live session auto start finished, scanned={}, effective={}, started={}",
+                        dueSessions.size(), effectiveDueSessions.size(), startedCount);
             }
         }
 
@@ -66,6 +70,63 @@
     }
 
     /**
+     * 同一课程只挑一条最应被自动开播的场次,避免历史过期开播记录被批量拉起后又互相收敛。
+     */
+    private List<LiveSession> pickEffectiveDueSessions(List<LiveSession> dueSessions) {
+        if (dueSessions == null || dueSessions.isEmpty()) {
+            return dueSessions;
+        }
+        Map<Long, LiveSession> effectiveSessionMap = new LinkedHashMap<Long, LiveSession>();
+        for (LiveSession dueSession : dueSessions) {
+            if (dueSession == null || dueSession.getLiveCourseId() == null) {
+                continue;
+            }
+            LiveSession current = effectiveSessionMap.get(dueSession.getLiveCourseId());
+            if (current == null || compareDueSession(current, dueSession) < 0) {
+                effectiveSessionMap.put(dueSession.getLiveCourseId(), dueSession);
+            }
+        }
+        return new java.util.ArrayList<LiveSession>(effectiveSessionMap.values());
+    }
+
+    /**
+     * 自动开播候选按计划开播时间排序,时间更晚者优先;同时间取 ID 更大的最新记录。
+     */
+    private int compareDueSession(LiveSession left, LiveSession right) {
+        LocalDateTime leftTime = left == null ? null : left.getStartTime();
+        LocalDateTime rightTime = right == null ? null : right.getStartTime();
+        if (leftTime == null && rightTime == null) {
+            return compareSessionId(left, right);
+        }
+        if (leftTime == null) {
+            return -1;
+        }
+        if (rightTime == null) {
+            return 1;
+        }
+        int timeCompare = leftTime.compareTo(rightTime);
+        if (timeCompare != 0) {
+            return timeCompare;
+        }
+        return compareSessionId(left, right);
+    }
+
+    private int compareSessionId(LiveSession left, LiveSession right) {
+        Long leftId = left == null ? null : left.getId();
+        Long rightId = right == null ? null : right.getId();
+        if (leftId == null && rightId == null) {
+            return 0;
+        }
+        if (leftId == null) {
+            return -1;
+        }
+        if (rightId == null) {
+            return 1;
+        }
+        return leftId.compareTo(rightId);
+    }
+
+    /**
      * 定时收敛历史残留的直播中场次,避免同课程出现多条或过期直播中状态。
      */
     private void reconcileLivingCourses(LocalDateTime now) {

--
Gitblit v1.7.1