|
@@ -36,6 +36,7 @@ import com.fs.course.config.CourseConfig;
|
|
|
import com.fs.course.config.RandomRedPacketConfig;
|
|
import com.fs.course.config.RandomRedPacketConfig;
|
|
|
import com.fs.course.config.RandomRedPacketRule;
|
|
import com.fs.course.config.RandomRedPacketRule;
|
|
|
import com.fs.course.domain.*;
|
|
import com.fs.course.domain.*;
|
|
|
|
|
+import com.fs.course.dto.CoursePeriodSyncResultDTO;
|
|
|
import com.fs.course.dto.CoursePackageDTO;
|
|
import com.fs.course.dto.CoursePackageDTO;
|
|
|
import com.fs.course.mapper.*;
|
|
import com.fs.course.mapper.*;
|
|
|
import com.fs.course.param.*;
|
|
import com.fs.course.param.*;
|
|
@@ -4357,5 +4358,120 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 同步会员营期
|
|
|
|
|
+ * 将课程的视频排序同步到绑定的营期中(更新lesson和dayDate)
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public CoursePeriodSyncResultDTO syncCoursePeriod(Long courseId) {
|
|
|
|
|
+ log.info("开始同步课程 {} 的会员营期", courseId);
|
|
|
|
|
+
|
|
|
|
|
+ CoursePeriodSyncResultDTO result = new CoursePeriodSyncResultDTO();
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 查询课程视频,按courseSort排序
|
|
|
|
|
+ FsUserCourseVideo queryVideo = new FsUserCourseVideo();
|
|
|
|
|
+ queryVideo.setCourseId(courseId);
|
|
|
|
|
+ List<FsUserCourseVideo> courseVideos = fsUserCourseVideoMapper.selectFsUserCourseVideoListByCourseId(queryVideo);
|
|
|
|
|
+
|
|
|
|
|
+ if (courseVideos == null || courseVideos.isEmpty()) {
|
|
|
|
|
+ log.warn("课程 {} 没有视频", courseId);
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 按courseSort排序
|
|
|
|
|
+ courseVideos.sort(Comparator.comparing(v -> v.getCourseSort() != null ? v.getCourseSort() : Long.MAX_VALUE));
|
|
|
|
|
+ log.info("课程 {} 共有 {} 个视频", courseId, courseVideos.size());
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 查询该课程绑定的营期
|
|
|
|
|
+ FsUserCoursePeriod queryPeriod = new FsUserCoursePeriod();
|
|
|
|
|
+ queryPeriod.setCourseId(courseId);
|
|
|
|
|
+ List<FsUserCoursePeriod> periods = fsUserCoursePeriodMapper.selectFsUserCoursePeriodList(queryPeriod);
|
|
|
|
|
+
|
|
|
|
|
+ if (periods == null || periods.isEmpty()) {
|
|
|
|
|
+ log.warn("课程 {} 没有绑定营期", courseId);
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 过滤已结束的营期
|
|
|
|
|
+ List<FsUserCoursePeriod> activePeriods = periods.stream()
|
|
|
|
|
+ .filter(p -> p.getPeriodStatus() != null && p.getPeriodStatus() != 3)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ if (activePeriods.isEmpty()) {
|
|
|
|
|
+ log.warn("课程 {} 的所有营期已结束", courseId);
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("课程 {} 有 {} 个未结束营期", courseId, activePeriods.size());
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 遍历营期进行同步
|
|
|
|
|
+ for (FsUserCoursePeriod period : activePeriods) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 查询营期中的课程
|
|
|
|
|
+ FsUserCoursePeriodDays queryDays = new FsUserCoursePeriodDays();
|
|
|
|
|
+ queryDays.setPeriodId(period.getPeriodId());
|
|
|
|
|
+ queryDays.setCourseId(courseId);
|
|
|
|
|
+ List<FsUserCoursePeriodDays> existingDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(queryDays);
|
|
|
|
|
+
|
|
|
|
|
+ if (existingDays.isEmpty()) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 构建 videoId -> day 的映射
|
|
|
|
|
+ Map<Long, FsUserCoursePeriodDays> videoToDayMap = existingDays.stream()
|
|
|
|
|
+ .collect(Collectors.toMap(FsUserCoursePeriodDays::getVideoId, d -> d, (a, b) -> a));
|
|
|
|
|
+
|
|
|
|
|
+ // 获取营期开始日期
|
|
|
|
|
+ LocalDate periodStartDate = period.getPeriodStartingTime();
|
|
|
|
|
+ if (periodStartDate == null) {
|
|
|
|
|
+ periodStartDate = LocalDate.now();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 更新lesson和dayDate
|
|
|
|
|
+ List<FsUserCoursePeriodDays> daysToUpdate = new ArrayList<>();
|
|
|
|
|
+ for (int i = 0; i < courseVideos.size(); i++) {
|
|
|
|
|
+ FsUserCourseVideo video = courseVideos.get(i);
|
|
|
|
|
+ if (videoToDayMap.containsKey(video.getVideoId())) {
|
|
|
|
|
+ FsUserCoursePeriodDays day = videoToDayMap.get(video.getVideoId());
|
|
|
|
|
+ int newLesson = i;
|
|
|
|
|
+ LocalDate newDayDate = periodStartDate.plusDays(newLesson);
|
|
|
|
|
+
|
|
|
|
|
+ // 判断是否需要更新
|
|
|
|
|
+ if (day.getLesson() == null || day.getLesson() != newLesson || !newDayDate.equals(day.getDayDate())) {
|
|
|
|
|
+ day.setLesson(newLesson);
|
|
|
|
|
+ day.setDayDate(newDayDate);
|
|
|
|
|
+
|
|
|
|
|
+ // 更新时间字段
|
|
|
|
|
+ if (day.getStartDateTime() != null) {
|
|
|
|
|
+ day.setStartDateTime(LocalDateTime.of(newDayDate, day.getStartDateTime().toLocalTime()));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (day.getEndDateTime() != null) {
|
|
|
|
|
+ day.setEndDateTime(LocalDateTime.of(newDayDate, day.getEndDateTime().toLocalTime()));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (day.getLastJoinTime() != null) {
|
|
|
|
|
+ day.setLastJoinTime(LocalDateTime.of(newDayDate, day.getLastJoinTime().toLocalTime()));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ daysToUpdate.add(day);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 批量更新
|
|
|
|
|
+ if (!daysToUpdate.isEmpty()) {
|
|
|
|
|
+ fsUserCoursePeriodDaysMapper.batchUpdateCoursePeriodDays(daysToUpdate);
|
|
|
|
|
+ result.addPeriodDetail(period.getPeriodId(), period.getPeriodName(), daysToUpdate.size());
|
|
|
|
|
+ log.info("营期 {} ({}) 同步完成,更新 {} 条", period.getPeriodId(), period.getPeriodName(), daysToUpdate.size());
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("同步营期 {} 失败", period.getPeriodId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("课程 {} 同步完成,共更新 {} 条记录", courseId, result.getTotalUpdated());
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|