|
@@ -1,5 +1,7 @@
|
|
|
package com.yonge.cooleshow.biz.dal.service.impl;
|
|
|
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
|
|
|
import com.yonge.cooleshow.auth.api.entity.SysUser;
|
|
@@ -9,12 +11,21 @@ import com.yonge.cooleshow.biz.dal.constant.SysConfigConstant;
|
|
|
import com.yonge.cooleshow.biz.dal.dao.CourseGroupDao;
|
|
|
import com.yonge.cooleshow.biz.dal.dto.CheckLiveCourseTimeDto;
|
|
|
import com.yonge.cooleshow.biz.dal.dto.LiveCourseGroupDto;
|
|
|
+import com.yonge.cooleshow.biz.dal.dto.LiveCourseGroupDto.CoursePlanDto;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.CourseGroup;
|
|
|
+import com.yonge.cooleshow.biz.dal.entity.CoursePlan;
|
|
|
+import com.yonge.cooleshow.biz.dal.entity.CourseSchedule;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.CourseTimeEntity;
|
|
|
+import com.yonge.cooleshow.biz.dal.enums.CourseGroupEnum;
|
|
|
+import com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum;
|
|
|
import com.yonge.cooleshow.biz.dal.service.CourseGroupService;
|
|
|
+import com.yonge.cooleshow.biz.dal.service.CoursePlanService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.CourseScheduleService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.SysConfigService;
|
|
|
+import com.yonge.cooleshow.biz.dal.support.PageUtil;
|
|
|
+import com.yonge.cooleshow.biz.dal.vo.TeacherCourseGroupVo;
|
|
|
import com.yonge.cooleshow.common.exception.BizException;
|
|
|
+import com.yonge.cooleshow.common.page.PageInfo;
|
|
|
import com.yonge.toolset.utils.date.DateUtil;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
import org.redisson.api.RMap;
|
|
@@ -25,14 +36,12 @@ 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.*;
|
|
|
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.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
@@ -53,6 +62,8 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
|
|
|
@Autowired
|
|
|
private CourseScheduleService courseScheduleService;
|
|
|
@Autowired
|
|
|
+ private CoursePlanService coursePlanService;
|
|
|
+ @Autowired
|
|
|
private SysConfigService sysConfigService;
|
|
|
|
|
|
@Override
|
|
@@ -61,18 +72,104 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 查询课程组详情-直播课详情
|
|
|
+ *
|
|
|
+ * @param groupId
|
|
|
+ */
|
|
|
+ public void queryLiveCourseInfo(Long groupId) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分页查询课程组列表
|
|
|
+ *
|
|
|
+ * @param param 传入参数
|
|
|
+ * <p> - teacherId 老师id
|
|
|
+ * <p> - groupStatus 课程组状态 ING(进行中) NOT_SALE(未开售,未上架) APPLY(报名中,销售中) COMPLETE(已完成)
|
|
|
+ * <p> - row 条数
|
|
|
+ * <p> - page 页数
|
|
|
+ */
|
|
|
+ public PageInfo<TeacherCourseGroupVo> queryPageLiveCourseGroup(Map<String, Object> param) {
|
|
|
+ //查询该月的所有课程
|
|
|
+ param.put("teacherId", param.get("teacherId"));
|
|
|
+ param.put("groupStatus", param.get("groupStatus"));
|
|
|
+ param.put("type", CourseScheduleEnum.LIVE.getCode());
|
|
|
+ Page<TeacherCourseGroupVo> pageInfo = PageUtil.getPageInfo(param);
|
|
|
+ pageInfo.setAsc("a.start_time_");
|
|
|
+ IPage<TeacherCourseGroupVo> page = baseMapper.queryTeacherCourseGroup(pageInfo, param);
|
|
|
+ return PageUtil.pageInfo(page);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 新增课程组
|
|
|
*
|
|
|
- * @param dto
|
|
|
+ * @param dto 创建直播课课程组参数
|
|
|
*/
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
- public void add(LiveCourseGroupDto dto) {
|
|
|
- //1.查询该老师没有用缓存的课时
|
|
|
+ @Override
|
|
|
+ public void addLiveCourse(LiveCourseGroupDto dto) {
|
|
|
+ //批量检查老师课时在数据库是否重复
|
|
|
+ batchCheckTeacherCourseTime(dto.getTeacherId(), dto.getCoursePlanList(), CoursePlanDto::getStartTime, CoursePlanDto::getEndTime);
|
|
|
+ //获取锁定课时缓存,没有问题就刷新缓存
|
|
|
+ RMap<Long, List<CourseTimeEntity>> cacheTime = getExpireLockTimeCache(dto.getTeacherId());
|
|
|
+ List<CourseTimeEntity> timeEntities = new ArrayList<>();
|
|
|
+ dto.getCoursePlanList().forEach(o -> {
|
|
|
+ CourseTimeEntity time = new CourseTimeEntity();
|
|
|
+ time.setStartTime(o.getStartTime());
|
|
|
+ time.setEndTime(o.getEndTime());
|
|
|
+ timeEntities.add(time);
|
|
|
+ });
|
|
|
+ cacheTime.fastPut(dto.getTeacherId(), timeEntities);
|
|
|
+ Date now = new Date();
|
|
|
+ String live = CourseScheduleEnum.LIVE.getCode();
|
|
|
+ //写入课程组表
|
|
|
+ CourseGroup group = new CourseGroup();
|
|
|
+ group.setType(live);
|
|
|
+ group.setTeacherId(dto.getTeacherId());
|
|
|
+ group.setName(dto.getName());
|
|
|
+ group.setSubjectId(dto.getSubjectId());
|
|
|
+ group.setSingleCourseMinutes(dto.getSingleCourseMinutes());
|
|
|
+ group.setCourseNum(dto.getCourseNum());
|
|
|
+ group.setCourseIntroduce(dto.getCourseIntroduce());
|
|
|
+ group.setCoursePrice(dto.getCoursePrice());
|
|
|
+ group.setStatus(CourseGroupEnum.NOT_SALE.getCode());
|
|
|
+ group.setSalesStartDate(dto.getSalesStartDate());
|
|
|
+ group.setSalesEndDate(dto.getSalesEndDate());
|
|
|
+ group.setBackgroundPic(dto.getBackgroundPic());
|
|
|
+ group.setMixStudentNum(dto.getMixStudentNum());
|
|
|
+ group.setCreatedBy(dto.getTeacherId());
|
|
|
+ group.setCreatedTime(now);
|
|
|
+ this.save(group);
|
|
|
|
|
|
- //1.1 有缓存课时
|
|
|
+ //写入课程表及课程计划表
|
|
|
+ List<CourseSchedule> courseList = new ArrayList<>();
|
|
|
+ List<CoursePlan> planList = new ArrayList<>();
|
|
|
+ dto.getCoursePlanList().forEach(o -> {
|
|
|
+ CourseSchedule course = new CourseSchedule();
|
|
|
+ course.setCourseGroupId(group.getId());
|
|
|
+ course.setType(live);
|
|
|
+ course.setClassNum(o.getClassNum());
|
|
|
+ course.setTeacherId(dto.getTeacherId());
|
|
|
+ course.setClassDate(o.getStartTime());
|
|
|
+ course.setStartTime(o.getStartTime());
|
|
|
+ course.setEndTime(o.getEndTime());
|
|
|
+ course.setCreatedBy(dto.getTeacherId());
|
|
|
+ course.setCreatedTime(now);
|
|
|
+ course.setStatus(CourseScheduleEnum.NOT_START.getCode());
|
|
|
+ courseList.add(course);
|
|
|
|
|
|
- //1.2 没有缓存课时
|
|
|
+ CoursePlan plan = new CoursePlan();
|
|
|
+ plan.setCourseGroupId(group.getId());
|
|
|
+ plan.setClassNum(o.getClassNum());
|
|
|
+ plan.setPlan(o.getPlan());
|
|
|
+ plan.setCreatedTime(now);
|
|
|
+ planList.add(plan);
|
|
|
+ });
|
|
|
+ courseScheduleService.getDao().insertBatch(courseList);
|
|
|
+ coursePlanService.getDao().insertBatch(planList);
|
|
|
|
|
|
+ //课程组完成删除缓存
|
|
|
+ cacheTime.delete();
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -86,61 +183,66 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
|
|
|
if (i == timeList.size() - 1) {
|
|
|
break;
|
|
|
}
|
|
|
- CourseTimeEntity o1 = timeList.get(i);
|
|
|
+ CourseTimeEntity o = 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());
|
|
|
+ boolean checkParamTime = courseScheduleService.checkCourseTime(newList, CourseTimeEntity::getStartTime, CourseTimeEntity::getEndTime, o.getStartTime(), o.getEndTime());
|
|
|
if (checkParamTime) {
|
|
|
- throw new BizException(DateUtil.dateToString(o1.getStartTime(), "yyyy年MM月dd号 HH点mm分") + "的课程时间重复!");
|
|
|
+ throw new BizException(DateUtil.dateToString(o.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);
|
|
|
+ //批量检查老师课时在数据库是否重复
|
|
|
+ batchCheckTeacherCourseTime(dto.getTeacherId(), timeList, CourseTimeEntity::getStartTime, CourseTimeEntity::getEndTime);
|
|
|
+ //获取老师锁课缓存并添加课时数据
|
|
|
+ RMap<Long, List<CourseTimeEntity>> map = getExpireLockTimeCache(dto.getTeacherId());
|
|
|
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);
|
|
|
+ List<CourseTimeEntity> allCourseTime = teacherAutoPlanningLiveCourseTime(dto.getTeacherId(), dto.getCourseNum(), timeList);
|
|
|
allCourseTime.sort(Comparator.comparing(CourseTimeEntity::getStartTime));
|
|
|
//替换掉原有的课时
|
|
|
dto.setTimeList(allCourseTime);
|
|
|
//将自动排课后的课时写入缓存覆盖原有的
|
|
|
- map.fastPut(dto.getTeacherId(), allCourseTime);
|
|
|
+ map.fastPut(dto.getTeacherId(), dto.getTimeList());
|
|
|
}
|
|
|
return dto.getTimeList();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 批量检查老师课时在数据库是否重复
|
|
|
+ *
|
|
|
+ * @param teacherId 老师id
|
|
|
+ * @param timeList 时间集合
|
|
|
+ */
|
|
|
+ private <T> void batchCheckTeacherCourseTime(Long teacherId, List<T> timeList, Function<T, Date> startTimeFun, Function<T, Date> endTimeFun) {
|
|
|
+ //再校验数据库中课程时间和传入时间是否有交集
|
|
|
+ timeList.forEach(o -> {
|
|
|
+ boolean checkDataTime = courseScheduleService.checkTeacherCourseTime(teacherId, startTimeFun.apply(o), endTimeFun.apply(o));
|
|
|
+ if (checkDataTime) {
|
|
|
+ throw new BizException("预计安排在" + DateUtil.dateToString(startTimeFun.apply(o), "yyyy年MM月dd号 HH点mm分") + "的课程已被学员选择!");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 老师创建直播课自动排课
|
|
|
* <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) {
|
|
|
+ private List<CourseTimeEntity> teacherAutoPlanningLiveCourseTime(Long teacherId, int totalCourseNum, List<CourseTimeEntity> paramTimeList) {
|
|
|
+ //获取当前课程
|
|
|
+ int nowCourseNum = paramTimeList.size();
|
|
|
//获取总课程数量 - 获取当前选择的课程数量 = 要自动排课的课程数量
|
|
|
int diffCourse = totalCourseNum - nowCourseNum;
|
|
|
//获取课程时间,并按开始时间排序
|
|
|
- List<CourseTimeEntity> sortCourseTime = paramTimeList.stream()
|
|
|
+ List<CourseTimeEntity> resultCourseTime = paramTimeList.stream()
|
|
|
.sorted(Comparator.comparing(CourseTimeEntity::getStartTime))
|
|
|
.collect(Collectors.toList());
|
|
|
//获取最大排课周
|
|
@@ -163,7 +265,7 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
|
|
|
//进入新的循环周数+1
|
|
|
week.getAndIncrement();
|
|
|
}
|
|
|
- CourseTimeEntity timeDto = sortCourseTime.get(index);
|
|
|
+ CourseTimeEntity timeDto = resultCourseTime.get(index);
|
|
|
if (week.get() > maxWeek) {
|
|
|
throw new BizException("系统自动排课时发现当前时间往后" + maxWeek + "周的课程时间已排满,请手动排课!");
|
|
|
}
|
|
@@ -184,7 +286,7 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
|
|
|
boolean checkTime;
|
|
|
|
|
|
//若:传入时间是1号10点和8号10点,然后1号10点自动生成的课时是8号10点那么就和传入的8号10点冲突了,这种情况需要继续往后延续1周
|
|
|
- checkTime = courseScheduleService.checkCourseTime(sortCourseTime, CourseTimeEntity::getStartTime, CourseTimeEntity::getEndTime, autoStartDate, autoEndDate);
|
|
|
+ checkTime = courseScheduleService.checkCourseTime(resultCourseTime, CourseTimeEntity::getStartTime, CourseTimeEntity::getEndTime, autoStartDate, autoEndDate);
|
|
|
con.accept(checkTime);
|
|
|
//如果和传入时间冲突则跳过
|
|
|
if (flag.get()) {
|
|
@@ -203,11 +305,41 @@ public class CourseGroupServiceImpl extends ServiceImpl<CourseGroupDao, CourseGr
|
|
|
CourseTimeEntity autoTimeDto = new CourseTimeEntity();
|
|
|
autoTimeDto.setStartTime(autoStartDate);
|
|
|
autoTimeDto.setEndTime(autoEndDate);
|
|
|
- sortCourseTime.add(autoTimeDto);
|
|
|
+ resultCourseTime.add(autoTimeDto);
|
|
|
}
|
|
|
index++;
|
|
|
}
|
|
|
- return sortCourseTime;
|
|
|
+ return resultCourseTime;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建直播课程组-解除锁定课程时间-删除写到缓存当作锁定的课时
|
|
|
+ *
|
|
|
+ * @param teacherId 老师id
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void unlockCourseToCache(Long teacherId) {
|
|
|
+ Optional.ofNullable(teacherId)
|
|
|
+ .ifPresent(id -> getLockTimeCache(id).delete());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取老师锁定课时数据的缓存
|
|
|
+ *
|
|
|
+ * @param teacherId 老师id
|
|
|
+ * @return 缓存
|
|
|
+ */
|
|
|
+ private RMap<Long, List<CourseTimeEntity>> getExpireLockTimeCache(Long teacherId) {
|
|
|
+ String lockMinuteStr = sysConfigService.findConfigValue(SysConfigConstant.CREATE_LIVE_TIME_LOCK_MINUTE);
|
|
|
+ long lockMinute = StringUtils.isBlank(lockMinuteStr) ? 15L : Long.parseLong(lockMinuteStr);
|
|
|
+ RMap<Long, List<CourseTimeEntity>> cache = getLockTimeCache(teacherId);
|
|
|
+ cache.expire(lockMinute, TimeUnit.MINUTES);
|
|
|
+ return cache;
|
|
|
+ }
|
|
|
+
|
|
|
+ private RMap<Long, List<CourseTimeEntity>> getLockTimeCache(Long teacherId) {
|
|
|
+ String key = String.join(":", LiveRoomConstant.COOLESHOW, CourseConstant.LOCK_COURSE_TIME_INFO, teacherId.toString());
|
|
|
+ return redissonClient.getMap(key);
|
|
|
}
|
|
|
|
|
|
private SysUser getSysUser(Long userId) {
|