package com.tcm.training.admin.app.home.service; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.tcm.training.admin.app.live.support.AppLiveCourseDisplaySupport; import com.tcm.training.admin.app.home.vo.AppHomeLiveCourseVO; import com.tcm.training.admin.live.entity.LiveCourse; import com.tcm.training.admin.live.entity.LiveSession; import com.tcm.training.admin.live.mapper.LiveCourseMapper; import com.tcm.training.admin.live.mapper.LiveSessionMapper; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; /** * APP 首页养生直播聚合服务。 */ @Service public class AppHomeLiveCourseService { private static final int COURSE_STATUS_ENABLED = 1; private static final long NEXT_START_DELAY_MINUTES = 10L; private static final int HOME_CARD_LIMIT = 2; private static final DateTimeFormatter START_TIME_FORMATTER = DateTimeFormatter.ofPattern("MM月dd日 HH:mm 开播"); private final LiveCourseMapper liveCourseMapper; private final LiveSessionMapper liveSessionMapper; private final AppLiveCourseDisplaySupport appLiveCourseDisplaySupport; /** * 注入首页直播所需的课程与场次查询能力。 */ public AppHomeLiveCourseService(LiveCourseMapper liveCourseMapper, LiveSessionMapper liveSessionMapper, AppLiveCourseDisplaySupport appLiveCourseDisplaySupport) { this.liveCourseMapper = liveCourseMapper; this.liveSessionMapper = liveSessionMapper; this.appLiveCourseDisplaySupport = appLiveCourseDisplaySupport; } /** * 查询 APP 首页展示的养生直播卡片。 */ public List listHomeLiveCourses() { List courses = liveCourseMapper.selectList(new LambdaQueryWrapper() .eq(LiveCourse::getDeleted, 0) .eq(LiveCourse::getStatus, COURSE_STATUS_ENABLED) .orderByDesc(LiveCourse::getId)); if (courses == null || courses.isEmpty()) { return Collections.emptyList(); } Map> sessionMap = loadSessionMap(courses); LocalDateTime now = LocalDateTime.now(); List cards = new ArrayList(courses.size()); for (LiveCourse course : courses) { cards.add(buildHomeCard(course, sessionMap.get(course.getId()), now)); } cards.sort(new Comparator() { @Override public int compare(HomeLiveCourseCard left, HomeLiveCourseCard right) { return compareCards(left, right); } }); List result = new ArrayList(Math.min(cards.size(), HOME_CARD_LIMIT)); for (int i = 0; i < cards.size() && i < HOME_CARD_LIMIT; i++) { result.add(cards.get(i).getCard()); } return result; } /** * 批量加载首页直播课程的全部场次。 */ private Map> loadSessionMap(List courses) { List courseIds = new ArrayList(courses.size()); for (LiveCourse course : courses) { courseIds.add(course.getId()); } List sessions = liveSessionMapper.selectList(new LambdaQueryWrapper() .in(LiveSession::getLiveCourseId, courseIds) .eq(LiveSession::getDeleted, 0) .orderByAsc(LiveSession::getStartTime) .orderByAsc(LiveSession::getId)); return appLiveCourseDisplaySupport.groupSessionsByCourseId(sessions); } /** * 根据课程与场次快照构造首页直播卡片。 */ private HomeLiveCourseCard buildHomeCard(LiveCourse course, List sessions, LocalDateTime now) { HomeLiveCourseCard homeCard = new HomeLiveCourseCard(); AppHomeLiveCourseVO card = new AppHomeLiveCourseVO(); String coverImage = appLiveCourseDisplaySupport.trimToNull(course.getCoverImg()); String liveImage = appLiveCourseDisplaySupport.resolveLiveImage(course); card.setCourseId(course.getId()); card.setTitle(appLiveCourseDisplaySupport.trimToNull(course.getTitle())); card.setCoverImage(coverImage); card.setLiveImage(liveImage); card.setHasPassword(StrUtil.isNotBlank(course.getPassword())); homeCard.setCard(card); AppLiveCourseDisplaySupport.CourseDisplaySnapshot snapshot = appLiveCourseDisplaySupport.resolveDisplay(sessions, now, NEXT_START_DELAY_MINUTES); LiveSession currentSession = snapshot.getCurrentSession(); if (currentSession != null) { card.setDisplayStatus(AppLiveCourseDisplaySupport.DISPLAY_STATUS_LIVING); card.setDisplayStatusText("直播中"); card.setDisplayImage(appLiveCourseDisplaySupport.resolveLivingDisplayImage(coverImage, liveImage)); card.setCurrentSessionId(currentSession.getId()); card.setVideoUrl(appLiveCourseDisplaySupport.trimToNull(currentSession.getVideoUrl())); homeCard.setStatusRank(0); return homeCard; } homeCard.setLatestEndedAt(snapshot.getLatestEndedAt()); if (snapshot.isEndedCooldown()) { card.setDisplayStatus(AppLiveCourseDisplaySupport.DISPLAY_STATUS_ENDED); card.setDisplayStatusText("已结束"); card.setDisplayImage(appLiveCourseDisplaySupport.resolveStaticDisplayImage(coverImage, liveImage)); homeCard.setStatusRank(2); return homeCard; } LiveSession nextSession = snapshot.getNextSession(); if (nextSession != null) { card.setDisplayStatus(AppLiveCourseDisplaySupport.DISPLAY_STATUS_NOT_STARTED); card.setNextStartTime(nextSession.getStartTime()); card.setDisplayStatusText(formatNextStartTime(nextSession.getStartTime())); card.setDisplayImage(appLiveCourseDisplaySupport.resolveStaticDisplayImage(coverImage, liveImage)); homeCard.setStatusRank(1); homeCard.setNextStartTime(nextSession.getStartTime()); return homeCard; } card.setDisplayStatus(AppLiveCourseDisplaySupport.DISPLAY_STATUS_ENDED); card.setDisplayStatusText("已结束"); card.setDisplayImage(appLiveCourseDisplaySupport.resolveStaticDisplayImage(coverImage, liveImage)); homeCard.setStatusRank(2); return homeCard; } /** * 将开播时间格式化为首页展示文案。 */ private String formatNextStartTime(LocalDateTime startTime) { if (startTime == null) { return "已结束"; } return START_TIME_FORMATTER.format(startTime); } /** * 对首页直播卡片执行统一排序。 */ private int compareCards(HomeLiveCourseCard left, HomeLiveCourseCard right) { int rankCompare = Integer.compare(left.getStatusRank(), right.getStatusRank()); if (rankCompare != 0) { return rankCompare; } if (left.getStatusRank() == 1) { int nextStartCompare = appLiveCourseDisplaySupport.compareSessionTime(left.getNextStartTime(), right.getNextStartTime()); if (nextStartCompare != 0) { return nextStartCompare; } } if (left.getStatusRank() == 2) { int endedCompare = appLiveCourseDisplaySupport.compareSessionTime(right.getLatestEndedAt(), left.getLatestEndedAt()); if (endedCompare != 0) { return endedCompare; } } return Long.compare(right.getCard().getCourseId(), left.getCard().getCourseId()); } /** * 首页直播卡片排序中间态。 */ private static class HomeLiveCourseCard { private AppHomeLiveCourseVO card; private int statusRank; private LocalDateTime nextStartTime; private LocalDateTime latestEndedAt; /** * 获取首页直播卡片响应。 */ public AppHomeLiveCourseVO getCard() { return card; } /** * 设置首页直播卡片响应。 */ public void setCard(AppHomeLiveCourseVO card) { this.card = card; } /** * 获取状态优先级。 */ public int getStatusRank() { return statusRank; } /** * 设置状态优先级。 */ public void setStatusRank(int statusRank) { this.statusRank = statusRank; } /** * 获取下一次开播时间。 */ public LocalDateTime getNextStartTime() { return nextStartTime; } /** * 设置下一次开播时间。 */ public void setNextStartTime(LocalDateTime nextStartTime) { this.nextStartTime = nextStartTime; } /** * 获取最近结束时间。 */ public LocalDateTime getLatestEndedAt() { return latestEndedAt; } /** * 设置最近结束时间。 */ public void setLatestEndedAt(LocalDateTime latestEndedAt) { this.latestEndedAt = latestEndedAt; } } }