|
|
|
@ -4,7 +4,9 @@ import cn.hutool.core.bean.BeanUtil;
|
|
|
|
|
import cn.hutool.core.collection.CollectionUtil;
|
|
|
|
|
import cn.hutool.core.date.*;
|
|
|
|
|
import cn.hutool.core.lang.Assert;
|
|
|
|
|
import cn.hutool.core.lang.func.Consumer3;
|
|
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
|
import cn.hutool.json.JSONUtil;
|
|
|
|
|
import cn.jlw.util.ToolUtils;
|
|
|
|
|
import cn.jlw.validate.ValidateConfig;
|
|
|
|
@ -24,6 +26,7 @@ import com.ibeetl.jlw.dao.*;
|
|
|
|
|
import com.ibeetl.jlw.entity.*;
|
|
|
|
|
import com.ibeetl.jlw.web.query.TeacherOpenCourseScheduleSessionClassQuery;
|
|
|
|
|
import com.ibeetl.jlw.web.query.TeacherOpenCourseScheduleSessionQuery;
|
|
|
|
|
import com.ibeetl.jlw.web.query.TeacherOpenCourseScheduleSessionSnapQuery;
|
|
|
|
|
import lombok.Builder;
|
|
|
|
|
import lombok.Data;
|
|
|
|
|
import lombok.Getter;
|
|
|
|
@ -42,13 +45,14 @@ import org.springframework.validation.annotation.Validated;
|
|
|
|
|
import javax.validation.constraints.NotEmpty;
|
|
|
|
|
import javax.validation.constraints.NotNull;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.function.Consumer;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import static cn.hutool.core.collection.CollUtil.join;
|
|
|
|
|
import static cn.hutool.core.date.DateField.HOUR_OF_DAY;
|
|
|
|
|
import static cn.hutool.core.date.DateField.MINUTE;
|
|
|
|
|
import static cn.hutool.core.date.DatePattern.NORM_DATE_PATTERN;
|
|
|
|
|
import static cn.hutool.core.date.DateUtil.*;
|
|
|
|
|
import static cn.hutool.core.util.ObjectUtil.defaultIfNull;
|
|
|
|
|
import static com.ibeetl.admin.core.util.BeanUtil.copyToListSupportExtMap;
|
|
|
|
|
import static com.ibeetl.admin.core.util.DateUtil.weekNumberInList;
|
|
|
|
|
import static com.ibeetl.admin.core.util.user.CacheUserUtil.getUser;
|
|
|
|
@ -78,6 +82,8 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
TeacherOpenCourseScheduleSessionTagDao teacherOpenCourseScheduleSessionTagDao;
|
|
|
|
|
@Autowired
|
|
|
|
|
TeacherOpenCourseScheduleSessionClassService teacherOpenCourseScheduleSessionClassService;
|
|
|
|
|
@Autowired
|
|
|
|
|
TeacherService teacherService;
|
|
|
|
|
|
|
|
|
|
@Master
|
|
|
|
|
public PageQuery<TeacherOpenCourseScheduleSession>queryByCondition(PageQuery query){
|
|
|
|
@ -354,7 +360,7 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
// 构建的入库实体
|
|
|
|
|
TeacherOpenCourseScheduleSession tocss = insertByOptionResult.getScheduleSession();
|
|
|
|
|
// 验证排课规则
|
|
|
|
|
validateScheduleOptions(options);
|
|
|
|
|
// validateScheduleOptions(options, dateTimes);
|
|
|
|
|
// 入库
|
|
|
|
|
teacherOpenCourseScheduleSessionDao.insert(tocss);
|
|
|
|
|
// 获取插入数据库后返回的主键ID
|
|
|
|
@ -442,12 +448,17 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
DateTime startTime = parseDate(options.getStartTime());
|
|
|
|
|
// 结束时间向前偏移一天
|
|
|
|
|
DateTime endTime = offsetDay(DateUtil.offsetWeek(startTime, options.getWeekNum()), -1);
|
|
|
|
|
// 取开始和结束之间的区间
|
|
|
|
|
// 取开始和结束之间的区间,单位(天)
|
|
|
|
|
List<DateTime> dateTimes = DateUtil.rangeToList(startTime, endTime, DateField.DAY_OF_YEAR);
|
|
|
|
|
|
|
|
|
|
// 开课星期,排序。数据直观一些
|
|
|
|
|
List<Object> sortWeekDetail = options.getWeekDetail().stream().sorted().collect(Collectors.toList());
|
|
|
|
|
|
|
|
|
|
final Long teacherId = options.getTeacherId();
|
|
|
|
|
Teacher teacher = CollectionUtil.getFirst(teacherService.getByIds(teacherId.toString()));
|
|
|
|
|
final Long teacherOrgId = (teacher != null ? teacher.getOrgId() : null);
|
|
|
|
|
final Long teacherUserId = (teacher != null ? teacher.getUserId() : null);
|
|
|
|
|
|
|
|
|
|
// 课表主表保存
|
|
|
|
|
TeacherOpenCourseScheduleSession tocss = new TeacherOpenCourseScheduleSession();
|
|
|
|
|
tocss.setTeacherOpenCourseScheduleSessionAddTime(DateUtil.beginOfHour(DateUtil.date()));
|
|
|
|
@ -462,8 +473,8 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
tocss.setTeacherOpenCourseScheduleSessionEndDate(endTime.toDateStr());
|
|
|
|
|
tocss.setTeacherOpenCourseScheduleSessionWeekNum(options.getWeekNum());
|
|
|
|
|
tocss.setTeacherOpenCourseScheduleSessionStatusWeekDetail(join(sortWeekDetail, ","));
|
|
|
|
|
tocss.setOrgId(options.getOrgId());
|
|
|
|
|
tocss.setUserId(options.getUserId());
|
|
|
|
|
tocss.setOrgId(defaultIfNull(teacherOrgId, options.getOrgId()));
|
|
|
|
|
tocss.setUserId(defaultIfNull(teacherUserId, options.getUserId()));
|
|
|
|
|
|
|
|
|
|
// 返回结果暂存
|
|
|
|
|
InsertByOptionResult insertByOptionResult = new InsertByOptionResult();
|
|
|
|
@ -487,7 +498,20 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
* @Author: lx
|
|
|
|
|
* @Date: 2023/2/16 0:16
|
|
|
|
|
*/
|
|
|
|
|
public void validateScheduleOptions(@NotNull(message = "排课配置不能为空!") TeacherOpenCourseScheduleSessionOptions tocss) {
|
|
|
|
|
public void validateScheduleOptions(@NotNull(message = "排课配置不能为空!") TeacherOpenCourseScheduleSessionOptions tocss, List<DateTime> dateTimes) {
|
|
|
|
|
|
|
|
|
|
// 通过教师,获取org_id,过滤院校之间的数据,用于加快查询速度
|
|
|
|
|
final Long teacherId = tocss.getTeacherId();
|
|
|
|
|
Teacher teacher = CollectionUtil.getFirst(teacherService.getByIds(teacherId.toString()));
|
|
|
|
|
final Long teacherOrgId = (teacher != null ? teacher.getOrgId() : null);
|
|
|
|
|
final Long teacherUserId = (teacher != null ? teacher.getUserId() : null);
|
|
|
|
|
|
|
|
|
|
// 开课ID
|
|
|
|
|
final Long teacherOpenCourseId = tocss.getTeacherOpenCourseId();
|
|
|
|
|
|
|
|
|
|
// 上午或者下午,每节课的时间间隔
|
|
|
|
|
final int intervalTimeMinutes = 30;
|
|
|
|
|
|
|
|
|
|
// 这里的TeacherOpenCourseScheduleSessionTag 是前端传递过来的对象,全量数据
|
|
|
|
|
Map<Long, List<TeacherOpenCourseScheduleSessionTag>> sessionClassTagMap = tocss.getSessionClassList();
|
|
|
|
|
|
|
|
|
@ -496,8 +520,17 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
// 这里不带status = 1,全量查询吧,查询上课的教室列表
|
|
|
|
|
TeacherOpenCourseScheduleSessionClassQuery query = new TeacherOpenCourseScheduleSessionClassQuery();
|
|
|
|
|
query.setTeacherOpenCourseScheduleSessionClassIdPlural(join(sessionClassIds, ","));
|
|
|
|
|
query.setOrgId(teacherOrgId);
|
|
|
|
|
List<TeacherOpenCourseScheduleSessionClass> sessionClassList = teacherOpenCourseScheduleSessionClassService.getValuesByQuery(query);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 这里不带status = 1,全量查询吧,查询上课的教室列表
|
|
|
|
|
TeacherOpenCourseScheduleSessionClassQuery tocQuery = new TeacherOpenCourseScheduleSessionClassQuery();
|
|
|
|
|
tocQuery.setOrgId(teacherOrgId);
|
|
|
|
|
final List<TeacherOpenCourseScheduleSessionClass> sessionClassListByTOC = Collections
|
|
|
|
|
.unmodifiableList(CollectionUtil.emptyIfNull(teacherOpenCourseScheduleSessionClassService.getValuesByQuery(tocQuery)));
|
|
|
|
|
|
|
|
|
|
// 一个Key对应多个Value的封装Map
|
|
|
|
|
MultiValueMapAdapter<Long, TeacherOpenCourseScheduleSessionClass> multiValueMapAdapter = new MultiValueMapAdapter(
|
|
|
|
|
sessionClassList.stream().collect(groupingBy(TeacherOpenCourseScheduleSessionClass::getTeacherOpenCourseScheduleSessionClassId)));
|
|
|
|
|
|
|
|
|
@ -512,7 +545,7 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
parseTimeToday(o2.getTeacherOpenCourseScheduleSessionTagStartTime())));
|
|
|
|
|
|
|
|
|
|
// 判断时间是否有重叠部分
|
|
|
|
|
sessionTagConsumerHandler(tagList, (o) -> {
|
|
|
|
|
sessionTagConsumerHandler(tagList, (o, index, isSecondLast) -> {
|
|
|
|
|
// 判断时间区间的交集
|
|
|
|
|
List<DateTime> containsList = rangeContains(
|
|
|
|
|
new DateRange(o.getFirstStartTime(), o.getFirstEndTime(), HOUR_OF_DAY),
|
|
|
|
@ -527,10 +560,10 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
return isIn(parseTimeToday("00:01"), parseTimeToday("13:00"), endDate);
|
|
|
|
|
}).collect(Collectors.toList());
|
|
|
|
|
|
|
|
|
|
sessionTagConsumerHandler(AMTagList, (o) -> {
|
|
|
|
|
sessionTagConsumerHandler(AMTagList, (o, index, isSecondLast) -> {
|
|
|
|
|
// 上午6点到12点之间的每节课之间,间隔不允许超过30分钟,来判断是否有断课
|
|
|
|
|
long betweenMinutes = o.getFirstEndTime().between(o.getSecondStartTime(), DateUnit.MINUTE);
|
|
|
|
|
Assert.isTrue(betweenMinutes < 30,
|
|
|
|
|
Assert.isTrue(betweenMinutes < intervalTimeMinutes,
|
|
|
|
|
"无法正常排课,课次名称:[{}],{}] 不是连续的课次,上午每节课间隔不超过30分钟!", o.getFirstTagName(), o.getSecondTagName());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
@ -540,18 +573,116 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
return isIn(parseTimeToday("13:01"), parseTimeToday("23:59"), endDate);
|
|
|
|
|
}).collect(Collectors.toList());
|
|
|
|
|
|
|
|
|
|
sessionTagConsumerHandler(PMTagList, (o) -> {
|
|
|
|
|
sessionTagConsumerHandler(PMTagList, (o, index, isSecondLast) -> {
|
|
|
|
|
// 上午6点到12点之间的每节课之间,间隔不允许超过30分钟,来判断是否有断课
|
|
|
|
|
long betweenMinutes = o.getFirstEndTime().between(o.getSecondStartTime(), DateUnit.MINUTE);
|
|
|
|
|
Assert.isTrue(betweenMinutes < 30,
|
|
|
|
|
Assert.isTrue(betweenMinutes < intervalTimeMinutes,
|
|
|
|
|
"无法正常排课,课次名称:[{}],{}] 不是连续的课次,下午每节课间隔不超过30分钟!", o.getFirstTagName(), o.getSecondTagName());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查重复:重复提示:
|
|
|
|
|
// 同一个教室,同一个时段,不能安排两次课;
|
|
|
|
|
// TODO 排课重复检查
|
|
|
|
|
sessionTagConsumerHandler(tagList, (o, index, isSecondLast) -> {
|
|
|
|
|
|
|
|
|
|
// 快照表没存教室ID,所以需要实时的查询教室的全名称
|
|
|
|
|
final String sessionClassFullName = defaultIfNull(
|
|
|
|
|
teacherOpenCourseScheduleSessionClassService.getSessionClassFullName(sessionClassId, sessionClassListByTOC), "");
|
|
|
|
|
|
|
|
|
|
// 查看已经安排了的课表,判断同一个教室同一个时间段,不能重复
|
|
|
|
|
TeacherOpenCourseScheduleSessionSnapQuery sessionSnapQuery = new TeacherOpenCourseScheduleSessionSnapQuery();
|
|
|
|
|
sessionSnapQuery.setTeacherOpenCourseId(teacherOpenCourseId);
|
|
|
|
|
sessionSnapQuery.setTeacherOpenCourseScheduleSessionSnapStatus(1);
|
|
|
|
|
sessionSnapQuery.setTeacherOpenCourseScheduleSessionClassName(sessionClassFullName);
|
|
|
|
|
|
|
|
|
|
//查询正常状态下的排课快照列表
|
|
|
|
|
List<TeacherOpenCourseScheduleSessionSnap> normalStatusSessionSnapList =
|
|
|
|
|
teacherOpenCourseScheduleSessionSnapDao.getValuesByQuery(sessionSnapQuery);
|
|
|
|
|
|
|
|
|
|
// 数据库中保存的时间区间
|
|
|
|
|
final DateRange dr = new DateRange(o.getSecondStartTime(), o.getFirstEndTime(), MINUTE);
|
|
|
|
|
|
|
|
|
|
// 题目快照构建出来的时间区间集合
|
|
|
|
|
normalStatusSessionSnapList.stream()
|
|
|
|
|
.filter(item -> StrUtil.isNotBlank(sessionClassFullName)
|
|
|
|
|
&& sessionClassFullName.equals(item.getTeacherOpenCourseScheduleSessionClassName()))
|
|
|
|
|
.forEach(item -> {
|
|
|
|
|
// yyyy-MM-dd HH:mm 时间格式
|
|
|
|
|
String startDateTime = item.getTeacherOpenCourseScheduleSessionDayTime() + " " + item.getTeacherOpenCourseScheduleSessionTagStartTime();
|
|
|
|
|
String endDateTime = item.getTeacherOpenCourseScheduleSessionDayTime() + " " + item.getTeacherOpenCourseScheduleSessionTagEndTime();
|
|
|
|
|
|
|
|
|
|
// 判断时间区间的交集
|
|
|
|
|
List<DateTime> containsList = rangeContains(new DateRange(parse(startDateTime), parse(endDateTime), MINUTE), dr);
|
|
|
|
|
|
|
|
|
|
Assert.notEmpty(
|
|
|
|
|
containsList, "无法正常排课,教室名称:{},课次名称:[{}],{}] 时间有重叠部分!",
|
|
|
|
|
sessionClassFullName, o.getFirstTagName(), o.getSecondTagName());
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 同一个老师,不能安排在不同课程的同一个时段上课;
|
|
|
|
|
sessionTagConsumerHandler(tagList, (o, index, isSecondLast) -> {
|
|
|
|
|
|
|
|
|
|
// 查看已经安排了的课表,判断同一个教室同一个时间段,不能重复
|
|
|
|
|
TeacherOpenCourseScheduleSessionSnapQuery sessionSnapQuery = new TeacherOpenCourseScheduleSessionSnapQuery();
|
|
|
|
|
sessionSnapQuery.setTeacherOpenCourseId(teacherOpenCourseId);
|
|
|
|
|
sessionSnapQuery.setTeacherOpenCourseScheduleSessionSnapStatus(1);
|
|
|
|
|
sessionSnapQuery.setUserId(teacherUserId);
|
|
|
|
|
|
|
|
|
|
//查询正常状态下的排课快照列表,教师的所有排课
|
|
|
|
|
List<TeacherOpenCourseScheduleSessionSnap> normalStatusSessionSnapList =
|
|
|
|
|
teacherOpenCourseScheduleSessionSnapDao.getValuesByQuery(sessionSnapQuery);
|
|
|
|
|
|
|
|
|
|
// 数据库中保存的时间区间
|
|
|
|
|
final DateRange dr = new DateRange(o.getSecondStartTime(), o.getFirstEndTime(), MINUTE);
|
|
|
|
|
|
|
|
|
|
// 题目快照构建出来的时间区间集合
|
|
|
|
|
normalStatusSessionSnapList.stream().forEach(item -> {
|
|
|
|
|
// yyyy-MM-dd HH:mm 时间格式
|
|
|
|
|
String startDateTime = item.getTeacherOpenCourseScheduleSessionDayTime() + " " + item.getTeacherOpenCourseScheduleSessionTagStartTime();
|
|
|
|
|
String endDateTime = item.getTeacherOpenCourseScheduleSessionDayTime() + " " + item.getTeacherOpenCourseScheduleSessionTagEndTime();
|
|
|
|
|
|
|
|
|
|
// 判断时间区间的交集
|
|
|
|
|
List<DateTime> containsList = rangeContains(new DateRange(parse(startDateTime), parse(endDateTime), MINUTE), dr);
|
|
|
|
|
|
|
|
|
|
Assert.notEmpty(containsList, "无法正常排课,教师名称:{},课次名称:[{}],{}] 时间有重叠部分!",
|
|
|
|
|
teacher.getTeacherName(), o.getFirstTagName(), o.getSecondTagName());
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 同一个班级,不能安排不同教室同一个时间上课
|
|
|
|
|
// TODO 排课重复检查
|
|
|
|
|
sessionTagConsumerHandler(tagList, (o, index, isSecondLast) -> {
|
|
|
|
|
|
|
|
|
|
// 查看已经安排了的课表,判断同一个教室同一个时间段,不能重复
|
|
|
|
|
TeacherOpenCourseScheduleSessionSnapQuery sessionSnapQuery = new TeacherOpenCourseScheduleSessionSnapQuery();
|
|
|
|
|
sessionSnapQuery.setTeacherOpenCourseId(teacherOpenCourseId);
|
|
|
|
|
sessionSnapQuery.setTeacherOpenCourseScheduleSessionSnapStatus(1);
|
|
|
|
|
sessionSnapQuery.setUserId(teacherUserId);
|
|
|
|
|
|
|
|
|
|
//查询正常状态下的排课快照列表,教师的所有排课
|
|
|
|
|
List<TeacherOpenCourseScheduleSessionSnap> normalStatusSessionSnapList =
|
|
|
|
|
teacherOpenCourseScheduleSessionSnapDao.getValuesByQuery(sessionSnapQuery);
|
|
|
|
|
|
|
|
|
|
// 数据库中保存的时间区间
|
|
|
|
|
final DateRange dr = new DateRange(o.getSecondStartTime(), o.getFirstEndTime(), MINUTE);
|
|
|
|
|
|
|
|
|
|
// 题目快照构建出来的时间区间集合
|
|
|
|
|
normalStatusSessionSnapList.stream().forEach(item -> {
|
|
|
|
|
// yyyy-MM-dd HH:mm 时间格式
|
|
|
|
|
String startDateTime = item.getTeacherOpenCourseScheduleSessionDayTime() + " " + item.getTeacherOpenCourseScheduleSessionTagStartTime();
|
|
|
|
|
String endDateTime = item.getTeacherOpenCourseScheduleSessionDayTime() + " " + item.getTeacherOpenCourseScheduleSessionTagEndTime();
|
|
|
|
|
|
|
|
|
|
// 判断时间区间的交集
|
|
|
|
|
List<DateTime> containsList = rangeContains(new DateRange(parse(startDateTime), parse(endDateTime), MINUTE), dr);
|
|
|
|
|
|
|
|
|
|
Assert.notEmpty(containsList, "无法正常排课,教师名称:{},课次名称:[{}],{}] 时间有重叠部分!",
|
|
|
|
|
teacher.getTeacherName(), o.getFirstTagName(), o.getSecondTagName());
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -564,7 +695,12 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
* @Author: lx
|
|
|
|
|
* @Date: 2023/2/16 1:42
|
|
|
|
|
*/
|
|
|
|
|
private void sessionTagConsumerHandler(List<TeacherOpenCourseScheduleSessionTag> tagList, Consumer<SessionTagTemp> consumer) {
|
|
|
|
|
private void sessionTagConsumerHandler(List<TeacherOpenCourseScheduleSessionTag> tagList, Consumer3<SessionTagTemp, Integer, Boolean> consumer) {
|
|
|
|
|
|
|
|
|
|
// 如果只查询到条数据的话,那么直接跳过,不进行验证
|
|
|
|
|
if (tagList == null || tagList.size() <= 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 循环遍历,构建消费
|
|
|
|
|
for (int i = 0; i < tagList.size() - 1; i++) {
|
|
|
|
@ -588,7 +724,9 @@ public class TeacherOpenCourseScheduleSessionService extends CoreBaseService<Tea
|
|
|
|
|
.secondStartTime(secondStartTime)
|
|
|
|
|
.secondEndTime(secondEndTime)
|
|
|
|
|
.build();
|
|
|
|
|
consumer.accept(stt);
|
|
|
|
|
|
|
|
|
|
// 构建的实体,索引,当前索引是否是倒数第二个元素
|
|
|
|
|
consumer.accept(stt, i, i == tagList.size() - 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|