|
@@ -1,17 +1,39 @@
|
|
|
package com.yonge.cooleshow.biz.dal.service.impl;
|
|
|
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
|
|
|
+import com.yonge.cooleshow.auth.api.entity.SysUser;
|
|
|
+import com.yonge.cooleshow.biz.dal.constant.CourseConstant;
|
|
|
+import com.yonge.cooleshow.biz.dal.constant.LiveRoomConstant;
|
|
|
import com.yonge.cooleshow.biz.dal.dao.CourseGroupDao;
|
|
|
-import com.yonge.cooleshow.biz.dal.dto.CourseGroupDto;
|
|
|
+import com.yonge.cooleshow.biz.dal.dto.CheckLiveCourseTimeDto;
|
|
|
+import com.yonge.cooleshow.biz.dal.dto.LiveCourseGroupDto;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.CourseGroup;
|
|
|
+import com.yonge.cooleshow.biz.dal.entity.CourseTimeEntity;
|
|
|
import com.yonge.cooleshow.biz.dal.service.CourseGroupService;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.stereotype.Service;
|
|
|
-
|
|
|
+import com.yonge.cooleshow.biz.dal.service.CourseScheduleService;
|
|
|
+import com.yonge.cooleshow.biz.dal.service.SysConfigService;
|
|
|
+import com.yonge.cooleshow.common.exception.BizException;
|
|
|
+import com.yonge.toolset.utils.date.DateUtil;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.redisson.api.RMap;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
+import java.util.Comparator;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Optional;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
+import java.util.function.Consumer;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
/**
|
|
|
* 课程组表(CourseGroup)表服务实现类
|
|
|
*
|
|
@@ -23,6 +45,15 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
|
|
|
|
|
|
private final static Logger log = LoggerFactory.getLogger(CourseGroupServiceImpl.class);
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private SysUserFeignService sysUserFeignService;
|
|
|
+ @Autowired
|
|
|
+ private RedissonClient redissonClient;
|
|
|
+ @Autowired
|
|
|
+ private CourseScheduleService courseScheduleService;
|
|
|
+ @Autowired
|
|
|
+ private SysConfigService sysConfigService;
|
|
|
+
|
|
|
@Override
|
|
|
public CourseGroupDao getDao() {
|
|
|
return this.baseMapper;
|
|
@@ -30,15 +61,162 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
|
|
|
|
|
|
/**
|
|
|
* 新增课程组
|
|
|
+ *
|
|
|
* @param dto
|
|
|
*/
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
- @Override
|
|
|
- public void add(CourseGroupDto dto){
|
|
|
+ public void add(LiveCourseGroupDto dto) {
|
|
|
+ //1.查询该老师没有用缓存的课时
|
|
|
+
|
|
|
+ //1.1 有缓存课时
|
|
|
+
|
|
|
+ //1.2 没有缓存课时
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建直播课程组时将课时写到缓存当作锁定的时间
|
|
|
+ */
|
|
|
+ public List<CourseTimeEntity> lockCourseToCache(CheckLiveCourseTimeDto dto) {
|
|
|
+ //先自校验传入时间是否交集
|
|
|
+ List<CourseTimeEntity> timeList = dto.getTimeList();
|
|
|
+ if (timeList.size() > 1) {
|
|
|
+ for (int i = 0; i < timeList.size(); i++) {
|
|
|
+ if (i == timeList.size() - 1) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ CourseTimeEntity o1 = timeList.get(i);
|
|
|
+ List<CourseTimeEntity> newList = timeList.subList(i + 1, timeList.size());
|
|
|
+ boolean checkParamTime = courseScheduleService.checkCourseTime(newList, CourseTimeEntity::getStartTime, CourseTimeEntity::getEndTime, o1.getStartTime(), o1.getEndTime());
|
|
|
+ if (checkParamTime) {
|
|
|
+ throw new BizException(DateUtil.dateToString(o1.getStartTime(), "yyyy年MM月dd号 HH点mm分") + "的课程时间重复!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ //再校验数据库中课程时间和传入时间是否有交集
|
|
|
+ timeList.forEach(o -> {
|
|
|
+ boolean checkDataTime = courseScheduleService.checkTeacherCourseTime(dto.getTeacherId(), o.getStartTime(), o.getEndTime());
|
|
|
+ if (checkDataTime) {
|
|
|
+ throw new BizException("预计安排在" + DateUtil.dateToString(o.getStartTime(), "yyyy年MM月dd号 HH点mm分") + "的课程已被学员选择!");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ //先将当前验证通过课程时间锁住
|
|
|
+ String key = String.join(":", LiveRoomConstant.COOLESHOW, CourseConstant.LOCK_COURSE_TIME_INFO, dto.getTeacherId().toString());
|
|
|
+ RMap<Long, List<CourseTimeEntity>> map = redissonClient.getMap(key);
|
|
|
+ map.expire(1L, TimeUnit.DAYS);
|
|
|
+ map.fastPut(dto.getTeacherId(), timeList);
|
|
|
+
|
|
|
+ //需要自动补全课时
|
|
|
+ if (dto.getLoop() == 1) {
|
|
|
+ //获取总课程数量
|
|
|
+ Integer totalCourseNum = dto.getCourseNum();
|
|
|
+ //获取当前课程
|
|
|
+ int nowCourseNum = timeList.size();
|
|
|
+ //自动排课,获取排课后所有的课程时间
|
|
|
+ List<CourseTimeEntity> allCourseTime = teacherAutoPlanningLiveCourseTime(dto.getTeacherId(), totalCourseNum, nowCourseNum, timeList);
|
|
|
+ //替换掉原有的课时
|
|
|
+ dto.setTimeList(allCourseTime);
|
|
|
+ //将自动排课后的课时写入缓存覆盖原有的
|
|
|
+ map.fastPut(dto.getTeacherId(), allCourseTime);
|
|
|
+ }
|
|
|
+ return dto.getTimeList();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 老师创建直播课自动排课
|
|
|
+ * <p>自动排课规则及场景:总5节课,填入2节,需要自动补3节
|
|
|
+ * <p>1.把前面2节课的时间循环+1周直到填满5节课为止
|
|
|
+ * <p>2.如果自动排课时的时间和未来课程时间有冲突则继续往后面延续一周
|
|
|
+ *
|
|
|
+ * @param totalCourseNum 总课程数量
|
|
|
+ * @param nowCourseNum 当前选择的课程数量
|
|
|
+ * @param paramTimeList 当前课程的时间段
|
|
|
+ * @return 自动排课后的全部课时
|
|
|
+ */
|
|
|
+ private List<CourseTimeEntity> teacherAutoPlanningLiveCourseTime(Long teacherId, int totalCourseNum, int nowCourseNum, List<CourseTimeEntity> paramTimeList) {
|
|
|
+ //获取总课程数量 - 获取当前选择的课程数量 = 要自动排课的课程数量
|
|
|
+ int diffCourse = totalCourseNum - nowCourseNum;
|
|
|
+ //获取课程时间,并按开始时间排序
|
|
|
+ List<CourseTimeEntity> sortCourseTime = paramTimeList.stream()
|
|
|
+ .sorted(Comparator.comparing(CourseTimeEntity::getStartTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ //获取最大排课周
|
|
|
+ String maxWeekStr = sysConfigService.findConfigValue("auto_planning_course_max_week");
|
|
|
+ int maxWeek = 26;//默认 26周
|
|
|
+ if (StringUtils.isBlank(maxWeekStr)) {
|
|
|
+ maxWeek = Integer.parseInt(maxWeekStr);
|
|
|
+ }
|
|
|
+ int index = 0;
|
|
|
+ //自动补全课时
|
|
|
+ for (int i = 0; i < diffCourse; i++) {
|
|
|
+ //需要增加的周数
|
|
|
+ AtomicInteger week = new AtomicInteger(1);
|
|
|
+ //是否要一直生成课程 true 一直增加周数并生成到不冲突的时间为止
|
|
|
+ AtomicBoolean flag = new AtomicBoolean(true);
|
|
|
+ //生成课程
|
|
|
+ while (flag.get()) {
|
|
|
+ if (index == nowCourseNum) {
|
|
|
+ index = 0;
|
|
|
+ //进入新的循环周数+1
|
|
|
+ week.getAndIncrement();
|
|
|
+ }
|
|
|
+ CourseTimeEntity timeDto = sortCourseTime.get(index);
|
|
|
+ if (week.get() > maxWeek) {
|
|
|
+ throw new BizException("系统自动排课时发现当前时间往后" + maxWeek + "周的课程时间已排满,请手动排课!");
|
|
|
+ }
|
|
|
+ Date autoStartDate = DateUtil.addWeeks(timeDto.getStartTime(), week.get());
|
|
|
+ Date autoEndDate = DateUtil.addWeeks(timeDto.getEndTime(), week.get());
|
|
|
+
|
|
|
+ //true flag = true 并且 周数+1
|
|
|
+ Consumer<Boolean> con = (check) -> {
|
|
|
+ //check = true ,有交集延续1周后继续生成时间
|
|
|
+ if (check) {
|
|
|
+ week.getAndIncrement();
|
|
|
+ flag.set(true);
|
|
|
+ } else {
|
|
|
+ flag.set(false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ boolean checkTime;
|
|
|
|
|
|
+ //若:传入时间是1号10点和8号10点,然后1号10点自动生成的课时是8号10点那么就和传入的8号10点冲突了,这种情况需要继续往后延续1周
|
|
|
+ checkTime = courseScheduleService.checkCourseTime(sortCourseTime, CourseTimeEntity::getStartTime, CourseTimeEntity::getEndTime, autoStartDate, autoEndDate);
|
|
|
+ con.accept(checkTime);
|
|
|
+ //如果和传入时间冲突则跳过
|
|
|
+ if (flag.get()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
+ //校验当前生成时间是否和未来的课程时间是否交集
|
|
|
+ checkTime = courseScheduleService.checkTeacherCourseTime(teacherId, autoStartDate, autoEndDate);
|
|
|
+ con.accept(checkTime);
|
|
|
+ //如果和未来时间冲突则跳过
|
|
|
+ if (flag.get()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ //将自动生成时间收入集合
|
|
|
+ CourseTimeEntity autoTimeDto = new CourseTimeEntity();
|
|
|
+ autoTimeDto.setStartTime(autoStartDate);
|
|
|
+ autoTimeDto.setEndTime(autoEndDate);
|
|
|
+ sortCourseTime.add(autoTimeDto);
|
|
|
+ }
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+ return sortCourseTime;
|
|
|
+ }
|
|
|
+
|
|
|
+ private SysUser getSysUser(Long userId) {
|
|
|
+ return Optional.ofNullable(userId)
|
|
|
+ .map(sysUserFeignService::queryUserById)
|
|
|
+ .orElseThrow(() -> new BizException("用户不存在"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private SysUser getSysUser() {
|
|
|
+ return Optional.ofNullable(sysUserFeignService.queryUserInfo())
|
|
|
+ .orElseThrow(() -> new BizException("用户不存在"));
|
|
|
+ }
|
|
|
}
|
|
|
|