package com.ym.mec.biz.service.impl;

import static com.ym.mec.biz.dal.enums.GroupType.MUSIC;
import static com.ym.mec.biz.dal.enums.GroupType.PRACTICE;
import static com.ym.mec.biz.dal.enums.GroupType.VIP;
import static com.ym.mec.biz.dal.enums.PracticeGroupType.CHARGE;
import static com.ym.mec.biz.dal.enums.PracticeGroupType.FREE;
import static com.ym.mec.biz.dal.enums.PracticeGroupType.TRIAL;

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.ym.mec.biz.service.*;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ym.mec.auth.api.client.SysUserFeignService;
import com.ym.mec.auth.api.entity.SysUser;
import com.ym.mec.auth.api.entity.SysUserRole;
import com.ym.mec.biz.dal.dao.ClassGroupDao;
import com.ym.mec.biz.dal.dao.ClassGroupStudentMapperDao;
import com.ym.mec.biz.dal.dao.ClassGroupTeacherMapperDao;
import com.ym.mec.biz.dal.dao.ClassGroupTeacherSalaryDao;
import com.ym.mec.biz.dal.dao.CourseScheduleComplaintsDao;
import com.ym.mec.biz.dal.dao.CourseScheduleDao;
import com.ym.mec.biz.dal.dao.CourseScheduleEvaluateDao;
import com.ym.mec.biz.dal.dao.CourseScheduleModifyLogDao;
import com.ym.mec.biz.dal.dao.CourseScheduleReviewDao;
import com.ym.mec.biz.dal.dao.CourseScheduleStudentPaymentDao;
import com.ym.mec.biz.dal.dao.CourseScheduleTeacherSalaryDao;
import com.ym.mec.biz.dal.dao.CoursesGroupDao;
import com.ym.mec.biz.dal.dao.CoursesGroupModifyLogDao;
import com.ym.mec.biz.dal.dao.GroupDao;
import com.ym.mec.biz.dal.dao.MusicGroupDao;
import com.ym.mec.biz.dal.dao.PracticeGroupDao;
import com.ym.mec.biz.dal.dao.SchoolDao;
import com.ym.mec.biz.dal.dao.StudentAttendanceDao;
import com.ym.mec.biz.dal.dao.SubjectDao;
import com.ym.mec.biz.dal.dao.SysConfigDao;
import com.ym.mec.biz.dal.dao.TeacherAttendanceDao;
import com.ym.mec.biz.dal.dao.TeacherDao;
import com.ym.mec.biz.dal.dao.TeacherDefaultMusicGroupSalaryDao;
import com.ym.mec.biz.dal.dao.TeacherDefaultPracticeGroupSalaryDao;
import com.ym.mec.biz.dal.dao.TeacherDefaultVipGroupSalaryDao;
import com.ym.mec.biz.dal.dao.VipGroupDao;
import com.ym.mec.biz.dal.dto.BatchInsertCoursesDto;
import com.ym.mec.biz.dal.dto.ClassDateAdjustDto;
import com.ym.mec.biz.dal.dto.CourseAttendanceDetailHeadInfoDto;
import com.ym.mec.biz.dal.dto.CourseMergeDto;
import com.ym.mec.biz.dal.dto.CoursePostponeDto;
import com.ym.mec.biz.dal.dto.CourseRepeatCheckDto;
import com.ym.mec.biz.dal.dto.CourseScheduleDto;
import com.ym.mec.biz.dal.dto.CourseScheduleEndDto;
import com.ym.mec.biz.dal.dto.CourseScheduleRateDto;
import com.ym.mec.biz.dal.dto.CourseScheduleStudentDto;
import com.ym.mec.biz.dal.dto.CourseTimeDto;
import com.ym.mec.biz.dal.dto.CreateCourseScheduleDto;
import com.ym.mec.biz.dal.dto.IntegerAndIntegerListDto;
import com.ym.mec.biz.dal.dto.Mapper;
import com.ym.mec.biz.dal.dto.StudentNameAndPhoneDto;
import com.ym.mec.biz.dal.dto.TeacherAttendanceDto;
import com.ym.mec.biz.dal.dto.TeacherClassCourseSchudeleDto;
import com.ym.mec.biz.dal.dto.TeacherRemarkCommitDto;
import com.ym.mec.biz.dal.dto.VipGroupApplyBaseInfoDto;
import com.ym.mec.biz.dal.dto.VipGroupApplyDto;
import com.ym.mec.biz.dal.dto.VipGroupCourseAdjustInfoDto;
import com.ym.mec.biz.dal.entity.ClassGroup;
import com.ym.mec.biz.dal.entity.ClassGroupStudentMapper;
import com.ym.mec.biz.dal.entity.ClassGroupTeacherMapper;
import com.ym.mec.biz.dal.entity.ClassGroupTeacherSalary;
import com.ym.mec.biz.dal.entity.CourseGenerateDto;
import com.ym.mec.biz.dal.entity.CourseSchedule;
import com.ym.mec.biz.dal.entity.CourseSchedule.CourseScheduleType;
import com.ym.mec.biz.dal.entity.CourseScheduleAuditDetailDto;
import com.ym.mec.biz.dal.entity.CourseScheduleComplaints;
import com.ym.mec.biz.dal.entity.CourseScheduleEvaluate;
import com.ym.mec.biz.dal.entity.CourseScheduleModifyLog;
import com.ym.mec.biz.dal.entity.CourseScheduleReview;
import com.ym.mec.biz.dal.entity.CourseScheduleStudentPayment;
import com.ym.mec.biz.dal.entity.CourseScheduleTeacherSalary;
import com.ym.mec.biz.dal.entity.CoursesGroup;
import com.ym.mec.biz.dal.entity.CoursesGroupModifyLog;
import com.ym.mec.biz.dal.entity.Group;
import com.ym.mec.biz.dal.entity.MusicGroup;
import com.ym.mec.biz.dal.entity.PracticeGroup;
import com.ym.mec.biz.dal.entity.School;
import com.ym.mec.biz.dal.entity.StudentAttendance;
import com.ym.mec.biz.dal.entity.StudentCourseScheduleRecordDto;
import com.ym.mec.biz.dal.entity.Subject;
import com.ym.mec.biz.dal.entity.SysConfig;
import com.ym.mec.biz.dal.entity.Teacher;
import com.ym.mec.biz.dal.entity.TeacherAttendance;
import com.ym.mec.biz.dal.entity.TeacherDefaultMusicGroupSalary;
import com.ym.mec.biz.dal.entity.TeacherDefaultPracticeGroupSalary;
import com.ym.mec.biz.dal.entity.TeacherDefaultVipGroupSalary;
import com.ym.mec.biz.dal.entity.VipGroup;
import com.ym.mec.biz.dal.enums.AuditStatusEnum;
import com.ym.mec.biz.dal.enums.ClassGroupStudentStatusEnum;
import com.ym.mec.biz.dal.enums.ClassGroupTypeEnum;
import com.ym.mec.biz.dal.enums.CourseStatusEnum;
import com.ym.mec.biz.dal.enums.GroupStatusEnum;
import com.ym.mec.biz.dal.enums.GroupType;
import com.ym.mec.biz.dal.enums.MessageTypeEnum;
import com.ym.mec.biz.dal.enums.MusicGroupStatusEnum;
import com.ym.mec.biz.dal.enums.ParamEnum;
import com.ym.mec.biz.dal.enums.SalarySettlementTypeEnum;
import com.ym.mec.biz.dal.enums.StudentAttendanceStatusEnum;
import com.ym.mec.biz.dal.enums.TeachModeEnum;
import com.ym.mec.biz.dal.enums.TeachTypeEnum;
import com.ym.mec.biz.dal.enums.VipGroupStatusEnum;
import com.ym.mec.biz.dal.enums.YesOrNoEnum;
import com.ym.mec.biz.dal.page.CourseScheduleQueryInfo;
import com.ym.mec.biz.dal.page.EndCourseScheduleQueryInfo;
import com.ym.mec.biz.dal.page.StudentCourseScheduleRecordQueryInfo;
import com.ym.mec.biz.dal.page.VipGroupQueryInfo;
import com.ym.mec.biz.event.source.CourseEventSource;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.entity.ImGroupMember;
import com.ym.mec.common.entity.ImGroupModel;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.page.QueryInfo;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.im.ImFeignService;
import com.ym.mec.thirdparty.message.MessageSenderPluginContext.MessageSender;
import com.ym.mec.util.collection.ListUtil;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateUtil;
import com.ym.mec.util.json.JsonUtil;

@Service
public class CourseScheduleServiceImpl extends BaseServiceImpl<Long, CourseSchedule> implements CourseScheduleService {

    @Autowired
    private CourseScheduleDao courseScheduleDao;
    @Autowired
    private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private CourseScheduleModifyLogDao courseScheduleModifyLogDao;
    @Autowired
    private CourseScheduleComplaintsDao courseScheduleComplaintsDao;
    @Autowired
    private CourseScheduleEvaluateDao courseScheduleEvaluateDao;
    @Autowired
    private SysConfigDao sysConfigDao;
    @Autowired
    private StudentAttendanceDao studentAttendanceDao;
    @Autowired
    private ClassGroupStudentMapperDao classGroupStudentMapperDao;
    @Autowired
    private TeacherDefaultPracticeGroupSalaryDao teacherDefaultPracticeGroupSalaryDao;
    @Autowired
    private SysMessageService sysMessageService;
    @Autowired
    @Lazy
    private CourseScheduleTeacherSalaryService courseScheduleTeacherSalaryService;
    @Autowired
    private VipGroupDao vipGroupDao;
	@Autowired
	private CoursesGroupDao coursesGroupDao;
    @Autowired
    private TeacherDefaultVipGroupSalaryDao teacherDefaultVipGroupSalaryDao;
    @Autowired
    private TeacherDefaultMusicGroupSalaryDao teacherDefaultMusicGroupSalaryDao;
    @Autowired
    private ClassGroupTeacherMapperService classGroupTeacherMapperService;
    @Autowired
    private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;
    @Autowired
    private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
    @Autowired
    private TeacherAttendanceDao teacherAttendanceDao;
    @Autowired
    private ClassGroupService classGroupService;
    @Autowired
    private ClassGroupDao classGroupDao;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private SubjectDao subjectDao;
    @Autowired
    private ClassGroupTeacherSalaryDao classGroupTeacherSalaryDao;
    @Autowired
    private PracticeGroupDao practiceGroupDao;
    @Autowired
    @Lazy
    private VipGroupService vipGroupService;
    @Autowired
    private MusicGroupService musicGroupService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private SchoolDao schoolDao;
    @Autowired
	private ImGroupMemberService imGroupMemberService;
    @Autowired
	private ImUserFriendService imUserFriendService;
    @Autowired
    private CourseHomeworkService courseHomeworkService;
    @Autowired
    private GroupDao groupDao;
    @Autowired
    private TeacherDao teacherDao;
    @Autowired
	private CourseScheduleReviewDao courseScheduleReviewDao;
    @Autowired
	private PracticeGroupService practiceGroupService;
    @Autowired
	private CoursesGroupModifyLogDao coursesGroupModifyLogDao;
    @Autowired
	private ClassGroupTeacherMapperDao classGroupTeacherMapperDao;
    @Autowired
	private CourseEventSource courseEventSource;
    @Autowired
	private StudentServeService studentServeService;

    private final Logger LOGGER = LoggerFactory
            .getLogger(this.getClass());

    @Override
    public BaseDAO<Long, CourseSchedule> getDAO() {
        return courseScheduleDao;
    }

    @Override
	public CourseSchedule queryById(Long courseScheduleId) {
    	CourseSchedule courseSchedule = courseScheduleDao.get(courseScheduleId);
    	if(courseSchedule != null){
    		//查询助教列表
    		List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaryList =  courseScheduleTeacherSalaryDao.findByCourseSchedule(courseScheduleId);
    		if(courseScheduleTeacherSalaryList != null){
    			List<Integer> teacherIdList = courseScheduleTeacherSalaryList.stream().filter(t -> TeachTypeEnum.TEACHING.equals(t.getTeacherRole())).map(CourseScheduleTeacherSalary::getUserId).collect(Collectors.toList());
    			courseSchedule.setTeachingTeacherIdList(teacherIdList);
    		}
    	}
		return courseSchedule;
	}

	@Override
    public TeacherAttendanceDto getCurrentCourseDetail(Long courseID) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        if (Objects.isNull(courseID)) {
            throw new BizException("参数错误!");
        }
        TeacherAttendanceDto currentCourseDetail = courseScheduleDao.getCurrentCourseDetail(courseID, user.getId());
        if (Objects.isNull(currentCourseDetail)) {
            throw new BizException("课程不存在");
        }
        if(Objects.nonNull(currentCourseDetail.getSchoolId())){
            boolean enableIgnoreAttendanceTime = enableIgnoreAttendanceTime(currentCourseDetail.getStartClassTime(),
                    user.getId(),
                    currentCourseDetail.getSchoolId().intValue());
            currentCourseDetail.setOnlyNormal(enableIgnoreAttendanceTime?YesOrNoEnum.YES:YesOrNoEnum.NO);
        }else{
            currentCourseDetail.setOnlyNormal(YesOrNoEnum.NO);
        }

		Set<Long> teacherServeCourseIds = studentServeService.getTeacherServeCourseIds(user.getId());
        if(teacherServeCourseIds.contains(courseID)){
			currentCourseDetail.setEnableAssignHomework(1);
		}

		currentCourseDetail.setCurrentClassTimes(courseScheduleDao.countClassGroupOverCourseNum(currentCourseDetail.getClassId()));
        SysConfig sysConfig = sysConfigService.findByParamName(SysConfigService.ENABLE_STUDENT_ATTENDANCE_TIME_RANGE);
        SysConfig sysConfigVip = sysConfigService.findByParamName(SysConfigService.ENABLE_STUDENT_ATTENDANCE_TIME_RANGE_VIP);
        currentCourseDetail.setEnableStudentAttendanceTimeRange(sysConfig.getParanValue(Integer.class));
        currentCourseDetail.setEnableStudentAttendanceTimeRangeVip(sysConfigVip.getParanValue(Integer.class));
        int studentNum = studentAttendanceDao.countByCourseSchedule(courseID);
        if (Objects.nonNull(studentNum)) {
            currentCourseDetail.setStudentAttendanceIsFirstTime(studentNum > 0 ? 0 : 1);
        } else {
            currentCourseDetail.setStudentAttendanceIsFirstTime(1);
        }

        currentCourseDetail.setCurrentTime(new Date());
        currentCourseDetail.setAdvanceSignInMinutes(Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ADVANCE_SIGN_IN_MINUTES)));
		currentCourseDetail.setAttendanceRange(CourseScheduleType.VIP.equals(currentCourseDetail.getCourseType())?Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ATTENDANCE_RANGE_VIP)):Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ATTENDANCE_RANGE)));
        currentCourseDetail.setAdvanceSignOutMinutes(Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ADVANCE_SIGN_OUT_MINUTES)));
        return currentCourseDetail;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
	public void batchDeleteCourseSchedules(List<Long> courseScheduleIds) {

		List<CourseSchedule> courseScheduleList = courseScheduleDao.findByCourseScheduleIds(courseScheduleIds);

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = new Date();
		if (courseScheduleList != null) {
			for (CourseSchedule cs : courseScheduleList) {
				if (cs.getStatus() != CourseStatusEnum.NOT_START) {
					throw new BizException("删除失败，未开始的课程才能删除");
				}
				String endDateStr = DateUtil.format(cs.getClassDate(), "yyyy-MM-dd") + " " + DateUtil.format(cs.getStartClassTime(), "HH:mm:ss");
				if (DateUtil.stringToDate(endDateStr, sdf).before(date)) {
					throw new BizException("删除失败，未开始的课程才能删除");
				}
				if(Objects.nonNull(cs.getNewCourseId())){
					throw new BizException("删除失败，被合并课程不能删除");
				}
			}
		}
		courseScheduleDao.batchDeleteCourseSchedules(courseScheduleIds);
		courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
		courseScheduleStudentPaymentDao.deleteByCourseSchedule(courseScheduleIds);
		// 删除考勤
		teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
		studentAttendanceDao.deleteByCourseSchedules(courseScheduleIds);

		// 删除作业
		courseHomeworkService.delHomwworkByCourseScheduleId(courseScheduleIds);

		List<Integer> classGroupIdList = courseScheduleList.stream().map(t -> t.getClassGroupId()).collect(Collectors.toList());
		// 更新班级信息
		if (classGroupIdList != null && classGroupIdList.size() > 0) {
			for (Integer classGroupId : classGroupIdList) {
				classGroupService.updateClassGroupInfo(classGroupId);
			}
		}
	}

	@Override
	public void batchDeleteCourseSchedulesWithoutCheck(List<CourseSchedule> courseScheduleList) {
    	if(CollectionUtils.isEmpty(courseScheduleList)){
    		return;
		}
		List<Long> courseScheduleIds = courseScheduleList.stream().map(CourseSchedule::getId).collect(Collectors.toList());

		courseScheduleDao.batchDeleteCourseSchedulesWithoutCheck(courseScheduleIds);
		courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
		courseScheduleStudentPaymentDao.deleteByCourseSchedule(courseScheduleIds);
		// 删除考勤
		teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
		studentAttendanceDao.deleteByCourseSchedules(courseScheduleIds);

		// 删除作业
		courseHomeworkService.delHomwworkByCourseScheduleId(courseScheduleIds);

		List<Integer> classGroupIdList = courseScheduleList.stream().map(t -> t.getClassGroupId()).collect(Collectors.toList());
		// 更新班级信息
		if (classGroupIdList != null && classGroupIdList.size() > 0) {
			for (Integer classGroupId : classGroupIdList) {
				classGroupService.updateClassGroupInfo(classGroupId);
			}
		}
	}

	@Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteMusicGroupNotStartCourse(String musicGroupId, GroupType groupType) {
        if (StringUtils.isBlank(musicGroupId)) {
            throw new BizException("请指定乐团");
        }
        List<CourseSchedule> musicGroupCourseSchedules = courseScheduleDao.findMusicGroupCourseSchedules(musicGroupId, groupType.getCode(), CourseStatusEnum.NOT_START.getCode());
        if (CollectionUtils.isEmpty(musicGroupCourseSchedules)) {
            throw new BizException("此乐团不存在未上课程");
        }
        List<Long> courseScheduleIds = musicGroupCourseSchedules.stream()
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());
        batchDeleteCourseSchedules(courseScheduleIds);
    }

	@Override
	public void batchDeleteMusicGroup(String musicGroupId, GroupType groupType) {
		if (StringUtils.isBlank(musicGroupId)) {
			throw new BizException("请指定乐团");
		}
		List<CourseSchedule> musicGroupCourseSchedules = courseScheduleDao.findMusicGroupAllCourseSchedules(musicGroupId, groupType.getCode());
		if (CollectionUtils.isEmpty(musicGroupCourseSchedules)) {
			throw new BizException("此乐团不存在未上课程");
		}
		batchDeleteCourseSchedulesWithoutCheck(musicGroupCourseSchedules);
	}

	@Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteMusicGroupCourseWithStudent(String musicGroupId, Integer userId, GroupType groupType) {
        if (StringUtils.isBlank(musicGroupId)) {
            throw new BizException("请指定乐团");
        }
        List<CourseSchedule> musicGroupCourseSchedules = courseScheduleDao.findMusicGroupCourseSchedulesWithStudent(musicGroupId, groupType.getCode(), CourseStatusEnum.NOT_START.getCode(), userId);
        if (!CollectionUtils.isEmpty(musicGroupCourseSchedules)) {
            List<Long> courseScheduleIds = musicGroupCourseSchedules.stream()
                    .map(courseSchedule -> courseSchedule.getId())
                    .collect(Collectors.toList());
            courseScheduleDao.deleteMusicGroupCourseSchedulesWithStudent(courseScheduleIds, userId);
        }
    }

    @Override
    public YesOrNoEnum enableOnlyNormalAttendance(Date startClassTime, Long userId, boolean checkSchool, Integer schoolId) {
        Date endTime = startClassTime;
        Date startTime = DateUtil.addHours(endTime, -1);
        List<TeacherAttendanceDto> teacherCourseByDateSpeeds = courseScheduleDao.getTeacherCourseByDateSpeed(startTime, endTime, userId, schoolId);
        if (CollectionUtils.isEmpty(teacherCourseByDateSpeeds)) {
            return YesOrNoEnum.NO;
        } else {
            if (checkSchool
                    && Objects.nonNull(schoolId)) {
                return YesOrNoEnum.YES;
            } else {
                return YesOrNoEnum.NO;
            }
        }
    }

	@Override
	public boolean enableIgnoreAttendanceTime(Date startClassTime, Integer teacherId, Integer schoolId) {
		CourseSchedule prevCourse = courseScheduleDao.getTeacherAttendanceCourseBeforeStartTime(startClassTime, teacherId);
		if(Objects.isNull(prevCourse)||Objects.isNull(prevCourse.getSchoolId())){
			return false;
		}
		if(!schoolId.equals(prevCourse.getSchoolId())){
			return true;
		}
		int minutesBetween = DateUtil.minutesBetween(prevCourse.getEndClassTime(), startClassTime);
		if(minutesBetween>60){
			return false;
		}else{
			return true;
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean batchAddCourseSchedule(Integer classGroupId, int coursesTimes, Date startDate, Date groupEndDate, Date groupStartDate, List<CourseTimeDto> teachingArrangementList,
			TeachModeEnum teachMode, CourseScheduleType type, Integer schoolId, boolean isJumpHoliday) {
		ClassGroup classGroup = classGroupService.get(classGroupId);
		if (classGroup == null) {
			throw new BizException("排课失败，班级信息不存在");
		}

		if (teachMode == TeachModeEnum.OFFLINE && schoolId == null) {
			throw new BizException("线下课请指定教学点");
		}

		if (type == null) {
			throw new BizException("请指定课程类型");
		}

		if (type == CourseScheduleType.VIP) {
			throw new BizException("暂不支持vip课加课");
		}

		if (teachingArrangementList == null || teachingArrangementList.size() == 0) {
			throw new BizException("请设置课时安排");
		}

		BigDecimal subSidy = new BigDecimal(0);
		// 查询教学点补贴
		if (schoolId != null) {
			School school = schoolDao.get(schoolId);
			if (school == null) {
				throw new BizException("指定的教学点不存在");
			}
			subSidy = school.getSubsidy();
		}

		//查询声部
		String subjectName = subjectDao.findNames(classGroup.getSubjectIdList());

		// 查询班级老师信息
		List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroupTeacherMapperService.getClassGroupTeachers(classGroupId);

		// 查询主教老师
		Integer teacherId = null;
		for (ClassGroupTeacherMapper cgtm : classGroupTeacherMapperList) {
			if (cgtm.getTeacherRole() == TeachTypeEnum.BISHOP) {
				teacherId = cgtm.getUserId();
				break;
			}
		}

		if (teacherId == null) {
			throw new BizException("班级缺少主教老师");
		}

		List<Integer> teacherIdList = classGroupTeacherMapperList.stream().map(ClassGroupTeacherMapper::getUserId).collect(Collectors.toList());

		// 查询老师列表
		List<Teacher> teacherList = teacherDao.findByTeacherIds(teacherIdList);
		Map<Integer, Teacher> teacherMap = teacherList.stream().collect(Collectors.toMap(Teacher::getId, t -> t));

		Map<Integer, BigDecimal> teacherPracticeSalaryMap = new HashMap<Integer, BigDecimal>();
		Map<Integer, TeacherDefaultMusicGroupSalary> teacherMusicSalaryMap = new HashMap<Integer, TeacherDefaultMusicGroupSalary>();

		Date entryDate = null;
		String settlementType = null;
		Integer organId = null;

		// 查询老师默认课酬
		if (type == CourseScheduleType.PRACTICE) {
			PracticeGroup practiceGroup = practiceGroupDao.get(Long.valueOf(classGroup.getMusicGroupId()));
			if(Objects.isNull(practiceGroup)){
				throw new BizException("找不到网管课信息");
			}
			if(!GroupStatusEnum.NORMAL.equals(practiceGroup.getGroupStatus())){
				throw new BizException("非进行中网管课不支持加课");
			}
			organId=practiceGroup.getOrganId();

			List<TeacherDefaultPracticeGroupSalary> teacherDefaultPracticeGroupSalaryList = teacherDefaultPracticeGroupSalaryDao
					.queryByUserIdList(teacherIdList);

			teacherPracticeSalaryMap = teacherDefaultPracticeGroupSalaryList.stream().collect(
					Collectors.toMap(TeacherDefaultPracticeGroupSalary::getUserId, TeacherDefaultPracticeGroupSalary::getMainTeacherSalary));

		} else {
			MusicGroup musicGroup = musicGroupDao.get(classGroup.getMusicGroupId());
			if (musicGroup == null) {
				throw new BizException("找不到乐团信息");
			}
			organId=musicGroup.getOrganId();
			// 乐团结算方式
			settlementType = musicGroup.getSettlementType().getCode();

			// 所有老师默认乐团课酬
			List<TeacherDefaultMusicGroupSalary> teacherDefaultMusicGroupSalaries = teacherDefaultMusicGroupSalaryDao.findByTeacher(teacherIdList);

			for (TeacherDefaultMusicGroupSalary tdms : teacherDefaultMusicGroupSalaries) {
				if (tdms.getCourseScheduleType() == type) {
					teacherMusicSalaryMap.put(tdms.getUserId(), tdms);
				}
			}
		}

		// 查询班级学生信息
		List<ClassGroupStudentMapper> classGroupStudentMapperList = classGroupStudentMapperDao.findByClassGroup(classGroupId);
		String usernameList = classGroupStudentMapperList.stream().map(ClassGroupStudentMapper::getUserName).collect(Collectors.joining("、"));

		Map<Integer, List<CourseTimeDto>> dayOfWeekMap = new HashMap<Integer, List<CourseTimeDto>>();
		for(CourseTimeDto dto : teachingArrangementList){
			//检查是否有开始时间
			if (StringUtils.isBlank(dto.getStartClassTime())) {
				throw new BizException("必须设置排课开始时间");
			}
			List<CourseTimeDto> list = dayOfWeekMap.get(dto.getDayOfWeek());
			if(list == null){
				list = new ArrayList<CourseTimeDto>();
			}
			list.add(dto);
			dayOfWeekMap.put(dto.getDayOfWeek(), list);
		}

		Calendar calendar = Calendar.getInstance();
		Date now = new Date();
		List<CourseTimeDto> courseTimeDtoList = null;
		List<CourseSchedule> courseScheduleList = new ArrayList<CourseSchedule>();
		List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = new ArrayList<CourseScheduleTeacherSalary>();
		List<CourseScheduleStudentPayment> courseScheduleStudentPayments = new ArrayList<CourseScheduleStudentPayment>();
		List<TeacherAttendance> teacherAttendances = new ArrayList<TeacherAttendance>();
		Set<String> holidayDays = new HashSet<>();
		if (isJumpHoliday) {
			SysConfig holidaySetting = sysConfigService.findByParamName(SysConfigService.HOLIDAY_SETTING);
			if(Objects.nonNull(holidaySetting)&&StringUtils.isNotBlank(holidaySetting.getParanValue())){
				holidayDays = new HashSet<>(JSON.parseArray(holidaySetting.getParanValue(), String.class));
			}
		}
		calendar.setTime(startDate);

		int currentCourseTimes = 0;
		while (coursesTimes != currentCourseTimes) {
            if (holidayDays.contains(DateUtil.format(calendar.getTime(), "yyyy-MM-dd"))) {
                calendar.add(Calendar.DATE, 1);
                continue;
            }
			// 查询当前日期是周几
			int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
			if (dayOfWeek == 1) {
				dayOfWeek = 7;
			} else {
				dayOfWeek = dayOfWeek - 1;
			}
			courseTimeDtoList = dayOfWeekMap.get(dayOfWeek);
			if (courseTimeDtoList != null) {
				for(CourseTimeDto courseTimeDto : courseTimeDtoList){

					// 课表
					CourseSchedule courseSchedule = new CourseSchedule();
					courseSchedule.setMusicGroupId(classGroup.getMusicGroupId());
					courseSchedule.setClassGroupId(classGroup.getId());
					courseSchedule.setStatus(CourseStatusEnum.NOT_START);
					courseSchedule.setClassDate(calendar.getTime());

					String dateYmdStr = DateUtil.dateToString(calendar.getTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT);

					String startTimeStr = dateYmdStr + " " + courseTimeDto.getStartClassTime();
					Date courseStartTime = DateUtil.stringToDate(startTimeStr, "yyyy-MM-dd HH:mm");
					courseSchedule.setStartClassTime(courseStartTime);

					if (StringUtils.isNotBlank(courseTimeDto.getEndClassTime())) {
						String endTimeStr = dateYmdStr + " " + courseTimeDto.getEndClassTime();
						Date courseEndTime = DateUtil.stringToDate(endTimeStr, "yyyy-MM-dd HH:mm");
						courseSchedule.setEndClassTime(courseEndTime);

						if (courseEndTime.before(courseStartTime)) {
							throw new BizException("课时上课时间安排错误");
						}
					} else {
						if (type == CourseScheduleType.PRACTICE) {
							courseSchedule.setEndClassTime(DateUtil.addMinutes(courseStartTime, 25));
						} else {
							throw new BizException("必须设置上课结束时间");
						}
					}

					if (!DateUtil.isSameDay(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime())) {
						throw new BizException("上课时间不允许跨天，请重新调整上课时间");
					}

					courseSchedule.setTeacherId(teacherId);
					courseSchedule.setActualTeacherId(teacherId);
					courseSchedule.setCreateTime(now);
					courseSchedule.setUpdateTime(now);
					courseSchedule.setTeachMode(teachMode);
					courseSchedule.setType(type);
					courseSchedule.setGroupType(classGroup.getGroupType());
					courseSchedule.setName(classGroup.getName());
					courseSchedule.setSchoolId(schoolId);
					courseSchedule.setSubsidy(subSidy);
					courseSchedule.setOrganId(organId);
					if (type == CourseScheduleType.PRACTICE || type == CourseScheduleType.VIP) {
						courseSchedule.setName(subjectName + "•" + usernameList);
					} else {
						courseSchedule.setName(type.getMsg());
					}

					// 判断课程时间是否超过排课结束时间
					if(groupStartDate != null){
						if(groupStartDate.after(calendar.getTime())){
							throw new BizException("调整时间不得早于开课时间（{}）",groupStartDate);
						}
					}
					if (groupEndDate != null) {
						if (calendar.getTime().after(groupEndDate)) {
							throw new BizException("排课时间超出排课截止日期（{}）", groupEndDate);
						}
					}

					courseScheduleDao.insert(courseSchedule);
					courseScheduleList.add(courseSchedule);

					// 课程与老师薪水表
					for (ClassGroupTeacherMapper cgtm : classGroupTeacherMapperList) {
						CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
						courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
						courseScheduleTeacherSalary.setGroupType(classGroup.getGroupType());
						courseScheduleTeacherSalary.setMusicGroupId(classGroup.getMusicGroupId());
						courseScheduleTeacherSalary.setTeacherRole(cgtm.getTeacherRole());
						courseScheduleTeacherSalary.setUserId(cgtm.getUserId());
						if (type == CourseScheduleType.PRACTICE) {
							PracticeGroup practiceGroup = practiceGroupDao.get(Long.parseLong(classGroup.getMusicGroupId()));
							if(practiceGroup == null){
								throw new BizException("课程组不存在");
							}else if (FREE.equals(practiceGroup.getType())){
								SysConfig practiceCourseSalaryConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_SALARY);
								BigDecimal teacherSalary = new BigDecimal(practiceCourseSalaryConfig.getParanValue());
								courseScheduleTeacherSalary.setExpectSalary(teacherSalary);
							}else if (practiceGroup.getType() == TRIAL){
								courseScheduleTeacherSalary.setExpectSalary(new BigDecimal(0));
							}else {
								BigDecimal salary = teacherPracticeSalaryMap.get(cgtm.getUserId());
								if (salary == null) {
									throw new BizException("请设置老师陪练课课酬");
								}
								courseScheduleTeacherSalary.setExpectSalary(salary);
							}
						} else if (type == CourseScheduleType.VIP) {

						} else {
							TeacherDefaultMusicGroupSalary tdms = teacherMusicSalaryMap.get(cgtm.getUserId());

							int newMinutes = DateUtil.minutesBetween(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime());

							int unitMinutes = 30;

							// 如果当前教师是在指定日期之后入职的，则按照3.0的方式结算
							if (type != CourseScheduleType.CLASSROOM) {
								Teacher teacher = teacherMap.get(teacherId);
								if (Objects.nonNull(teacher.getEntryDate())
										&& (teacher.getEntryDate().after(entryDate) || teacher.getEntryDate().getTime() == entryDate.getTime())) {
									settlementType = SalarySettlementTypeEnum.GRADIENT_SALARY.getCode();
								}
							}
							if (StringUtils.equals(settlementType, "TEACHER_DEFAULT")) {
								if (courseScheduleTeacherSalary.getTeacherRole() == TeachTypeEnum.BISHOP) {
									courseScheduleTeacherSalary.setExpectSalary(new BigDecimal(tdms.getMainTeacher30MinSalary().doubleValue() * newMinutes
											/ unitMinutes));
								} else {
									courseScheduleTeacherSalary.setExpectSalary(new BigDecimal(tdms.getAssistantTeacher30MinSalary().doubleValue() * newMinutes
											/ unitMinutes));
								}
							} else if (StringUtils.equals(settlementType, "GRADIENT_SALARY")) {
								unitMinutes = 90;
								if (type == CourseScheduleType.CLASSROOM) {
									unitMinutes = 40;
								} else if (type == CourseScheduleType.HIGH) {
									unitMinutes = 45;
								}
								if (courseScheduleTeacherSalary.getTeacherRole() == TeachTypeEnum.BISHOP) {
									courseScheduleTeacherSalary.setExpectSalary(new BigDecimal(tdms.getMainTeacher90MinSalary().doubleValue() * newMinutes
											/ unitMinutes));
								} else {
									courseScheduleTeacherSalary.setExpectSalary(new BigDecimal(tdms.getAssistantTeacher90MinSalary().doubleValue() * newMinutes
											/ unitMinutes));
								}
							}

							//课堂课课酬
							if (type == CourseScheduleType.CLASSROOM) {
								BigDecimal salary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? tdms.getMainTeacher30MinSalary() : tdms.getAssistantTeacher30MinSalary();
								courseScheduleTeacherSalary.setExpectSalary(salary);
							}
							//基础技能提高课
							if (type == CourseScheduleType.HIGH) {
								BigDecimal salary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? tdms.getMainTeacher30MinSalary() : tdms.getAssistantTeacher30MinSalary();
								if (StringUtils.equals(settlementType, "GRADIENT_SALARY")) {
									salary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? tdms.getMainTeacher90MinSalary() : tdms.getAssistantTeacher90MinSalary();
								}
								courseScheduleTeacherSalary.setExpectSalary(salary);
							}
							//线上小班课
							if(type == CourseScheduleType.HIGH_ONLINE){
								Integer studentNum = classGroupStudentMapperDao.countClassGroupNormalStudentNum(classGroup.getId());
								BigDecimal salary = JSON.parseObject(tdms.getSalaryRuleJson()).getBigDecimal(studentNum.toString());
								courseScheduleTeacherSalary.setExpectSalary(salary);
							}

							if (type.equals(CourseSchedule.CourseScheduleType.MUSIC_NETWORK)) {
								courseScheduleTeacherSalary.setExpectSalary(JSON.parseObject(tdms.getSalaryRuleJson()).getBigDecimal("1"));
							}
						}
						courseScheduleTeacherSalary.setCreateTime(now);
						courseScheduleTeacherSalary.setUpdateTime(now);
						courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
						courseScheduleTeacherSalary.setSubsidy(subSidy);
						courseScheduleTeacherSalaries.add(courseScheduleTeacherSalary);
					}

					// 学生缴费记录
					for (ClassGroupStudentMapper cgsm : classGroupStudentMapperList) {
						CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
						courseScheduleStudentPayment.setGroupType(classGroup.getGroupType());
						courseScheduleStudentPayment.setMusicGroupId(classGroup.getMusicGroupId());
						courseScheduleStudentPayment.setCourseScheduleId(courseSchedule.getId());
						courseScheduleStudentPayment.setUserId(cgsm.getUserId());
						courseScheduleStudentPayment.setExpectPrice(BigDecimal.ZERO);
						courseScheduleStudentPayment.setClassGroupId(classGroup.getId());
						courseScheduleStudentPayment.setCreateTime(now);
						courseScheduleStudentPayment.setUpdateTime(now);
						courseScheduleStudentPayments.add(courseScheduleStudentPayment);
					}

					// 教师签到记录
					for (ClassGroupTeacherMapper cgtm : classGroupTeacherMapperList) {
						TeacherAttendance teacherAttendance = new TeacherAttendance();
						teacherAttendance.setMusicGroupId(classGroup.getMusicGroupId());
						teacherAttendance.setTeacherId(cgtm.getUserId());
						teacherAttendance.setClassGroupId(classGroup.getId());
						teacherAttendance.setGroupType(classGroup.getGroupType());
						teacherAttendance.setCourseScheduleId(courseSchedule.getId());
						teacherAttendance.setCreateTime(now);
						teacherAttendances.add(teacherAttendance);
					}
	                ++currentCourseTimes;
	                if(coursesTimes == currentCourseTimes){
	                	break;
	                }
				}
			}
            calendar.add(Calendar.DATE, 1);
		}

		//检查冲突
		checkNewCourseSchedules(courseScheduleList, false,false);

		if (courseScheduleTeacherSalaries.size() > 0) {
			courseScheduleTeacherSalaryDao.batchInsert(courseScheduleTeacherSalaries);
		}

		if (courseScheduleStudentPayments.size() > 0) {
			courseScheduleStudentPaymentDao.batchInsert(courseScheduleStudentPayments);
		}

		if (teacherAttendances.size() > 0) {
			teacherAttendanceDao.batchInsert(teacherAttendances);
		}

		// 更新班级信息
		classGroupService.updateClassGroupInfo(classGroupId);

		return true;
	}

	@Override
    @Transactional(rollbackFor = Exception.class)
    public void createCourseSchedules(CreateCourseScheduleDto createCourseScheduleDto) {
        List<CourseSchedule> courseSchedules = createCourseScheduleDto.getCourseSchedules();

        if(!CollectionUtils.isEmpty(courseSchedules)){
			List<ClassGroupTeacherMapper> byMusicGroup = classGroupTeacherMapperDao.findAllByMusicGroup(createCourseScheduleDto.getMusicGroupID(),courseSchedules.get(0).getGroupType(),null);
			Map<Integer, List<ClassGroupTeacherMapper>> teacherByClassGroup = byMusicGroup.stream().collect(Collectors.groupingBy(ClassGroupTeacherMapper::getClassGroupId));

			Map<Integer, List<CourseSchedule>> classGroupCourseSchedules = courseSchedules.stream().collect(Collectors.groupingBy(CourseSchedule::getClassGroupId));
			for (Map.Entry<Integer, List<CourseSchedule>> classGroupCoursesEntry : classGroupCourseSchedules.entrySet()) {
				List<ClassGroupTeacherMapper> classGroupTeacherMappers = teacherByClassGroup.get(classGroupCoursesEntry.getKey());
				Set<Integer> teachingTeacherIds = classGroupTeacherMappers.stream().filter(t -> TeachTypeEnum.TEACHING.equals(t.getTeacherRole())).map(ClassGroupTeacherMapper::getUserId).collect(Collectors.toSet());
				classGroupCoursesEntry.getValue().sort(Comparator.comparing(CourseSchedule::getStartClassTime));
				for(int i=0;i<classGroupCoursesEntry.getValue().size();i++){
					classGroupCoursesEntry.getValue().get(i).setTeachingTeacherIdList(new ArrayList<>(teachingTeacherIds));
					if(i==0){
						continue;
					}
					CourseSchedule c1=classGroupCoursesEntry.getValue().get(i-1);
					CourseSchedule c2=classGroupCoursesEntry.getValue().get(i);
					if(c1.getStartClassTime().compareTo(c2.getEndClassTime())<0
						&&c1.getEndClassTime().compareTo(c2.getStartClassTime())>0){
						throw new BizException("排课循环周期时间存在重叠");
					}
				}
//				for (CourseSchedule courseSchedule : classGroupCoursesEntry.getValue()) {
//					courseSchedule.setTeachingTeacherIdList(new ArrayList<>(teachingTeacherIds));
//				}
				//添加课程计划
				batchAddCourseSchedule(classGroupCoursesEntry.getValue());
				//创建学生单节课的缴费记录，乐团课的缴费为0
				courseScheduleStudentPaymentService.createCourseScheduleStudentPaymentByCourseSchedules(classGroupCoursesEntry.getValue());
				classGroupTeacherMapperService.initCourseScheduleTeacherSalary(classGroupCoursesEntry.getValue(),classGroupTeacherMappers);
			}
			List<Long> courseScheduleIds = courseSchedules.stream().map(CourseSchedule::getId).collect(Collectors.toList());
			courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
            //更新课次
            List<Integer> classGroupIds = courseSchedules.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
            classGroupService.batchUpdateClassCourseTimes(classGroupIds);
        }

        MusicGroup musicGroup = musicGroupService.get(createCourseScheduleDto.getMusicGroupID());

        if (musicGroup.getStatus().equals(MusicGroupStatusEnum.PROGRESS)) {
            classGroupTeacherMapperService.createMusicGroupTeacherMapper(createCourseScheduleDto.getCourseSchedules(), musicGroup.getId());
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
	public boolean batchUpdateCourseSchedule(BatchInsertCoursesDto batchInsertCoursesDto) {

		List<CourseSchedule> courseScheduleList = courseScheduleDao.findByCourseScheduleIds(batchInsertCoursesDto.getCourseScheduleIdList());
		List<Integer> classGroupList = courseScheduleList.stream().map(CourseSchedule::getClassGroupId).distinct().collect(Collectors.toList());

		if (classGroupList == null || classGroupList.size() != 1) {
			throw new BizException("修改失败，只支持同一个班级的课程批量调整");
		}

		Integer classGroupId = classGroupList.get(0);
		String musicGroupId = courseScheduleList.get(0).getMusicGroupId();

		// 批量删课
		List<Long> courseScheduleIds = batchInsertCoursesDto.getCourseScheduleIdList();

		// 学生已点名不能调整（请假可以调整）
		for (Long courseScheduleId : courseScheduleIds) {
			List<StudentAttendance> studentAttendanceList = studentAttendanceDao.findByCourseId(courseScheduleId);

			for (StudentAttendance studentAttendance : studentAttendanceList) {
				if (studentAttendance.getStatus() != null && studentAttendance.getStatus() != StudentAttendanceStatusEnum.LEAVE) {
					throw new BizException("操作失败，存在已点名课程");
				}
			}
		}

		courseScheduleDao.batchDeleteAllCourseSchedules(courseScheduleIds);
		courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
		courseScheduleStudentPaymentDao.deleteByCourseSchedule(courseScheduleIds);
		// 删除考勤
		teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
		studentAttendanceDao.deleteByCourseSchedules(courseScheduleIds);

		// 删除作业
		courseHomeworkService.delHomwworkByCourseScheduleId(courseScheduleIds);
		//删除评论
		courseScheduleReviewDao.delByCourseScheduleIds(courseScheduleIds);
		//删除申述
		courseScheduleComplaintsDao.delByCourseScheduleIds(courseScheduleIds);

		Date endDate = null;
		Date startDate = null;
		if (batchInsertCoursesDto.getType() == CourseScheduleType.PRACTICE) {
			PracticeGroup practiceGroup = practiceGroupDao.get(Long.parseLong(musicGroupId));
			if (practiceGroup == null) {
				throw new BizException("找不到课程组[{}]信息", musicGroupId);
			}
			endDate = practiceGroup.getCoursesExpireDate();
			startDate = practiceGroup.getCoursesStartDate();
		}

		// 批量加课
		batchAddCourseSchedule(classGroupId, batchInsertCoursesDto.getCourseScheduleIdList().size(), batchInsertCoursesDto.getStartDate(), endDate, startDate,
				batchInsertCoursesDto.getTeachingArrangementList(), batchInsertCoursesDto.getTeachMode(), batchInsertCoursesDto.getType(),
				batchInsertCoursesDto.getSchoolId(), batchInsertCoursesDto.getIsJumpHoliday());
		return true;
	}

	@Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAddCourseSchedule(List<CourseSchedule> courseSchedules) {
        if (Objects.isNull(courseSchedules) && courseSchedules.size() <= 0) {
            throw new BizException("参数错误!");
        }
        checkNewCourseSchedules(courseSchedules, false,false);
        createCourseScheduleName(courseSchedules);
        courseScheduleDao.batchAddCourseSchedules(courseSchedules);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdateCourseSchedule(List<CourseSchedule> courseSchedules, String musicGroupID) {
        if (Objects.isNull(courseSchedules) && courseSchedules.size() <= 0) {
            throw new BizException("请选择需要调整的课程!");
        }
        if (Objects.isNull(musicGroupID)) {
            throw new BizException("请指定乐团!");
        }
        checkNewCourseSchedules(courseSchedules, false,false);
        courseScheduleDao.deleteCourseSchedulesByMusicGroupID(musicGroupID, GroupType.MUSIC);
        courseScheduleDao.batchAddCourseSchedules(courseSchedules);
    }

    @Override
    public List<Date> getCourseScheduleDateByMonth(Long musicGroupID, Date month) {
        if (Objects.isNull(month) || Objects.isNull(musicGroupID)) {
            throw new BizException("请选择日期并指定乐团!");
        }
        return courseScheduleDao.getCourseScheduleDateByMonth(musicGroupID, month);
    }

    @Override
    public List<Date> getCourseScheduleDateByStudent(Date month, Integer isAttend) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        return courseScheduleDao.getStudentCourseScheduleDate(user.getId().longValue(), month, isAttend);
    }

    @Override
    public List<Date> getCourseScheduleDateByTeacher(Date month, String type) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        return courseScheduleDao.getTeacherCourseScheduleDate(user.getId().longValue(), month, type);
    }

    @Override
    public List<Date> getHistoryCourseScheduleDateByTeacher(Integer userId, Date month) {
        return courseScheduleDao.getTeacherHistoryCourseScheduleDate(userId, month);
    }

    @Override
    public List<Date> getCourseScheduleDates(Date month, String organIdList, String type) {
		Map<String, Object> params = new HashMap<>();
		params.put("organIdList", organIdList);

		List<Group> groups = groupDao.searchGroups(params);
		List<Integer> classGroupIds=new ArrayList<>();
		if(!CollectionUtils.isEmpty(groups)){
			Map<GroupType, List<Group>> groupTypeGroupsMap = groups.stream().collect(Collectors.groupingBy(Group::getGroupType));
			for (Map.Entry<GroupType, List<Group>> groupTypeListEntry : groupTypeGroupsMap.entrySet()) {
				List<String> groupIds = groupTypeListEntry.getValue().stream().map(Group::getId).collect(Collectors.toList());
				List<ClassGroup> classGroups = classGroupDao.findByMusicGroupsAndType(groupIds, groupTypeListEntry.getKey().getCode());
				if(!CollectionUtils.isEmpty(classGroups)){
					List<Integer> tempClassGroupIds=classGroups.stream().map(ClassGroup::getId).collect(Collectors.toList());
					classGroupIds.addAll(tempClassGroupIds);
				}
			}
			if(CollectionUtils.isEmpty(classGroupIds)){
				return Collections.EMPTY_LIST;
			}
		}else{
			return Collections.EMPTY_LIST;
		}
        return courseScheduleDao.getCourseScheduleDate(month, classGroupIds,type);
    }

    @Override
    public Map getStudentCourseSchedulesWithDate(Date classDate) {
        if (Objects.isNull(classDate)) {
            throw new BizException("请选择上课日期!");
        }
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("请登录");
        }
        Date now = new Date();
        SysConfig studentAttendanceAfterTimeConfig = sysConfigService.findByParamName(SysConfigService.ENABLE_STUDENT_ATTENDANCE_BEFOR_COURSE_START_TIME_RANGE_VIP);
		SysConfig courseBeforeBufferTime = sysConfigService.findByParamName(SysConfigService.COURSE_BEFORE_BUFFER_TIME);
		SysConfig courseAfterBufferTime = sysConfigService.findByParamName(SysConfigService.COURSE_AFTER_BUFFER_TIME);
        Map<String, Object> result = new HashMap<>(3);
        result.put("vipAppealDaysRange", sysConfigDao.findConfigValue(SysConfigService.VIP_APPEAL_DAYS_RANGE));
        result.put("advanceLeaveHours", Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ADVANCE_LEAVE_HOURS)));
        result.put("earliestTimeForLeave", Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.EARLIEST_TIME_FOR_LEAVE)));
        result.put("joinRoomBeforeTime",studentAttendanceAfterTimeConfig.getParanValue(Integer.class));
		result.put("courseBeforeBufferTime", courseBeforeBufferTime.getParanValue(Integer.class));
		result.put("courseAfterBufferTime", courseAfterBufferTime.getParanValue(Integer.class));
//		List<Integer> quitClassGroupIds=classGroupStudentMapperDao.findClassGroupIdByUserAndCourseDateAndStatus(user.getId(),classDate, ClassGroupStudentStatusEnum.QUIT.getCode());
        List<CourseScheduleDto> studentCourseSchedulesWithDate = courseScheduleDao.getStudentCourseSchedulesWithDate(classDate, user.getId().longValue(), null);
        List<Long> courseScheduleIds = studentCourseSchedulesWithDate.stream()
                .filter(cs -> cs.getType().equals(CourseSchedule.CourseScheduleType.VIP) || cs.getType().equals(CourseSchedule.CourseScheduleType.DEMO) || cs.getType().equals(CourseScheduleType.PRACTICE) || cs.getType().equals(CourseScheduleType.COMM))
                .map(CourseScheduleDto::getId).collect(Collectors.toList());

        Map<Integer, String> subjectNameCourseMap = new HashMap<>();
        Map<Integer, String> subjectIdCourseMap = new HashMap<>();
        Map<Integer, Integer> reviewIdMap = new HashMap<>();
        Map<Long, Long> StudentReviewIdMap = new HashMap<>();

        if (!CollectionUtils.isEmpty(courseScheduleIds)) {
            List<Map<Integer, String>> subjectNameCourseMaps = subjectDao.findSubjectNameCourseMaps(courseScheduleIds);
            List<Map<Integer, String>> subjectIdCourseMaps = subjectDao.findClassGroupSubjectId(courseScheduleIds);
            subjectNameCourseMap = MapUtil.convertMybatisMap(subjectNameCourseMaps);
            subjectIdCourseMap = MapUtil.convertMybatisMap(subjectIdCourseMaps);
			List<CourseScheduleReview> reviews = courseScheduleReviewDao.findByCourseSchedulesAndStudentId(courseScheduleIds, user.getId());
			reviewIdMap = reviews.stream().collect(Collectors.toMap(CourseScheduleReview::getCourseScheduleId, CourseScheduleReview::getId));
			List<CourseScheduleComplaints> studentReviews = courseScheduleComplaintsDao.findByCourseIdAndUserId(courseScheduleIds, user.getId());
			StudentReviewIdMap = studentReviews.stream().collect(Collectors.toMap(CourseScheduleComplaints::getCourseScheduleId, CourseScheduleComplaints::getId));
		}

        for (CourseScheduleDto courseScheduleDto : studentCourseSchedulesWithDate) {
            if (now.before(courseScheduleDto.getStartClassTime())) {
                courseScheduleDto.setStatus(CourseStatusEnum.NOT_START);
            } else if (now.after(courseScheduleDto.getEndClassTime())) {
                courseScheduleDto.setStatus(CourseStatusEnum.OVER);
            } else {
                courseScheduleDto.setStatus(CourseStatusEnum.UNDERWAY);
            }
            courseScheduleDto.setSubjectName(subjectNameCourseMap.get(courseScheduleDto.getId().intValue()));
            courseScheduleDto.setSubjectId(subjectIdCourseMap.get(courseScheduleDto.getId().intValue()));
			courseScheduleDto.setReviewId(reviewIdMap.get(courseScheduleDto.getId().intValue()));
			courseScheduleDto.setStudentReviewId(StudentReviewIdMap.get(courseScheduleDto.getId()));
        }
        result.put("list", studentCourseSchedulesWithDate);
        return result;
    }

    @Override
    public PageInfo getCourseSchedulesWithDateByEdu(CourseScheduleQueryInfo queryInfo) {
//        queryInfo.setOrganId(Long.parseLong(user.getOrganId()));
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

        if (Objects.isNull(queryInfo.getDate())) {
            queryInfo.setDate(new Date());
        }

        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);

        params.put("musicGroupStatus", null);
        params.put("vipGroupStatus", null);
        List<Group> groups = groupDao.searchGroups(params);
        if(!CollectionUtils.isEmpty(groups)){
            Map<GroupType, List<Group>> groupTypeGroupsMap = groups.stream().collect(Collectors.groupingBy(Group::getGroupType));
            List<Integer> classGroupIds=new ArrayList<>();
            for (Map.Entry<GroupType, List<Group>> groupTypeListEntry : groupTypeGroupsMap.entrySet()) {
                List<String> groupIds = groupTypeListEntry.getValue().stream().map(Group::getId).collect(Collectors.toList());
                List<ClassGroup> classGroups = classGroupDao.findByMusicGroupsAndType(groupIds, groupTypeListEntry.getKey().getCode());
                if(!CollectionUtils.isEmpty(classGroups)){
                    List<Integer> tempClassGroupIds=classGroups.stream().map(ClassGroup::getId).collect(Collectors.toList());
                    classGroupIds.addAll(tempClassGroupIds);
                }
            }
            if(CollectionUtils.isEmpty(classGroupIds)){
                return pageInfo;
            }
            params.put("classGroupIds", classGroupIds);
        }else{
            return pageInfo;
        }

        List<CourseScheduleDto> dataList = null;
        int count = courseScheduleDao.countCourseSchedulesWithDate(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = courseScheduleDao.getCourseSchedulesWithDate(params);
            List<Long> allCourseScheduleIds = dataList.stream().map(CourseScheduleDto::getId).collect(Collectors.toList());
            List<Map<Integer, Integer>> courseStudentNumMaps = courseScheduleStudentPaymentDao.countCourseStudentNum(allCourseScheduleIds);
            Map<Long, Long> courseStudentNumMap = MapUtil.convertIntegerMap(courseStudentNumMaps);

			List<StudentAttendance> studentAttendances = studentAttendanceDao.getWithCoursesAndExcludeQuitStudent(allCourseScheduleIds);
			Map<Long, List<StudentAttendance>> courseStudentAttendanceMap = studentAttendances.stream().collect(Collectors.groupingBy(StudentAttendance::getCourseScheduleId));

			List<Integer> teacherIds=new ArrayList<>();
            for (CourseScheduleDto courseScheduleEndDto : dataList) {
                teacherIds.add(courseScheduleEndDto.getActualTeacherId());
            }

			List<Integer> classGroupIds = dataList.stream().map(CourseScheduleDto::getClassGroupId).collect(Collectors.toList());
			List<Group> groupsT = groupDao.findByClassGroupIds(classGroupIds);
            Map<Integer, Group> idGroupMap = groupsT.stream().collect(Collectors.toMap(Group::getClassGroupId, group -> group));

            for (int i=0;i<dataList.size();i++) {
                Long studentNum=courseStudentNumMap.get(dataList.get(i).getId());
                dataList.get(i).setTotalStudentNum(Objects.isNull(studentNum)?0:studentNum.intValue());
                Group group = idGroupMap.get(dataList.get(i).getClassGroupId());
                if(Objects.nonNull(group)){
                    dataList.get(i).setGroupName(group.getGroupName());
                }
				dataList.get(i).setLeaveStudentNum(0);
				dataList.get(i).setStudentNum(0);
                if(courseStudentAttendanceMap.containsKey(dataList.get(i).getId())){
					List<StudentAttendance> courseStudentAttendances = courseStudentAttendanceMap.get(dataList.get(i).getId());
					dataList.get(i).setLeaveStudentNum((int) courseStudentAttendances.stream().filter(s->StudentAttendanceStatusEnum.LEAVE.equals(s.getStatus())).count());
					dataList.get(i).setStudentNum((int) courseStudentAttendances.stream().filter(s->StudentAttendanceStatusEnum.NORMAL.equals(s.getStatus())).count());
				}
            }
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public List<CourseScheduleDto> getTeacherCourseSchedulesWithDate(Integer userId, Date classDate, String type) {
        if (Objects.isNull(classDate)) {
            throw new BizException("请选择上课日期!");
        }
        Date now = new Date();
        List<CourseScheduleDto> teacherCourseSchedulesWithDate = courseScheduleDao.getTeacherCourseSchedulesWithDate(classDate, userId.longValue(), type);
        List<Long> allCourseScheduleIds = teacherCourseSchedulesWithDate.stream().map(CourseScheduleDto::getId).collect(Collectors.toList());
        List<Long> courseScheduleIds = teacherCourseSchedulesWithDate.stream()
                .filter(cs -> cs.getType().equals(CourseSchedule.CourseScheduleType.VIP) ||
                        cs.getType().equals(CourseSchedule.CourseScheduleType.DEMO) ||
                        cs.getType().equals(CourseSchedule.CourseScheduleType.PRACTICE) ||
						cs.getType().equals(CourseScheduleType.COMM))
                .map(CourseScheduleDto::getId).collect(Collectors.toList());

        Map<Integer, String> subjectNameCourseMap = new HashMap<>();
        Map<Integer, String> subjectIdCourseMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(courseScheduleIds)) {
            List<Map<Integer, String>> subjectNameCourseMaps = subjectDao.findSubjectNameCourseMaps(courseScheduleIds);
            List<Map<Integer, String>> subjectIdCourseMaps = subjectDao.findClassGroupSubjectId(courseScheduleIds);
            subjectNameCourseMap = MapUtil.convertMybatisMap(subjectNameCourseMaps);
            subjectIdCourseMap = MapUtil.convertMybatisMap(subjectIdCourseMaps);
        }
        List<Map<Integer, Integer>> studentNumCourseMaps = null;
        if (!CollectionUtils.isEmpty(allCourseScheduleIds)) {
            studentNumCourseMaps = studentAttendanceDao.countStudentAttendancesByCourses(allCourseScheduleIds);
        }
        Map<Integer, Long> studentNumCourseMap = new HashMap<>();
        if (Objects.nonNull(studentNumCourseMaps)) {
            studentNumCourseMap = MapUtil.convertIntegerMap(studentNumCourseMaps);
        }

        if(CollectionUtils.isEmpty(teacherCourseSchedulesWithDate)){
            return teacherCourseSchedulesWithDate;
        }

        List<Integer> classGroupIds = teacherCourseSchedulesWithDate.stream().map(CourseScheduleDto::getClassGroupId).collect(Collectors.toList());
        List<Map<Integer, Integer>> classGroupStudentNumMaps = classGroupStudentMapperDao.countClassGroupsStudentNum(classGroupIds, ClassGroupStudentStatusEnum.NORMAL);
        Map<Integer, Long> classGroupStudentNumMap = MapUtil.convertIntegerMap(classGroupStudentNumMaps);

        SysConfig advanceLeaveHoursConfig = sysConfigService.findByParamName(SysConfigService.ADVANCE_LEAVE_HOURS);
        Integer advanceLeaveHours=advanceLeaveHoursConfig.getParanValue(Integer.class);
        List<Map<Long, Integer>> courseLeaveStudentNumMaps = studentAttendanceDao.countCourseLeaveStudentNumWithFourHoursAgo(allCourseScheduleIds, advanceLeaveHours);
        Map<Long,Long> courseLeaveStudentNumMap = MapUtil.convertIntegerMap((courseLeaveStudentNumMaps));

		List<CourseScheduleReview> AllCourseScheduleReviews = courseScheduleReviewDao.findByCourseSchedules(allCourseScheduleIds);
		Map<Integer, List<CourseScheduleReview>> idCourseReview=new HashMap<>();
		if(!CollectionUtils.isEmpty(AllCourseScheduleReviews)){
			idCourseReview=AllCourseScheduleReviews.stream().collect(Collectors.groupingBy(CourseScheduleReview::getCourseScheduleId));
		}

		for (CourseScheduleDto courseScheduleDto : teacherCourseSchedulesWithDate) {
            Long studentNum = studentNumCourseMap.get(courseScheduleDto.getId());
            if (Objects.nonNull(studentNum)) {
                courseScheduleDto.setStudentAttendanceIsFirstTime(studentNum > 0 ? 0 : 1);
            } else {
                courseScheduleDto.setStudentAttendanceIsFirstTime(1);
            }

            if (now.before(courseScheduleDto.getStartClassTime())) {
                courseScheduleDto.setStatus(CourseStatusEnum.NOT_START);
            } else if (now.after(courseScheduleDto.getEndClassTime())) {
                courseScheduleDto.setStatus(CourseStatusEnum.OVER);
            } else {
                courseScheduleDto.setStatus(CourseStatusEnum.UNDERWAY);
            }
            if (Objects.nonNull(courseScheduleDto.getClassGroupId())) {
//                String[] studentNames = classGroupStudentMapperDao.findCourseStudentName(courseScheduleDto.getId().intValue());
                List<StudentNameAndPhoneDto> courseStudentNameAndPhone = classGroupStudentMapperDao.findCourseStudentNameAndPhone(courseScheduleDto.getId().intValue());
                if(!CollectionUtils.isEmpty(courseStudentNameAndPhone)){
                    List<String> studentNames = courseStudentNameAndPhone.stream().filter(s->Objects.nonNull(s)&&Objects.nonNull(s.getUserName())).map(StudentNameAndPhoneDto::getUserName).collect(Collectors.toList());
                    courseScheduleDto.setStudentNames(org.apache.commons.lang3.StringUtils.join(studentNames, ","));
                    courseScheduleDto.setStudents(courseStudentNameAndPhone);
                }
            }
            courseScheduleDto.setSubjectName(subjectNameCourseMap.get(courseScheduleDto.getId()));
            courseScheduleDto.setSubjectId(subjectIdCourseMap.get(courseScheduleDto.getId()));
            Long leaveStudentNum = courseLeaveStudentNumMap.get(courseScheduleDto.getId());
            Long normalStudentNum = classGroupStudentNumMap.get(courseScheduleDto.getClassGroupId());
            if(Objects.nonNull(leaveStudentNum)&&Objects.nonNull(normalStudentNum)&&leaveStudentNum.intValue()==normalStudentNum.intValue()){
                courseScheduleDto.setEnableAdjustInToday(1);
            }
			List<CourseScheduleReview> courseScheduleReviews = idCourseReview.get(courseScheduleDto.getId().intValue());
            if(!CollectionUtils.isEmpty(courseScheduleReviews)){
				courseScheduleDto.setComplaintsStatus(1);
				CourseScheduleReview courseScheduleReview = courseScheduleReviews.get(0);
				courseScheduleDto.setReviewId(courseScheduleReview.getId());
			}else{
            	courseScheduleDto.setComplaintsStatus(0);
			}
		}
        return teacherCourseSchedulesWithDate;
    }

    @Override
    public List<CourseScheduleDto> getTeacherHistoryCourseSchedulesWithDate(Integer userId, Date classDate) {
        if (Objects.isNull(classDate)) {
            throw new BizException("请选择上课日期!");
        }
        List<CourseScheduleDto> teacherCourseSchedulesWithDate = courseScheduleDao.getTeacherHistoryCourseSchedulesWithDate(classDate, userId.longValue());
        List<Long> courseScheduleIds = teacherCourseSchedulesWithDate.stream()
                .filter(cs -> cs.getType().equals(CourseSchedule.CourseScheduleType.VIP) || cs.getType().equals(CourseSchedule.CourseScheduleType.DEMO))
                .map(CourseScheduleDto::getId).collect(Collectors.toList());

        Map<Integer, String> subjectNameCourseMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(courseScheduleIds)) {
            List<Map<Integer, String>> subjectNameCourseMaps = subjectDao.findSubjectNameCourseMaps(courseScheduleIds);
            subjectNameCourseMap = MapUtil.convertMybatisMap(subjectNameCourseMaps);
        }
        for (CourseScheduleDto courseScheduleDto : teacherCourseSchedulesWithDate) {
            if (Objects.nonNull(courseScheduleDto.getClassGroupId())) {
                String[] studentNums = classGroupStudentMapperDao.findCourseStudentName(courseScheduleDto.getId().intValue());
                courseScheduleDto.setStudentNames(org.apache.commons.lang3.StringUtils.join(studentNums, ","));
            }
            courseScheduleDto.setSubjectName(subjectNameCourseMap.get(courseScheduleDto.getId()));
        }
        return teacherCourseSchedulesWithDate;
    }

//    @Override
//    public void checkNewCourseSchedules(List<CourseSchedule> courseSchedules, boolean checkExistCourseSchedule) {
//        if (CollectionUtils.isEmpty(courseSchedules)) {
//            return;
//        }
//        List<String> classDates = courseSchedules.stream().map(courseSchedule -> DateUtil.dateToString(courseSchedule.getClassDate(), "yyyy-MM-dd"))
//                .collect(Collectors.toList());
//
//        List<CourseSchedule> existCourseSchedules = courseScheduleDao.findByClassDate(classDates);
//
//        //只需要调整课程信息的课程编号列表
//        List<Long> updateCourseScheduleIds = courseSchedules
//                .stream()
//                .filter(courseSchedule -> Objects.nonNull(courseSchedule.getId()))
//                .map(CourseSchedule::getId)
//                .collect(Collectors.toList());
//
//        //排除只需调整的课程
//        existCourseSchedules = existCourseSchedules.stream()
//                .filter(courseSchedule -> !updateCourseScheduleIds.contains(courseSchedule.getId()))
//                .collect(Collectors.toList());
//        //新课程对应的班级编号列表
//        List<Integer> newCourseScheduleClassGroupIds = courseSchedules
//                .stream()
//                .map(CourseSchedule::getClassGroupId)
//                .distinct()
//                .collect(Collectors.toList());
//
//        List<Long> existCourseScheduleIds = existCourseSchedules.stream()
//                .map(CourseSchedule::getId)
//                .collect(Collectors.toList());
//
//        HashSet<Long> courseScheduleIdsSet = new HashSet<>(existCourseScheduleIds);
//
//        //合并新课程和已存在的课程
//        List<CourseSchedule> allCourseSchedules;
//        if (!CollectionUtils.isEmpty(existCourseSchedules)) {
//            allCourseSchedules = ListUtils.sum(courseSchedules, existCourseSchedules);
//        } else {
//            allCourseSchedules = courseSchedules;
//        }
//        //所有课程的班级编号
//        List<Integer> classGroupIds = allCourseSchedules
//                .stream()
//                .map(CourseSchedule::getClassGroupId)
//                .distinct()
//                .collect(Collectors.toList());
//        //班级与学生的关联记录
//        List<ClassGroupStudentMapper> classGroupStudentMappers = classGroupStudentMapperDao.findByClassGroups(classGroupIds);
//        Map<Integer, List<ClassGroupStudentMapper>> classGroupStudentsMap = classGroupStudentMappers
//                .stream()
//                .collect(Collectors.groupingBy(ClassGroupStudentMapper::getClassGroupId));
//
//        //根据课程获取助教id关联集合
//        List<IntegerAndIntegerListDto> courseScheduleTeachingTeacherIdList = new ArrayList<>();
//        if (!CollectionUtils.isEmpty(existCourseScheduleIds)) {
//            courseScheduleTeachingTeacherIdList = courseScheduleDao.findCourseScheduleIdAndUserIdsMap(existCourseScheduleIds, TeachTypeEnum.TEACHING.getCode());
//        }
//        Map<Integer, IntegerAndIntegerListDto> courseScheduleTeachingTeacherMap = courseScheduleTeachingTeacherIdList.stream()
//                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));
//
//        //班级助教关联ID集合
//        List<IntegerAndIntegerListDto> classGroupAndUserIdsMap = courseScheduleDao.findClassGroupAndUserIdsMap(newCourseScheduleClassGroupIds, TeachTypeEnum.TEACHING.getCode());
//        Map<Integer, IntegerAndIntegerListDto> classGroupTeachingTeacherMap = classGroupAndUserIdsMap.stream()
//                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));
//
//        //将课程计划按照开课时间排序
//        allCourseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
//        if (allCourseSchedules.size() > 1) {
//            //记录连续冲突的次数
//            int repeatTimes = 1;
//            for (int i = 1; i < allCourseSchedules.size(); i++) {
//                int temp_repeat = repeatTimes;
//                for (int j = 1; j <= temp_repeat; j++) {
//                    //当前课程
//                    CourseSchedule preCourseSchedule = allCourseSchedules.get(i - j);
//                    //后面一节课程
//                    CourseSchedule backCourseSchedule = allCourseSchedules.get(i);
//                    //判断前后两节课是否存在冲突
//                    if (backCourseSchedule.getStartClassTime().before(preCourseSchedule.getEndClassTime())) {
//                        if (j == repeatTimes) {
//                            repeatTimes += 1;
//                        }
//                        if (!checkExistCourseSchedule
//                                && courseScheduleIdsSet.contains(preCourseSchedule.getId())
//                                && courseScheduleIdsSet.contains(backCourseSchedule.getId())) {
//                            continue;
//                        }
//
//                        //如果存在时间重叠，则需要判断前后两节课的教师和学生是否存在冲突
//                        //主教冲突检测
//                        if (Objects.nonNull(preCourseSchedule.getActualTeacherId())
//                                && preCourseSchedule.getActualTeacherId().equals(backCourseSchedule.getActualTeacherId())) {
//
//                            throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 1));
//                        }
//                        //助教冲突检测
//                        if (Objects.isNull(preCourseSchedule.getId())) {
//                            IntegerAndIntegerListDto integerAndIntegerListDto = classGroupTeachingTeacherMap.get(preCourseSchedule.getClassGroupId());
//                            if (Objects.nonNull(integerAndIntegerListDto)) {
//                                preCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
//                            }
//                        } else if (existCourseScheduleIds.contains(preCourseSchedule.getId())) {
//                            IntegerAndIntegerListDto integerAndIntegerListDto = courseScheduleTeachingTeacherMap.get(preCourseSchedule.getId());
//                            if (Objects.nonNull(integerAndIntegerListDto)) {
//                                preCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
//                            }
//                        }
//                        if (Objects.isNull(backCourseSchedule.getId())) {
//                            IntegerAndIntegerListDto integerAndIntegerListDto = classGroupTeachingTeacherMap.get(backCourseSchedule.getClassGroupId());
//                            if (Objects.nonNull(integerAndIntegerListDto)) {
//                                backCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
//                            }
//                        } else if (existCourseScheduleIds.contains(backCourseSchedule.getId())) {
//                            IntegerAndIntegerListDto integerAndIntegerListDto = courseScheduleTeachingTeacherMap.get(backCourseSchedule.getId());
//                            if (Objects.nonNull(integerAndIntegerListDto)) {
//                                backCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
//                            }
//                        }
//                        if (!CollectionUtils.isEmpty(preCourseSchedule.getTeachingTeacherIdList())
//                                && !CollectionUtils.isEmpty(backCourseSchedule.getTeachingTeacherIdList())) {
//                            List<Integer> repeatIds = preCourseSchedule.getTeachingTeacherIdList()
//                                    .stream().filter(backCourseSchedule.getTeachingTeacherIdList()::contains)
//                                    .collect(Collectors.toList());
//                            if (!CollectionUtils.isEmpty(repeatIds)) {
//                                throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 2));
//                            }
//                        }
//                        //学生冲突检测
//                        if (preCourseSchedule.getClassGroupId().equals(backCourseSchedule.getClassGroupId())) {
//                            //如果班级相同，则学生肯定存在冲突
//                            throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 3));
//                        }
//                        //如果班级不同，则需要检测两个班级是否存在重复的学生
//                        List<ClassGroupStudentMapper> preClassGroupStudents = classGroupStudentsMap.get(preCourseSchedule.getClassGroupId());
//                        List<ClassGroupStudentMapper> backClassGroupStudents = classGroupStudentsMap.get(backCourseSchedule.getClassGroupId());
//                        //如果有一个存在没有学生的班级则不存在冲突
//                        if (CollectionUtils.isEmpty(preClassGroupStudents) || CollectionUtils.isEmpty(backClassGroupStudents)) {
//                            continue;
//                        }
//                        //当前课程所在班级的学生编号列表
//                        List<Integer> preClassGroupStudentIds = preClassGroupStudents.stream()
//                                .map(ClassGroupStudentMapper::getUserId)
//                                .collect(Collectors.toList());
//                        //后面一节课程所在班级的学生编号列表
//                        List<Integer> backClassGroupStudentIds = backClassGroupStudents.stream()
//                                .map(ClassGroupStudentMapper::getUserId)
//                                .collect(Collectors.toList());
//                        List<Integer> repeatStudentIds = preClassGroupStudentIds.stream()
//                                .filter(backClassGroupStudentIds::contains)
//                                .collect(Collectors.toList());
//                        if (!CollectionUtils.isEmpty(repeatStudentIds)) {
//                            throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 3));
//                        }
//                    } else {
//                        repeatTimes = j;
//                        break;
//                    }
//                }
//            }
//        }
//    }


	@Override
	public void courseAdjustOnlyWithClassDate(List<CourseSchedule> courseSchedules, Integer operatorId) {
    	if(CollectionUtils.isEmpty(courseSchedules)){
    		throw new BizException("请指定课程");
		}
		Map<Long, CourseSchedule> idCourseMap = courseSchedules.stream().collect(Collectors.toMap(CourseSchedule::getId, c -> c));
		List<Long> courseIds = courseSchedules.stream().map(CourseSchedule::getId).collect(Collectors.toList());
		List<CourseSchedule> existCourses = courseScheduleDao.findByCourseScheduleIds(courseIds);
		Date now = new Date();

		SysUser sysUser = sysUserFeignService.queryUserInfo();
		if (null == sysUser) {
			throw new BizException("获取用户信息失败");
		}

		//获取操作日志
		List<CourseScheduleModifyLog> modifyLogs = getModifyLogs(courseIds,existCourses,sysUser.getId(),now);

		for (CourseSchedule existCours : existCourses) {
			CourseSchedule ac = idCourseMap.get(existCours.getId());

			if(now.compareTo(ac.getStartClassTime())>0){
				throw new BizException("课程调整时间不得小于当前时间");
			}

			int singleClassMinutes = DateUtil.minutesBetween(existCours.getStartClassTime(), existCours.getEndClassTime());

			existCours.setClassDate(ac.getClassDate());
			existCours.setUpdateTime(now);
			existCours.setStartClassTime(ac.getStartClassTime());
			existCours.setEndClassTime(DateUtil.addMinutes(existCours.getStartClassTime(), singleClassMinutes));
		}

		Date startDateTime = existCourses.stream().min(Comparator.comparing(CourseSchedule::getStartClassTime)).get().getStartClassTime();
		Date endDateTime = existCourses.stream().min(Comparator.comparing(CourseSchedule::getEndClassTime)).get().getEndClassTime();
		if(PRACTICE.equals(existCourses.get(0).getGroupType())){
			PracticeGroup practiceGroup = practiceGroupDao.get(Long.valueOf(existCourses.get(0).getMusicGroupId()));
			if(practiceGroup.getType() != TRIAL){
				if(DateUtil.minutesBetween(startDateTime,practiceGroup.getCoursesStartDate()) > 0){
					throw new BizException("调整失败: 调整时间不得早于开课时间");
				}
				if(DateUtil.minutesBetween(practiceGroup.getCoursesExpireDate(),endDateTime) > 0){
					throw new BizException("调整失败: 截止时间超过课程有效期");
				}
			}
		}

		checkNewCourseSchedules(existCourses, false,false);
		courseScheduleDao.batchUpdate(existCourses);

		studentAttendanceDao.deleteByCourseSchedules(courseIds);
		//删除作业
		courseHomeworkService.delHomwworkByCourseScheduleId(courseIds);
		//删除评论
		courseScheduleReviewDao.delByCourseScheduleIds(courseIds);
		//删除申述
		courseScheduleComplaintsDao.delByCourseScheduleIds(courseIds);
		//清除考勤申述
		teacherAttendanceDao.clearAttendanceComplaints(courseIds);
		//保存日志调整信息
		saveModifyLog(modifyLogs,courseIds);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, List<CourseSchedule>> courseAdjustOnlyWithClassDateCheck(VipGroupCourseAdjustInfoDto courseAdjustInfo) {
		if(StringUtils.isBlank(courseAdjustInfo.getCourseScheduleIds())){
			throw new BizException("请指定课程");
		}
		if(Objects.isNull(courseAdjustInfo.getCourseCreateStartTime())){
			throw new BizException("请指定课程调整起始时间");
		}
		if(Objects.isNull(courseAdjustInfo.getCourseTimes())){
			throw new BizException("请指定课程调整周期");
		}
		Date now=new Date();
		//所有课程编号
		List<Long> adjustCourseScheduleIds = Arrays.asList(courseAdjustInfo.getCourseScheduleIds().split(","))
				.stream().map(Long::parseLong).collect(Collectors.toList());
		//所有的课程
		List<CourseSchedule> courseSchedules = courseScheduleDao.findByCourseScheduleIds(adjustCourseScheduleIds);
		courseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
		if(adjustCourseScheduleIds.size()!=courseSchedules.size()){
			throw new BizException("部分课程不存在");
		}

		Map<Long, CourseSchedule> idCourseMap = courseSchedules.stream().collect(Collectors.toMap(CourseSchedule::getId, c -> {
			try {
				return (CourseSchedule)org.apache.commons.beanutils.BeanUtils.cloneBean(c);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			}
			return null;
		}));

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(courseAdjustInfo.getCourseCreateStartTime());
		List<Date> courseStartDates = new ArrayList<>();

		Set<String> holidayDays = new HashSet<>();

		if (courseAdjustInfo.isHoliday()) {
			SysConfig holidaySetting = sysConfigService.findByParamName(SysConfigService.HOLIDAY_SETTING);
			if(StringUtils.isNotBlank(holidaySetting.getParanValue())){
				holidayDays = new HashSet<>(JSON.parseArray(holidaySetting.getParanValue(), String.class));
			}
		}

		Map<String, List<CourseSchedule>> result = new HashMap<String, List<CourseSchedule>>(){{
			put("normal", new ArrayList<>());
			put("revise", new ArrayList<>());
			put("failed", new ArrayList<>());
		}};

		while (true) {
			if (courseAdjustInfo.isHoliday() && holidayDays.contains(DateUtil.format(calendar.getTime(), "yyyy-MM-dd"))) {
				calendar.add(Calendar.DATE, 1);
				continue;
			}
			int i = calendar.get(Calendar.DAY_OF_WEEK);
			if (i == 1) {
				i = 7;
			} else {
				i = i - 1;
			}
			for (CourseTimeDto courseTime : courseAdjustInfo.getCourseTimes()) {
				if (Objects.isNull(courseTime.getDayOfWeek())||StringUtils.isBlank(courseTime.getStartClassTime())) {
					throw new BizException("排课循环周期错误");
				}
				if (courseTime.getDayOfWeek() < 1 || courseTime.getDayOfWeek() > 7) {
					throw new BizException("排课循环周期错误");
				}
				if (courseTime.getDayOfWeek() == i) {
					String dateYmdStr = DateUtil.dateToString(calendar.getTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT);
					dateYmdStr = dateYmdStr + " " + courseTime.getStartClassTime();
					Date courseStartTime = DateUtil.stringToDate(dateYmdStr, "yyyy-MM-dd HH:mm");

					if(courseStartTime.compareTo(now)<=0){
						throw new BizException("课程调整时间不得小于当前时间");
					}

					courseStartDates.add(DateUtil.stringToDate(dateYmdStr, DateUtil.EXPANDED_DATE_TIME_FORMAT));
					CourseSchedule currentCourseSchedule = courseSchedules.get(courseStartDates.size() - 1);
					int singleClassMinutes = DateUtil.minutesBetween(currentCourseSchedule.getStartClassTime(), currentCourseSchedule.getEndClassTime());
					Date courseEndTime = DateUtil.addMinutes(courseStartTime, singleClassMinutes);
					int settlementNum = courseScheduleTeacherSalaryDao.checkCourseIsSettlement(courseSchedules.get(courseStartDates.size() - 1).getId().intValue());
					if (settlementNum > 0) {
						throw new BizException("{}[{}]{}-{}课程已结算",
								courseSchedules.get(courseStartDates.size() - 1).getName(),
								courseSchedules.get(courseStartDates.size() - 1).getId(),
								DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getStartClassTime(),
										DateUtil.ISO_EXPANDED_DATE_TIME_FORMAT),
								DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getEndClassTime(),
										DateUtil.ISO_EXPANDED_DATE_TIME_FORMAT));
					}
					int num = studentAttendanceDao.countStudentAttendenceNum(courseSchedules.get(courseStartDates.size() - 1).getId().intValue());
					if (num > 0) {
						throw new BizException("{}[{}]{}-{}课程已点名",
								courseSchedules.get(courseStartDates.size() - 1).getName(),
								courseSchedules.get(courseStartDates.size() - 1).getId(),
								DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getStartClassTime(),
										DateUtil.EXPANDED_DATE_TIME_FORMAT),
								DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getEndClassTime(),
										DateUtil.EXPANDED_DATE_TIME_FORMAT));
					}
					courseSchedules.get(courseStartDates.size() - 1).setStatus(CourseStatusEnum.NOT_START);
					courseSchedules.get(courseStartDates.size() - 1).setClassDate(courseStartTime);
					courseSchedules.get(courseStartDates.size() - 1).setStartClassTime(courseStartTime);
					courseSchedules.get(courseStartDates.size() - 1).setEndClassTime(courseEndTime);
				}
				if (courseStartDates.size() == adjustCourseScheduleIds.size()) {
					break;
				}
			}
			if (courseStartDates.size() == adjustCourseScheduleIds.size()) {
				break;
			}
			calendar.add(Calendar.DATE, 1);
		}
		for (CourseSchedule courseSchedule : courseSchedules) {
			boolean b = checkSingleCourseConflict(courseSchedule, courseSchedules, result);
			if(!b){
				result.get("failed").add(idCourseMap.get(courseSchedule.getId()));
			}
		}
		return result;
	}

	@Override
	public boolean courseTimeRevise(CourseSchedule courseSchedule, List<CourseSchedule> sameDayCourses) {
		int singleClassMinutes = DateUtil.minutesBetween(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime());
		sameDayCourses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
		Date lastEndClassTime = courseSchedule.getStartClassTime();

		for (int i=0;i<sameDayCourses.size();i++){
			CourseSchedule cs1 = sameDayCourses.get(i);
			if(cs1.getEndClassTime().compareTo(lastEndClassTime)>=0){
				lastEndClassTime = cs1.getEndClassTime();
			}

			if(i!=sameDayCourses.size()-1&&DateUtil.minutesBetween(lastEndClassTime, sameDayCourses.get(i + 1).getStartClassTime())>=singleClassMinutes+10){
				break;
			}
		}

		lastEndClassTime = DateUtil.addMinutes(lastEndClassTime, 10);;

		Date endClassTime = DateUtil.addMinutes(lastEndClassTime, singleClassMinutes);
		if(!DateUtil.isSameDay(lastEndClassTime, endClassTime)){
			return false;
		}
		courseSchedule.setStartClassTime(lastEndClassTime);
		courseSchedule.setEndClassTime(endClassTime);
		return true;
	}

	@Override
	public boolean checkSingleCourseConflict(CourseSchedule courseSchedule, List<CourseSchedule> adjustCourses, Map<String, List<CourseSchedule>> result) {
		if(!DateUtil.isSameDay(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime())){
			throw new BizException("课程时间不允许跨天");
		}
		List<CourseSchedule> allCourseSchedules = courseScheduleDao.findByClassDate(Arrays.asList(DateUtil.dateToString(courseSchedule.getClassDate(), "yyyy-MM-dd")));

		if(null == allCourseSchedules){
			allCourseSchedules = new ArrayList<>();
		}
		List<CourseSchedule> adjustCourseTemp = adjustCourses.stream().filter(c -> DateUtil.isSameDay(c.getClassDate(), courseSchedule.getClassDate())).collect(Collectors.toList());
		Set<Long> adjustCourseIds = adjustCourseTemp.stream().map(CourseSchedule::getId).collect(Collectors.toSet());
		allCourseSchedules= (List<CourseSchedule>) org.apache.commons.collections.CollectionUtils.union(allCourseSchedules.stream()
				.filter(c->!adjustCourseIds.contains(c.getId())).collect(Collectors.toList()),
				adjustCourseTemp);

		Map<Long, CourseSchedule> idCourseMap = allCourseSchedules.stream().collect(Collectors.toMap(CourseSchedule::getId, c -> c));
		Set<Long> courseScheduleIds = allCourseSchedules.stream().map(CourseSchedule::getId).collect(Collectors.toSet());
		courseScheduleIds.add(courseSchedule.getId());
		List<CourseScheduleStudentPayment> courseScheduleStudentPayments = courseScheduleStudentPaymentDao.findByCourseScheduleIds(new ArrayList<>(courseScheduleIds));
		Map<Long, Set<Integer>> courseStudentIdsMap = courseScheduleStudentPayments.stream()
				.collect(Collectors.groupingBy(CourseScheduleStudentPayment::getCourseScheduleId,
						Collectors.mapping(CourseScheduleStudentPayment::getUserId, Collectors.toSet())));

		List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = courseScheduleTeacherSalaryDao.findByCourseSchedules(new ArrayList<>(courseScheduleIds));
		Map<Long, Set<Integer>> courseTeacherIdsMap = courseScheduleTeacherSalaries.stream()
				.collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getCourseScheduleId,
						Collectors.mapping(CourseScheduleTeacherSalary::getUserId, Collectors.toSet())));
		Set<Integer> currentCourseTeacherIds = courseTeacherIdsMap.get(courseSchedule.getId());

		List<StudentAttendance> studentAttendances = studentAttendanceDao.findByCourseIds(new ArrayList<>(courseScheduleIds));
		Map<Long, Set<Integer>> courseLeaveStudentIdsMap = new HashMap<>();
		for (StudentAttendance sa : studentAttendances) {
			if(sa.getCourseScheduleId().equals(courseSchedule.getId())&&!StudentAttendanceStatusEnum.LEAVE.equals(sa.getStatus())){
				return false;
			}
			if(!courseLeaveStudentIdsMap.containsKey(sa.getCourseScheduleId())){
				courseLeaveStudentIdsMap.put(sa.getCourseScheduleId(), new HashSet<>());
			}
			CourseSchedule cs = idCourseMap.get(sa.getCourseScheduleId());
			if(DateUtil.addHours(sa.getCreateTime(),4).compareTo(cs.getStartClassTime())<0){
				courseLeaveStudentIdsMap.get(sa.getCourseScheduleId()).add(sa.getUserId());
			}
		}
		Set<Integer> currentCourseLeaveStudentIds = courseLeaveStudentIdsMap.get(courseSchedule.getId());
		Set<Integer> currentCourseStudentIds;
		if(null!=currentCourseLeaveStudentIds){
			currentCourseStudentIds = courseStudentIdsMap.get(courseSchedule.getId())
					.stream().filter(id->Objects.nonNull(currentCourseLeaveStudentIds)&&!currentCourseLeaveStudentIds.contains(id)).collect(Collectors.toSet());
		}else{
			currentCourseStudentIds = courseStudentIdsMap.get(courseSchedule.getId());
		}

		boolean isRepeat = false;
		List<CourseSchedule> repeatCourses = new ArrayList<>();

		allCourseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
		for (CourseSchedule cs : allCourseSchedules) {
			if(cs.getId().equals(courseSchedule.getId())){
				continue;
			}

			if(cs.getStartClassTime().compareTo(courseSchedule.getEndClassTime())>0){
				break;
			}

			if(cs.getEndClassTime().compareTo(courseSchedule.getStartClassTime())<0){
				continue;
			}

			//判断两节课程时间是否重叠
			if (!cs.getStartClassTime().before(courseSchedule.getEndClassTime())
					||!cs.getEndClassTime().after(courseSchedule.getStartClassTime())) {
				continue;
			}

			Set<Integer> csLeaveStudentIds = courseLeaveStudentIdsMap.get(cs.getId());
			Set<Integer> repeatStudentIds = new HashSet<>();
			Set<Integer> csStudentIds;
			if(null!=csLeaveStudentIds){
				csStudentIds = courseStudentIdsMap.get(cs.getId()).stream()
						.filter(id->Objects.nonNull(csLeaveStudentIds)&&!csLeaveStudentIds.contains(id)).collect(Collectors.toSet());
			}else{
				csStudentIds = courseStudentIdsMap.get(cs.getId());
			}
			if(null!=csStudentIds){
				repeatStudentIds = csStudentIds.stream().filter(id -> currentCourseStudentIds.contains(id)).collect(Collectors.toSet());
			}

			Set<Integer> csTeacherIds = courseTeacherIdsMap.get(cs.getId());
			Set<Integer> repeatTeacherIds = new HashSet<>();
			if(null!=csTeacherIds){
				repeatTeacherIds = csTeacherIds.stream().filter(id -> Objects.nonNull(currentCourseTeacherIds)&&currentCourseTeacherIds.contains(id)).collect(Collectors.toSet());
			}

			if(!CollectionUtils.isEmpty(repeatStudentIds)||!CollectionUtils.isEmpty(repeatTeacherIds)){
				isRepeat = true;
				break;
			}
		}
		if(isRepeat){
			for (CourseSchedule cs : allCourseSchedules) {
				if(cs.getId().equals(courseSchedule.getId())){
					continue;
				}

				Set<Integer> csLeaveStudentIds = courseLeaveStudentIdsMap.get(cs.getId());
				Set<Integer> repeatStudentIds = new HashSet<>();
				Set<Integer> csStudentIds;
				if(null!=csLeaveStudentIds){
					csStudentIds = courseStudentIdsMap.get(cs.getId()).stream()
							.filter(id->Objects.nonNull(csLeaveStudentIds)&&!csLeaveStudentIds.contains(id)).collect(Collectors.toSet());
				}else{
					csStudentIds = courseStudentIdsMap.get(cs.getId());
				}
				if(null!=csStudentIds){
					repeatStudentIds = csStudentIds.stream().filter(id -> currentCourseStudentIds.contains(id)).collect(Collectors.toSet());
				}

				Set<Integer> csTeacherIds = courseTeacherIdsMap.get(cs.getId());
				Set<Integer> repeatTeacherIds = new HashSet<>();
				if(null!=csTeacherIds){
					repeatTeacherIds = csTeacherIds.stream().filter(id -> Objects.nonNull(currentCourseTeacherIds)&&currentCourseTeacherIds.contains(id)).collect(Collectors.toSet());
				}
				if(!CollectionUtils.isEmpty(repeatStudentIds)||!CollectionUtils.isEmpty(repeatTeacherIds)){
					repeatCourses.add(cs);
				}
			}
			boolean b = courseTimeRevise(courseSchedule, repeatCourses);
			if(b){
				result.get("revise").add(courseSchedule);
			}
			return b;
		}
		result.get("normal").add(courseSchedule);
		return true;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
    public Boolean checkNewCourseSchedules(List<CourseSchedule> courseSchedules, boolean checkExistCourseSchedule,Boolean postponeFlag) {
        if (CollectionUtils.isEmpty(courseSchedules)) {
            return false;
        }
        List<String> classDates = courseSchedules.stream().map(courseSchedule -> DateUtil.dateToString(courseSchedule.getClassDate(), "yyyy-MM-dd"))
                .collect(Collectors.toList());

        List<CourseSchedule> existCourseSchedules = courseScheduleDao.findByClassDate(classDates);

        //只需要调整课程信息的课程编号列表
        List<Long> updateCourseScheduleIds = courseSchedules
                .stream()
                .filter(courseSchedule -> Objects.nonNull(courseSchedule.getId()))
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        //排除只需调整的课程
        existCourseSchedules = existCourseSchedules.stream()
                .filter(courseSchedule -> !updateCourseScheduleIds.contains(courseSchedule.getId()))
                .collect(Collectors.toList());
        //新课程对应的班级编号列表
        List<Integer> newCourseScheduleClassGroupIds = courseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());

        List<Long> existCourseScheduleIds = existCourseSchedules.stream()
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        HashSet<Long> courseScheduleIdsSet = new HashSet<>(existCourseScheduleIds);

        //合并新课程和已存在的课程
        List<CourseSchedule> allCourseSchedules;
        if (!CollectionUtils.isEmpty(existCourseSchedules)) {
            allCourseSchedules = ListUtils.sum(courseSchedules, existCourseSchedules);
        } else {
            allCourseSchedules = courseSchedules;
        }

        //所有课程编号
		Set<Long> allCourseScheduleIds = allCourseSchedules.stream().map(CourseSchedule::getId).collect(Collectors.toSet());
        //所有课程学员签到记录
		List<StudentAttendance> studentAttendances = studentAttendanceDao.findByCourseIds(new ArrayList<>(allCourseScheduleIds));
		//课程请假学员字典
		Map<Long, Set<Integer>> courseLeaveStudentMap = studentAttendances.stream()
				.filter(e -> StudentAttendanceStatusEnum.LEAVE.equals(e.getStatus()))
				.collect(Collectors.groupingBy(StudentAttendance::getCourseScheduleId, Collectors.mapping(StudentAttendance::getUserId, Collectors.toSet())));

		//所有课程的班级编号
        List<Integer> classGroupIds = allCourseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());
        //班级与学生的关联记录
        List<ClassGroupStudentMapper> classGroupStudentMappers = classGroupStudentMapperDao.findByClassGroups(classGroupIds);
        Map<Integer, List<ClassGroupStudentMapper>> classGroupStudentsMap = classGroupStudentMappers
                .stream()
                .collect(Collectors.groupingBy(ClassGroupStudentMapper::getClassGroupId));

        //根据课程获取助教id关联集合
        List<IntegerAndIntegerListDto> courseScheduleTeachingTeacherIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(allCourseScheduleIds)) {
            courseScheduleTeachingTeacherIdList = courseScheduleDao.findCourseScheduleIdAndUserIdsMap(new ArrayList<>(allCourseScheduleIds), TeachTypeEnum.TEACHING.getCode());
        }
        Map<Long, IntegerAndIntegerListDto> courseScheduleTeachingTeacherMap = courseScheduleTeachingTeacherIdList.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

        //班级助教关联ID集合
        List<IntegerAndIntegerListDto> classGroupAndUserIdsMap = courseScheduleDao.findClassGroupAndUserIdsMap(newCourseScheduleClassGroupIds, TeachTypeEnum.TEACHING.getCode());
        Map<Long, IntegerAndIntegerListDto> classGroupTeachingTeacherMap = classGroupAndUserIdsMap.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

        Set<Long> existCourseScheduleIdsSet=new HashSet<>(existCourseScheduleIds);

        Map<String, List<CourseSchedule>> existClassDateCoursesMap = allCourseSchedules.stream().collect(Collectors.groupingBy(c -> DateUtil.dateToString(c.getClassDate(), "yyyy-MM-dd")));
        Map<String, List<CourseSchedule>> newClassDateCoursesMap = courseSchedules.stream().collect(Collectors.groupingBy(c -> DateUtil.dateToString(c.getClassDate(), "yyyy-MM-dd")));
        if (allCourseSchedules.size() > 1) {
            for (Map.Entry<String, List<CourseSchedule>> classDateCourseEntry : newClassDateCoursesMap.entrySet()) {
                List<CourseSchedule> existClassDateCourses = existClassDateCoursesMap.get(classDateCourseEntry.getKey());
                if(CollectionUtils.isEmpty(existClassDateCourses)){
                    continue;
                }
                List<CourseSchedule> newClassDateCourses=classDateCourseEntry.getValue();
                existClassDateCourses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
                newClassDateCourses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
                for (CourseSchedule preCourseSchedule : newClassDateCourses) {
                    for (CourseSchedule backCourseSchedule : existClassDateCourses) {

                        //判断前后两节课是否存在冲突
                        if (!preCourseSchedule.getStartClassTime().before(backCourseSchedule.getEndClassTime())
                                ||!preCourseSchedule.getEndClassTime().after(backCourseSchedule.getStartClassTime())) {
                            continue;
                        }
                        if (preCourseSchedule.equals(backCourseSchedule)) {
                            continue;
                        }

                        //如果存在时间重叠，则需要判断前后两节课的教师和学生是否存在冲突
                        //主教冲突检测
                        if (Objects.nonNull(preCourseSchedule.getActualTeacherId())
                                && preCourseSchedule.getActualTeacherId().equals(backCourseSchedule.getActualTeacherId())) {
							if(postponeFlag){
								return false;
							}else {
								throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 1));
							}
                        }

//                        if(Objects.isNull(preCourseSchedule.getId())){
//                            continue;
//                        }

                        //助教冲突检测
						List<Integer> preTeachingTeacherIdList = new ArrayList<>();
						List<Integer> backTeachingTeacherIdList = new ArrayList<>();
						if (allCourseScheduleIds.contains(preCourseSchedule.getId())) {
							IntegerAndIntegerListDto integerAndIntegerListDto = courseScheduleTeachingTeacherMap.get(preCourseSchedule.getId());
							if (Objects.nonNull(integerAndIntegerListDto)) {
								preTeachingTeacherIdList.addAll(integerAndIntegerListDto.getIds());
							}
						}
                        if (CollectionUtils.isEmpty(preTeachingTeacherIdList)&&Objects.isNull(preCourseSchedule.getId())) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = classGroupTeachingTeacherMap.get(preCourseSchedule.getClassGroupId().longValue());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
								preTeachingTeacherIdList.addAll(integerAndIntegerListDto.getIds());
                            }
                        }

						if (allCourseScheduleIds.contains(backCourseSchedule.getId())) {
							IntegerAndIntegerListDto integerAndIntegerListDto = courseScheduleTeachingTeacherMap.get(backCourseSchedule.getId());
							if (Objects.nonNull(integerAndIntegerListDto)) {
								backTeachingTeacherIdList.addAll(integerAndIntegerListDto.getIds());
							}
						}
                        if (CollectionUtils.isEmpty(backTeachingTeacherIdList)) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = classGroupTeachingTeacherMap.get(backCourseSchedule.getClassGroupId().longValue());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
//								backTeachingTeacherIdList.addAll(integerAndIntegerListDto.getIds());
                            }
                        }

						preTeachingTeacherIdList.add(preCourseSchedule.getActualTeacherId());
						backTeachingTeacherIdList.add(backCourseSchedule.getActualTeacherId());

                        if (!CollectionUtils.isEmpty(preTeachingTeacherIdList)
                                && !CollectionUtils.isEmpty(backTeachingTeacherIdList)) {
                            List<Integer> repeatIds = preTeachingTeacherIdList
                                    .stream().filter(backTeachingTeacherIdList::contains)
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(repeatIds)) {
								if(postponeFlag){
									return false;
								}else {
									throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 2));
								}
                            }
                        }
                        //学生冲突检测
                        if (preCourseSchedule.getClassGroupId().equals(backCourseSchedule.getClassGroupId())) {
                            //如果班级相同，则学生肯定存在冲突
							if(postponeFlag){
								return false;
							}else {
								throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 3));
							}
                        }
                        //如果班级不同，则需要检测两个班级是否存在重复的学生
                        List<ClassGroupStudentMapper> preClassGroupStudents = classGroupStudentsMap.get(preCourseSchedule.getClassGroupId());
                        List<ClassGroupStudentMapper> backClassGroupStudents = classGroupStudentsMap.get(backCourseSchedule.getClassGroupId());
                        //如果有一个存在没有学生的班级则不存在冲突
                        if (CollectionUtils.isEmpty(preClassGroupStudents) || CollectionUtils.isEmpty(backClassGroupStudents)) {
                            continue;
                        }
                        //课程对应请假学员编号集合
						Set<Integer> preLeaveStudentIds = courseLeaveStudentMap.get(preCourseSchedule.getId());
                        if(null == preLeaveStudentIds){
                        	preLeaveStudentIds = Collections.EMPTY_SET;
						}
						Set<Integer> backLeaveStudentIds = courseLeaveStudentMap.get(backCourseSchedule.getId());
						if(null == backLeaveStudentIds){
							backLeaveStudentIds = Collections.EMPTY_SET;
						}

						//当前课程所在班级的学生编号列表
						Set<Integer> finalPreLeaveStudentIds = preLeaveStudentIds;
						List<Integer> preClassGroupStudentIds = preClassGroupStudents.stream()
								.filter(e->!finalPreLeaveStudentIds.contains(e.getUserId()))
                                .map(ClassGroupStudentMapper::getUserId)
                                .collect(Collectors.toList());
                        //后面一节课程所在班级的学生编号列表
						Set<Integer> finalBackLeaveStudentIds = backLeaveStudentIds;
						Set<Integer> backClassGroupStudentIds = backClassGroupStudents.stream()
								.filter(e->!finalBackLeaveStudentIds.contains(e.getUserId()))
                                .map(ClassGroupStudentMapper::getUserId)
                                .collect(Collectors.toSet());
                        List<Integer> repeatStudentIds = preClassGroupStudentIds.stream()
                                .filter(backClassGroupStudentIds::contains)
                                .collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(repeatStudentIds)) {
							if(postponeFlag){
								return false;
							}else {
								throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 3));
							}
                        }
                    }
                }
            }
        }
        return true;
    }

    @Override
    public void checkNewCourseSchedulesWithoutMusicGroup(List<CourseSchedule> courseSchedules, boolean checkExistCourseSchedule) {
        if (CollectionUtils.isEmpty(courseSchedules)) {
            return;
        }
        List<String> classDates = courseSchedules.stream().map(courseSchedule -> DateUtil.dateToString(courseSchedule.getClassDate(), "yyyy-MM-dd"))
                .collect(Collectors.toList());

        List<CourseSchedule> existCourseSchedules = courseScheduleDao.findByClassDateWithoutMusicGroup(classDates);

        //只需要调整课程信息的课程编号列表
        List<Long> updateCourseScheduleIds = courseSchedules
                .stream()
                .filter(courseSchedule -> Objects.nonNull(courseSchedule.getId()))
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        //排除只需调整的课程
        existCourseSchedules = existCourseSchedules.stream()
                .filter(courseSchedule -> !updateCourseScheduleIds.contains(courseSchedule.getId()))
                .collect(Collectors.toList());
        //新课程对应的班级编号列表
        List<Integer> newCourseScheduleClassGroupIds = courseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());

        List<Long> existCourseScheduleIds = existCourseSchedules.stream()
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        HashSet<Long> courseScheduleIdsSet = new HashSet<>(existCourseScheduleIds);

        //合并新课程和已存在的课程
        List<CourseSchedule> allCourseSchedules;
        if (!CollectionUtils.isEmpty(existCourseSchedules)) {
            allCourseSchedules = ListUtils.sum(courseSchedules, existCourseSchedules);
        } else {
            allCourseSchedules = courseSchedules;
        }
        //所有课程的班级编号
        List<Integer> classGroupIds = allCourseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());
        //班级与学生的关联记录
        List<ClassGroupStudentMapper> classGroupStudentMappers = classGroupStudentMapperDao.findByClassGroups(classGroupIds);
        Map<Integer, List<ClassGroupStudentMapper>> classGroupStudentsMap = classGroupStudentMappers
                .stream()
                .collect(Collectors.groupingBy(ClassGroupStudentMapper::getClassGroupId));

        //根据课程获取助教id关联集合
        List<IntegerAndIntegerListDto> courseScheduleTeachingTeacherIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(existCourseScheduleIds)) {
            courseScheduleTeachingTeacherIdList = courseScheduleDao.findCourseScheduleIdAndUserIdsMap(existCourseScheduleIds, TeachTypeEnum.TEACHING.getCode());
        }
        Map<Long, IntegerAndIntegerListDto> courseScheduleTeachingTeacherMap = courseScheduleTeachingTeacherIdList.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

        //班级助教关联ID集合
        List<IntegerAndIntegerListDto> classGroupAndUserIdsMap = courseScheduleDao.findClassGroupAndUserIdsMap(newCourseScheduleClassGroupIds, TeachTypeEnum.TEACHING.getCode());
        Map<Long, IntegerAndIntegerListDto> classGroupTeachingTeacherMap = classGroupAndUserIdsMap.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

        Set<Long> existCourseScheduleIdsSet=new HashSet<>(existCourseScheduleIds);

        Map<String, List<CourseSchedule>> existClassDateCoursesMap = allCourseSchedules.stream().collect(Collectors.groupingBy(c -> DateUtil.dateToString(c.getClassDate(), "yyyy-MM-dd")));
        Map<String, List<CourseSchedule>> newClassDateCoursesMap = courseSchedules.stream().collect(Collectors.groupingBy(c -> DateUtil.dateToString(c.getClassDate(), "yyyy-MM-dd")));
        if (allCourseSchedules.size() > 1) {
            for (Map.Entry<String, List<CourseSchedule>> classDateCourseEntry : newClassDateCoursesMap.entrySet()) {
                List<CourseSchedule> existClassDateCourses = existClassDateCoursesMap.get(classDateCourseEntry.getKey());
                if(CollectionUtils.isEmpty(existClassDateCourses)){
                    continue;
                }
                List<CourseSchedule> newClassDateCourses=classDateCourseEntry.getValue();
                existClassDateCourses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
                newClassDateCourses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
                for (CourseSchedule preCourseSchedule : newClassDateCourses) {
                    for (CourseSchedule backCourseSchedule : existClassDateCourses) {

                        //判断前后两节课是否存在冲突
                        if (!preCourseSchedule.getStartClassTime().before(backCourseSchedule.getEndClassTime())
                                ||!preCourseSchedule.getEndClassTime().after(backCourseSchedule.getStartClassTime())) {
                            continue;
                        }
                        if (!checkExistCourseSchedule
                                && !courseScheduleIdsSet.contains(backCourseSchedule.getId())) {
                            continue;
                        }

                        //如果存在时间重叠，则需要判断前后两节课的教师和学生是否存在冲突
                        //主教冲突检测
                        if (Objects.nonNull(preCourseSchedule.getActualTeacherId())
                                && preCourseSchedule.getActualTeacherId().equals(backCourseSchedule.getActualTeacherId())) {

                            throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 1));
                        }
                        //助教冲突检测
                        if (Objects.isNull(preCourseSchedule.getId())) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = classGroupTeachingTeacherMap.get(preCourseSchedule.getClassGroupId());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
                                preCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
                            }
                        } else if (existCourseScheduleIdsSet.contains(preCourseSchedule.getId())) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = courseScheduleTeachingTeacherMap.get(preCourseSchedule.getId());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
                                preCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
                            }
                        }
                        if (Objects.isNull(backCourseSchedule.getId())) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = classGroupTeachingTeacherMap.get(backCourseSchedule.getClassGroupId());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
                                backCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
                            }
                        } else if (existCourseScheduleIdsSet.contains(backCourseSchedule.getId())) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = courseScheduleTeachingTeacherMap.get(backCourseSchedule.getId());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
                                backCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
                            }
                        }
                        if (!CollectionUtils.isEmpty(preCourseSchedule.getTeachingTeacherIdList())
                                && !CollectionUtils.isEmpty(backCourseSchedule.getTeachingTeacherIdList())) {
                            List<Integer> repeatIds = preCourseSchedule.getTeachingTeacherIdList()
                                    .stream().filter(backCourseSchedule.getTeachingTeacherIdList()::contains)
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(repeatIds)) {
                                throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 2));
                            }
                        }
                        //学生冲突检测
                        if (preCourseSchedule.getClassGroupId().equals(backCourseSchedule.getClassGroupId())) {
                            //如果班级相同，则学生肯定存在冲突
                            throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 3));
                        }
                        //如果班级不同，则需要检测两个班级是否存在重复的学生
                        List<ClassGroupStudentMapper> preClassGroupStudents = classGroupStudentsMap.get(preCourseSchedule.getClassGroupId());
                        List<ClassGroupStudentMapper> backClassGroupStudents = classGroupStudentsMap.get(backCourseSchedule.getClassGroupId());
                        //如果有一个存在没有学生的班级则不存在冲突
                        if (CollectionUtils.isEmpty(preClassGroupStudents) || CollectionUtils.isEmpty(backClassGroupStudents)) {
                            continue;
                        }
                        //当前课程所在班级的学生编号列表
                        List<Integer> preClassGroupStudentIds = preClassGroupStudents.stream()
                                .map(ClassGroupStudentMapper::getUserId)
                                .collect(Collectors.toList());
                        //后面一节课程所在班级的学生编号列表
                        Set<Integer> backClassGroupStudentIds = backClassGroupStudents.stream()
                                .map(ClassGroupStudentMapper::getUserId)
                                .collect(Collectors.toSet());
                        List<Integer> repeatStudentIds = preClassGroupStudentIds.stream()
                                .filter(backClassGroupStudentIds::contains)
                                .collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(repeatStudentIds)) {
                            throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 3));
                        }
                    }
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> checkSnapCourseShchedules(List<CourseSchedule> courseSchedules) {
        List<Long> courseScheduleIds = new ArrayList<>();
        List<CourseScheduleStudentDto> courseScheduleStudents = new ArrayList<>();
        if (CollectionUtils.isEmpty(courseSchedules)) {
            return courseScheduleIds;
        }
        //第一节课
        CourseSchedule firstCourseSchedule;
        //最后一节课
        CourseSchedule latestCourseSchedule;
        if (courseSchedules.size() == 1) {
            firstCourseSchedule = courseSchedules.get(0);
            latestCourseSchedule = courseSchedules.get(0);
        } else {
            firstCourseSchedule = courseSchedules.stream().min(Comparator.comparing(CourseSchedule::getStartClassTime)).get();
            latestCourseSchedule = courseSchedules.stream().max(Comparator.comparing(CourseSchedule::getEndClassTime)).get();
        }
        //获取第一节课和最后一节课所包含的时间段内已存在的课程
        List<CourseSchedule> existCourseSchedules = courseScheduleDao
                .findAllCourseByDateZone(firstCourseSchedule.getStartClassTime(), latestCourseSchedule.getEndClassTime());

        if (existCourseSchedules == null || existCourseSchedules.size() == 0) {
            return null;
        }
        //只需要调整课程信息的课程编号列表
        List<Long> updateCourseScheduleIds = courseSchedules
                .stream()
                .filter(courseSchedule -> Objects.nonNull(courseSchedule.getId()))
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        //排除只需调整的课程
        existCourseSchedules = existCourseSchedules.stream()
                .filter(courseSchedule -> !updateCourseScheduleIds.contains(courseSchedule.getId()))
                .collect(Collectors.toList());
        if (existCourseSchedules == null || existCourseSchedules.size() == 0) {
            return null;
        }


        List<Long> existCourseScheduleIds = existCourseSchedules.stream()
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        //合并新课程和已存在的课程
        List<CourseSchedule> allCourseSchedules;
        if (!CollectionUtils.isEmpty(existCourseSchedules)) {
            allCourseSchedules = ListUtils.sum(courseSchedules, existCourseSchedules);
        } else {
            allCourseSchedules = courseSchedules;
        }

        //新课程对应的班级编号列表
        List<Integer> newCourseScheduleClassGroupIds = allCourseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());

        //所有课程的班级编号
        List<Integer> classGroupIds = allCourseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());
        //班级与学生的关联记录
        List<CourseScheduleStudentPayment> exitStudentPaymentList = courseScheduleStudentPaymentDao.findByCourseScheduleIds(existCourseScheduleIds);

        List<ClassGroupStudentMapper> classGroupStudentMappers = classGroupStudentMapperDao.findByClassGroups(classGroupIds);
        Map<Integer, List<ClassGroupStudentMapper>> classGroupStudentsMap = classGroupStudentMappers
                .stream()
                .collect(Collectors.groupingBy(ClassGroupStudentMapper::getClassGroupId));

        Map<Long, List<CourseScheduleStudentPayment>> exitStudentPaymentMap = exitStudentPaymentList.stream().collect(Collectors.groupingBy(CourseScheduleStudentPayment::getCourseScheduleId));

        //根据课程获取教师id关联集合
        List<IntegerAndIntegerListDto> courseScheduleTeachingTeacherIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(existCourseScheduleIds)) {
            courseScheduleTeachingTeacherIdList = courseScheduleDao.findCourseScheduleIdAndUserIdsMap(existCourseScheduleIds, null);
        }
        Map<Long, IntegerAndIntegerListDto> courseScheduleTeacherMap = courseScheduleTeachingTeacherIdList.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

        //班级教师关联ID集合
        List<IntegerAndIntegerListDto> classGroupAndUserIdsMap = courseScheduleDao.findClassGroupAndUserIdsMap(newCourseScheduleClassGroupIds, null);
        Map<Long, IntegerAndIntegerListDto> classGroupTeachingTeacherMap = classGroupAndUserIdsMap.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

		allCourseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
        courseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));

        newNode:
        for (CourseSchedule newCourseSchedule : courseSchedules) {
            for (CourseSchedule existCourseSchedule : allCourseSchedules) {
                if (newCourseSchedule.getEndClassTime().compareTo(existCourseSchedule.getStartClassTime()) <= 0) {
                    continue newNode;
                }
                if (existCourseSchedule.getEndClassTime().compareTo(newCourseSchedule.getStartClassTime()) <= 0) {
                    continue;
                }

                if(newCourseSchedule.equals(existCourseSchedule)){
                	continue;
				}

                boolean isTeacherRepeat = false;
                boolean isStudentRepeat = false;
                //检测老师冲突
				if (courseScheduleTeacherMap.containsKey(existCourseSchedule.getId())) {
					existCourseSchedule.setTeachingTeacherIdList(courseScheduleTeacherMap.get(existCourseSchedule.getId()).getIds());
				} else {
					existCourseSchedule.setTeachingTeacherIdList(classGroupTeachingTeacherMap.get(existCourseSchedule.getClassGroupId().longValue()).getIds());
				}
				newCourseSchedule.setTeachingTeacherIdList(classGroupTeachingTeacherMap.get(newCourseSchedule.getClassGroupId().longValue()).getIds());

                if (!CollectionUtils.isEmpty(newCourseSchedule.getTeachingTeacherIdList())
                        && !CollectionUtils.isEmpty(existCourseSchedule.getTeachingTeacherIdList())) {
                    List<Integer> repeatIds = newCourseSchedule.getTeachingTeacherIdList()
                            .stream().filter(existCourseSchedule.getTeachingTeacherIdList()::contains)
                            .collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(repeatIds)) {
                        isTeacherRepeat = true;
                    }
                }

                //学生冲突检测
                if (newCourseSchedule.getClassGroupId().equals(existCourseSchedule.getClassGroupId())) {
                    //如果班级相同，则学生肯定全部存在冲突，当做老师冲突处理
                    isTeacherRepeat = true;
                }

                List<Integer> repeatStudentIds = new ArrayList<>();
                if (!isTeacherRepeat && classGroupStudentsMap.containsKey(newCourseSchedule.getClassGroupId()) && exitStudentPaymentMap.containsKey(existCourseSchedule.getId())) {
                    //如果班级不同，则需要检测两个班级是否存在重复的学生
                    List<ClassGroupStudentMapper> preClassGroupStudents = classGroupStudentsMap.get(newCourseSchedule.getClassGroupId());
                    List<CourseScheduleStudentPayment> backClassGroupStudents = exitStudentPaymentMap.get(existCourseSchedule.getId());

                    //当前课程所在班级的学生编号列表
                    List<Integer> preClassGroupStudentIds = preClassGroupStudents.stream()
                            .map(ClassGroupStudentMapper::getUserId)
                            .collect(Collectors.toList());
                    //后面一节课程所在班级的学生编号列表
                    List<Integer> backClassGroupStudentIds = backClassGroupStudents.stream()
                            .map(CourseScheduleStudentPayment::getUserId)
                            .collect(Collectors.toList());
                    repeatStudentIds = preClassGroupStudentIds.stream()
                            .filter(backClassGroupStudentIds::contains)
                            .collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(repeatStudentIds)) {
                        isStudentRepeat = true;
                    }

                    if(isStudentRepeat && (backClassGroupStudentIds.size() == repeatStudentIds.size())){
                        isStudentRepeat = false;
                        isTeacherRepeat = true;
                    }
                }

                if (!isTeacherRepeat && !isStudentRepeat) {
                    continue;
                }

                if (ClassGroupTypeEnum.SNAP.getCode().equals(existCourseSchedule.getClassGroupType()) || ClassGroupTypeEnum.VIP.getCode().equals(existCourseSchedule.getClassGroupType())) {
                    throw new BizException(courseCheckInfo(newCourseSchedule, existCourseSchedule, existCourseScheduleIds, isTeacherRepeat?1:3));
                }

                if (!existCourseSchedule.getGroupType().equals(newCourseSchedule.getGroupType()) || !existCourseSchedule.getMusicGroupId().equals(newCourseSchedule.getMusicGroupId())) {
                    throw new BizException(courseCheckInfo(newCourseSchedule, existCourseSchedule, existCourseScheduleIds, isTeacherRepeat?1:3));
                }

                if (isTeacherRepeat) {
                    courseScheduleIds.add(existCourseSchedule.getId());
                }
                if (isStudentRepeat) {
                    CourseScheduleStudentDto courseScheduleStudentDto = new CourseScheduleStudentDto();
                    courseScheduleStudentDto.setId(existCourseSchedule.getId());
                    courseScheduleStudentDto.setStudentIds(repeatStudentIds);
                    courseScheduleStudents.add(courseScheduleStudentDto);
                }

            }
        }
        //老师冲突删除课程课程
        if (courseScheduleIds.size() > 0) {
            courseScheduleDao.batchDeleteCourseSchedules(courseScheduleIds);
            courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
            teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
            courseScheduleStudentPaymentDao.deleteByCourseSchedule(courseScheduleIds);
        }
        //学生冲突删除学生课程
        if (courseScheduleStudents.size() > 0) {
            for (CourseScheduleStudentDto courseScheduleStudent : courseScheduleStudents) {
                courseScheduleStudentPaymentDao.deleteStudentCourseScheduleByUserId(courseScheduleStudent.getId(), courseScheduleStudent.getStudentIds());
            }
        }
        return courseScheduleIds;
    }

    private String courseCheckInfo(CourseSchedule preCourseSchedule, CourseSchedule backCourseSchedule, List<Long> existCourseScheduleIds, Integer type) {
        List<CourseSchedule> courseSchedules=new ArrayList<>();
        courseSchedules.add(preCourseSchedule);
        courseSchedules.add(backCourseSchedule);
        courseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
        //提示信息
        StringBuffer errInfo = new StringBuffer("在");
        errInfo.append(DateUtil.dateToString(courseSchedules.get(1).getStartClassTime(), "yyyy-MM-dd HH:mm"));
        errInfo.append("至");
        errInfo.append(DateUtil.dateToString(courseSchedules.get(0).getEndClassTime().before(courseSchedules.get(1).getEndClassTime())?courseSchedules.get(0).getEndClassTime():courseSchedules.get(1).getEndClassTime(), "HH:mm"));
        errInfo.append("的时间段内");
        errInfo.append("安排的课程存在冲突,");
        errInfo.append("冲突课程为：");

        CourseSchedule courseSchedule = null;
        if (Objects.nonNull(preCourseSchedule.getId()) && existCourseScheduleIds.contains(preCourseSchedule.getId())) {
            courseSchedule = preCourseSchedule;
        }
        if (Objects.nonNull(backCourseSchedule.getId()) && existCourseScheduleIds.contains(backCourseSchedule.getId())) {
            courseSchedule = backCourseSchedule;
        }

		if (Objects.isNull(courseSchedule)) {
			errInfo.setLength(0);
			errInfo.append("您设置的循环周期存在时间冲突");
			return errInfo.toString();
		}

        String groupName = "";

        if (Objects.nonNull(courseSchedule.getId())) {
            if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.VIP)) {
                VipGroup vipGroup = vipGroupDao.get(Long.valueOf(courseSchedule.getMusicGroupId()));
                if (Objects.nonNull(vipGroup)) {
                    groupName = vipGroup.getName();
                }
            }else if(courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.PRACTICE)){
                PracticeGroup practiceGroup = practiceGroupDao.get(Long.valueOf(courseSchedule.getMusicGroupId()));
                if (Objects.nonNull(practiceGroup)) {
                    groupName = practiceGroup.getName();
                }
            }else{
                MusicGroup musicGroup = musicGroupDao.get(courseSchedule.getMusicGroupId());
                if (Objects.nonNull(musicGroup)) {
                    groupName = musicGroup.getName();
                }
            }
        }

        errInfo.append(groupName);
        errInfo.append("(");
        errInfo.append(courseSchedule.getMusicGroupId());
        errInfo.append(")-");
        errInfo.append(courseSchedule.getName());
        errInfo.append("(");
        errInfo.append(courseSchedule.getId());
        errInfo.append(")，");

        errInfo.append("类型为：");
        switch (type) {
            case 1:
                errInfo.append("主教冲突");
                break;
            case 2:
                errInfo.append("助教冲突");
                break;
            case 3:
                errInfo.append("学生冲突");
                break;
            default:
                errInfo.append("未知冲突");
                break;
        }

        return errInfo.toString();
    }

    /**
     * 判断课程安排中是否存在冲突
     * 计算课程课次
     *
     * @param courseSchedules
     * @return
     */
    private void checkCourseSchedule(List<CourseSchedule> courseSchedules) {
        List<Date> classDates = courseSchedules.stream().map(CourseSchedule::getClassDate).collect(Collectors.toList());
        List<CourseSchedule> byClassGroupAndDate = courseScheduleDao.findByClassGroupAndDate(classDates, null);
        List<CourseSchedule> collect3 = Stream.of(courseSchedules, byClassGroupAndDate).flatMap(Collection::stream).collect(Collectors.toList());
        Map<Date, List<CourseSchedule>> collect = collect3.stream().collect(Collectors.groupingBy(CourseSchedule::getClassDate));
        for (Date keyDate : collect.keySet()) {
            List<CourseSchedule> currentCourses = collect.get(keyDate);
            Map<Date, List<CourseSchedule>> collect1 = currentCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getStartClassTime));
            if (currentCourses.size() == 1 && currentCourses.size() == collect1.size()) {
                continue;
            } else if (currentCourses.size() > 1 && currentCourses.size() == collect1.size()) {
                ArrayList<CourseSchedule> collect2 = currentCourses
                        .stream()
                        .collect(Collectors.collectingAndThen(Collectors.toCollection(()
                                -> new TreeSet<CourseSchedule>(Comparator.comparing(o -> o.getStartClassTime() + "-" + o.getEndClassTime()))), ArrayList::new));
                if (collect2.size() != currentCourses.size()) {
                    throw new BizException("建课失败，当前课程安排与现有课程冲突，请调整相关设置");
                }
            } else {
                for (Date keyDate2 : collect1.keySet()) {
                    List<CourseSchedule> currentCourses1 = collect1.get(keyDate2);
                    if (currentCourses1.size() > ParamEnum.ONE.getCode()) {
                        Map<Integer, List<CourseSchedule>> collect2 = currentCourses1.stream().collect(
                                Collectors.groupingBy(CourseSchedule::getTeacherId));
                        for (Integer teacherID : collect2.keySet()) {
                            if (collect2.get(teacherID).size() > ParamEnum.ONE.getCode()) {
                                throw new BizException(new SimpleDateFormat("yyyy-MM-dd").format(keyDate) + "日的课程安排在教师分配上有冲突!");
                            }
                        }
                        List<Integer> repeatClassGroupIds = currentCourses1.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
                        Integer[] counts = courseScheduleDao.countStudentInClass(repeatClassGroupIds);
                        for (Integer i : counts) {
                            if (i > ParamEnum.ONE.getCode()) {
                                throw new BizException(new SimpleDateFormat("yyyy-MM-dd").format(keyDate) + "日的课程安排有学生重复!");
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * @Author: Joburgess
     * @Date: 2019/9/29
     * 生成课程名
     */
    @Override
    public void createCourseScheduleName(List<CourseSchedule> courseSchedules) {
        List<Integer> classGroupIds = courseSchedules.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
        HashSet<Integer> temp = new HashSet<>(classGroupIds);
        classGroupIds = new ArrayList<>(temp);
        Map<Integer, String> classIdSubjectNameMap = convertToMap(courseScheduleDao.findClassSubjects(classGroupIds));
        courseSchedules.forEach(courseSchedule -> {
        	if(StringUtils.isNotBlank(courseSchedule.getName())){
        		return;
			}
            if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.MIX)) {
                courseSchedule.setName(courseSchedule.getType().getMsg());
            } else {
                StringBuilder className = new StringBuilder(classIdSubjectNameMap.get(courseSchedule.getClassGroupId()));
                className.append("-");
                className.append(courseSchedule.getType().getMsg());
                courseSchedule.setName(className.toString());
            }
            courseSchedule.setStatus(CourseStatusEnum.NOT_START);
        });
    }

    private Map<Integer, String> convertToMap(String[] result) {
        Map<Integer, String> map = new HashMap<>();
        for (String s : result) {
        	if(s.split("-").length>1){
				map.put(Integer.valueOf(s.split("-")[0]), s.split("-")[1].replace(",", "/"));
			}
        }
        return map;
    }

	public List<CourseScheduleModifyLog> getModifyLogs(List<Long> courseScheduleIds,List<CourseSchedule> courseSchedules,Integer userId,Date now){
		List<CourseScheduleModifyLog> insertCourseScheduleModifyLogList = new ArrayList<>();
		//获取调整前助教信息
		Map<Long, String> teachingTeacherMap = MapUtil.convertMybatisMap(courseScheduleTeacherSalaryDao.queryTeacherIdMap(courseScheduleIds,"TEACHING"));
		for (CourseSchedule e : courseSchedules) {
			// 调整日志
			e.setTeachingTeacherIds(teachingTeacherMap.get(e.getId()));
			CourseScheduleModifyLog courseScheduleModifyLog = new CourseScheduleModifyLog();
			courseScheduleModifyLog.setCourseScheduleId(e.getId());
			courseScheduleModifyLog.setCreateTime(now);
			courseScheduleModifyLog.setPreviousCourseSchedule(JsonUtil.toJSONString(e));
			courseScheduleModifyLog.setOperatorId(userId);
			insertCourseScheduleModifyLogList.add(courseScheduleModifyLog);
		}
		return insertCourseScheduleModifyLogList;
	}

    public void saveModifyLog(List<CourseScheduleModifyLog> modifyLogs,List<Long> courseIds){
		//保存日志调整信息
		//获取调整后助教信息
		Map<Long, String> newTeachingTeacherMap = MapUtil.convertMybatisMap(courseScheduleTeacherSalaryDao.queryTeacherIdMap(courseIds,"TEACHING"));
		List<CourseSchedule> newCourseScheduleList = courseScheduleDao.findByCourseScheduleIds(courseIds);
		Map<Long, List<CourseSchedule>> collect = newCourseScheduleList.stream().collect(Collectors.groupingBy(CourseSchedule::getId));
		modifyLogs.forEach(e->{
			CourseSchedule schedule = collect.get(e.getCourseScheduleId()).get(0);
			schedule.setTeachingTeacherIds(newTeachingTeacherMap.get(schedule.getId()));
			e.setCurrentCourseSchedule(JsonUtil.toJSONString(schedule));
		});
		if (modifyLogs.size() > 0) {
			courseScheduleModifyLogDao.batchInsert(modifyLogs);
		}
	}

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void vipCourseAdjust(VipGroupCourseAdjustInfoDto vipGroupCourseAdjustInfo) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        if (Objects.isNull(vipGroupCourseAdjustInfo.getVipGroupId())) {
            throw new BizException("请指定课程");
        }
        if (Objects.isNull(vipGroupCourseAdjustInfo.getCourseCreateStartTime())) {
            throw new BizException("请指定排课起始时间;");
        }
        if (CollectionUtils.isEmpty(vipGroupCourseAdjustInfo.getCourseTimes())) {
            throw new BizException("请指定排课周期");
        }
        if (StringUtils.isBlank(vipGroupCourseAdjustInfo.getCourseScheduleIds())) {
            throw new BizException("请指定需要调整的课程");
        }
        Date courseCreateStartTime = vipGroupCourseAdjustInfo.getCourseCreateStartTime();
        Date now = new Date();
        Date today = DateUtil.stringToDate(DateUtil.dateToString(now, DateUtil.ISO_EXPANDED_DATE_FORMAT),
                DateUtil.ISO_EXPANDED_DATE_FORMAT);
        if (courseCreateStartTime.before(today)) {
            throw new BizException("排课起始时间不能小于当前时间");
        }

        boolean needSchoolId = Objects.nonNull(vipGroupCourseAdjustInfo.getTeachMode()) && vipGroupCourseAdjustInfo.getTeachMode().equals(TeachModeEnum.OFFLINE) && Objects.isNull(vipGroupCourseAdjustInfo.getSchoolId());
        if (needSchoolId) {
            throw new BizException("请设置教学点");
        }

        int singleClassMinutes = 0;
        int courseNum = 0;
        Date coursesExpireDate = null;
        Date coursesStartDate = null;
        GroupType groupType = vipGroupCourseAdjustInfo.getGroupType();
        switch (vipGroupCourseAdjustInfo.getGroupType()){
            case PRACTICE:
                PracticeGroup practiceGroup = practiceGroupDao.get(vipGroupCourseAdjustInfo.getVipGroupId().longValue());
                if (Objects.isNull(practiceGroup)) {
                    throw new BizException("指定课程不存在");
                }
                singleClassMinutes = practiceGroup.getSingleClassMinutes();
                courseNum = courseScheduleDao.countVipGroupCourses(practiceGroup.getId().intValue(),groupType.getCode());
                coursesExpireDate = practiceGroup.getCoursesExpireDate();
                coursesStartDate = practiceGroup.getCoursesStartDate();
                break;
            default:
                VipGroup vipGroup = vipGroupDao.get(vipGroupCourseAdjustInfo.getVipGroupId().longValue());
                if (Objects.isNull(vipGroup)) {
                    throw new BizException("指定课程不存在");
                }
				if(Objects.nonNull(vipGroup)
						&&!VipGroupStatusEnum.PROGRESS.equals(vipGroup.getStatus())
						&&!VipGroupStatusEnum.FINISHED.equals(vipGroup.getStatus())){
					throw new BizException("非进行中课程组不允许进行此操作");
				}
                singleClassMinutes = vipGroup.getSingleClassMinutes();
                courseNum = courseScheduleDao.countVipGroupCourses(vipGroup.getId().intValue(),groupType.getCode());
        }
        if (courseNum == 0) {
            throw new BizException("未排课的课程不能进行调整");
        }

        ClassGroup classGroup = classGroupDao.findByGroupAndType(vipGroupCourseAdjustInfo.getVipGroupId().toString(),groupType.getCode());
        if (Objects.isNull(classGroup)) {
            throw new BizException("对应班级不存在");
        }

        //所有课程编号
        List<Long> courseScheduleIds = Arrays.asList(vipGroupCourseAdjustInfo.getCourseScheduleIds().split(","))
                .stream().map(Long::parseLong).collect(Collectors.toList());
        //所有的课程
        List<CourseSchedule> courseSchedules = courseScheduleDao.findByCourseScheduleIds(courseScheduleIds);
        courseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
		//获取操作日志
		List<CourseScheduleModifyLog> modifyLogs = getModifyLogs(courseScheduleIds, courseSchedules, user.getId(), now);

        if (courseScheduleIds.size() != courseScheduleIds.size()) {
            throw new BizException("部分课程不存在");
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(courseCreateStartTime);
        List<Date> courseStartDates = new ArrayList<>();

		Set<String> holidayDays = new HashSet<>();

		if (vipGroupCourseAdjustInfo.isHoliday()) {
			SysConfig holidaySetting = sysConfigService.findByParamName(SysConfigService.HOLIDAY_SETTING);
			if(StringUtils.isNotBlank(holidaySetting.getParanValue())){
				holidayDays = new HashSet<>(JSON.parseArray(holidaySetting.getParanValue(), String.class));
			}
		}

        while (true) {
            if (vipGroupCourseAdjustInfo.isHoliday() && holidayDays.contains(DateUtil.format(calendar.getTime(), "yyyy-MM-dd"))) {
                calendar.add(Calendar.DATE, 1);
                continue;
            }
            int i = calendar.get(Calendar.DAY_OF_WEEK);
            if (i == 1) {
                i = 7;
            } else {
                i = i - 1;
            }
            for (CourseTimeDto courseTime : vipGroupCourseAdjustInfo.getCourseTimes()) {
                if (Objects.isNull(courseTime.getDayOfWeek())) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() < 1 || courseTime.getDayOfWeek() > 7) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() == i) {
                    String dateYmdStr = DateUtil.dateToString(calendar.getTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT);
                    dateYmdStr = dateYmdStr + " " + courseTime.getStartClassTime();
                    Date courseStartTime = DateUtil.stringToDate(dateYmdStr, "yyyy-MM-dd HH:mm");
                    Date courseEndTime = DateUtil.addMinutes(courseStartTime, singleClassMinutes);
                    if(DateUtil.daysBetween(DateUtil.stringToDate(DateUtil.format(courseStartTime,DateUtil.DEFAULT_PATTERN),DateUtil.DEFAULT_PATTERN),
                            DateUtil.stringToDate(DateUtil.format(courseEndTime,DateUtil.DEFAULT_PATTERN),DateUtil.DEFAULT_PATTERN)) > 0){
                        throw new BizException("单节课时不允许跨天");
                    }
                    courseStartDates.add(DateUtil.stringToDate(dateYmdStr, DateUtil.EXPANDED_DATE_TIME_FORMAT));
                    int settlementNum = courseScheduleTeacherSalaryDao.checkCourseIsSettlement(courseSchedules.get(courseStartDates.size() - 1).getId().intValue());
                    if (settlementNum > 0) {
                        throw new BizException("{}[{}]{}-{}课程已结算",
                                courseSchedules.get(courseStartDates.size() - 1).getName(),
                                courseSchedules.get(courseStartDates.size() - 1).getId(),
                                DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getStartClassTime(),
                                        DateUtil.ISO_EXPANDED_DATE_TIME_FORMAT),
                                DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getEndClassTime(),
                                        DateUtil.ISO_EXPANDED_DATE_TIME_FORMAT));
                    }
                    int num = studentAttendanceDao.countStudentAttendenceNum(courseSchedules.get(courseStartDates.size() - 1).getId().intValue());
                    if (num > 0) {
                        throw new BizException("{}[{}]{}-{}课程已点名",
                                courseSchedules.get(courseStartDates.size() - 1).getName(),
                                courseSchedules.get(courseStartDates.size() - 1).getId(),
                                DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getStartClassTime(),
                                        DateUtil.EXPANDED_DATE_TIME_FORMAT),
                                DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getEndClassTime(),
                                        DateUtil.EXPANDED_DATE_TIME_FORMAT));
                    }
                    courseSchedules.get(courseStartDates.size() - 1).setStatus(CourseStatusEnum.NOT_START);
                    courseSchedules.get(courseStartDates.size() - 1).setClassDate(courseStartTime);
                    courseSchedules.get(courseStartDates.size() - 1).setStartClassTime(courseStartTime);
                    courseSchedules.get(courseStartDates.size() - 1).setEndClassTime(courseEndTime);
                    if (Objects.nonNull(vipGroupCourseAdjustInfo.getTeachMode())) {
                        if(courseSchedules.get(courseStartDates.size() - 1).getTeachMode().equals(TeachModeEnum.ONLINE)
                            &&vipGroupCourseAdjustInfo.getTeachMode().equals(TeachModeEnum.OFFLINE)
							&&Objects.isNull(vipGroupCourseAdjustInfo.getSchoolId())){
                            throw new BizException("请选择教学点");
                        }
                        courseSchedules.get(courseStartDates.size() - 1).setTeachMode(vipGroupCourseAdjustInfo.getTeachMode());
                        if (vipGroupCourseAdjustInfo.getTeachMode().equals(TeachModeEnum.OFFLINE)) {
                            if(Objects.nonNull(vipGroupCourseAdjustInfo.getSchoolId())){
                                courseSchedules.get(courseStartDates.size() - 1).setSchoolId(vipGroupCourseAdjustInfo.getSchoolId());
                            }
                        } else {
                            courseSchedules.get(courseStartDates.size() - 1).setSchoolId(null);
                        }
                    }
                }
                if (courseStartDates.size() == courseScheduleIds.size()) {
                    break;
                }
            }
            if (courseStartDates.size() == courseScheduleIds.size()) {
                break;
            }
            calendar.add(Calendar.DATE, 1);
        }
        checkNewCourseSchedules(courseSchedules, false,false);
        //如果是陪练课，调整时间不允许超过有效期
        if(groupType == PRACTICE){
            for (CourseSchedule e:courseSchedules) {
                //已点名的不允许调整
                List<StudentAttendance> studentAttendances = studentAttendanceDao.findByCourseId(e.getId());
                if(studentAttendances != null && studentAttendances.size() > 0){
                    throw new BizException("调整失败: 课程已点名");
                }
                String classDate = DateUtil.format(e.getClassDate(), DateUtil.DEFAULT_PATTERN);
                String startClassTime = DateUtil.format(e.getStartClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
                Date startDateTime = DateUtil.stringToDate(classDate + " " + startClassTime, DateUtil.EXPANDED_DATE_TIME_FORMAT);
                Date endDateTime = DateUtil.addMinutes(startDateTime,singleClassMinutes);
                if(DateUtil.minutesBetween(startDateTime,coursesStartDate) > 0){
                    throw new BizException("调整失败: 课程{}调整时间早于有效期",e.getId());
                }
                if(DateUtil.minutesBetween(coursesExpireDate,endDateTime) > 0){
                    throw new BizException("调整失败: 课程{}截止时间超过课程有效期",e.getId());
                }
            }
        }
        if(groupType == VIP){
			VipGroup vipGroup = vipGroupDao.get(vipGroupCourseAdjustInfo.getVipGroupId().longValue());

			CourseSchedule courseSchedule = courseSchedules.stream().max(Comparator.comparing(CourseSchedule::getEndClassTime)).get();

			BigDecimal teacherSalary=BigDecimal.ZERO;

			Map<String, BigDecimal> salaryMap = vipGroupService.countVipGroupPredictFee(vipGroup, vipGroup.getUserId(), null, null);

			ClassGroupTeacherSalary classGroupTeacherSalary = classGroupTeacherSalaryDao.findByVipGoupAndTeacher(vipGroupCourseAdjustInfo.getVipGroupId().intValue(), courseSchedules.get(0).getActualTeacherId());

			if(Objects.nonNull(classGroupTeacherSalary)){
				teacherSalary=vipGroupCourseAdjustInfo.getTeachMode().equals(TeachModeEnum.OFFLINE)?salaryMap.get("offlineTeacherSalary"):salaryMap.get("onlineTeacherSalary");
			}

			if(courseSchedule.getEndClassTime().compareTo(vipGroup.getCoursesExpireDate())>0){
				vipGroup.setCoursesExpireDate(courseSchedule.getEndClassTime());
				vipGroupDao.update(vipGroup);
			}

			courseScheduleTeacherSalaryDao.batchUpdateCourseSalarys(courseScheduleIds, teacherSalary);

		}

        courseScheduleDao.batchUpdate(courseSchedules);
        classGroupService.updateClassGroupInfo(classGroup.getId());
        if(vipGroupCourseAdjustInfo.getCourseCreateStartTime().after(now)){
            teacherAttendanceDao.batchCleanCourseTeacherSignInfo(courseScheduleIds);
        }
        studentAttendanceDao.deleteByCourseSchedules(courseScheduleIds);
		//删除作业
		courseHomeworkService.delHomwworkByCourseScheduleId(courseScheduleIds);
		//删除评论
		courseScheduleReviewDao.delByCourseScheduleIds(courseScheduleIds);
		//删除申述
		courseScheduleComplaintsDao.delByCourseScheduleIds(courseScheduleIds);
		//清除考勤申述
		teacherAttendanceDao.clearAttendanceComplaints(courseScheduleIds);
//        vipGroupService.checkVipCourseIsInScore(vipGroupCourseAdjustInfo.getVipGroupId().longValue());
//        courseScheduleStudentPaymentService.updateVipGiveCourse(vipGroup.getId());
		//保存操作日志
		saveModifyLog(modifyLogs,courseScheduleIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void coursePostpone(CoursePostponeDto coursePostPoneInfo) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        if(StringUtils.isBlank(coursePostPoneInfo.getClassGroupIds())){
            throw new BizException("请指定班级");
        }
        if(Objects.isNull(coursePostPoneInfo.getPauseDate())){
            throw new BizException("请指定课程暂停时间");
        }
        if(Objects.isNull(coursePostPoneInfo.getRecoveryDate())){
            throw new BizException("请指定课程恢复时间");
        }
        //间隔天数
        int betweenDays = DateUtil.daysBetween(coursePostPoneInfo.getPauseDate(), coursePostPoneInfo.getRecoveryDate());
        List<CourseSchedule> classGroupCourseSchedulesWithDate = courseScheduleDao.findClassGroupCourseSchedulesWithDate(coursePostPoneInfo.getClassGroupIds(), coursePostPoneInfo.getPauseDate());

        if(CollectionUtils.isEmpty(classGroupCourseSchedulesWithDate)){
            throw new BizException("选择的班级上在指定日期之后不存在需要调整的课程");
        }
		Date date = new Date();
		List<Long> courseIds = classGroupCourseSchedulesWithDate.stream().map(e -> e.getId()).collect(Collectors.toList());
		//获取修改日志
		List<CourseScheduleModifyLog> modifyLogs = getModifyLogs(courseIds,classGroupCourseSchedulesWithDate,user.getId(),date);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(coursePostPoneInfo.getRecoveryDate());

		Set<String> holidayDays = new HashSet<>();

		if (coursePostPoneInfo.isSkipHoliday()) {
			SysConfig holidaySetting = sysConfigService.findByParamName(SysConfigService.HOLIDAY_SETTING);
			if(Objects.nonNull(holidaySetting)&&StringUtils.isNotBlank(holidaySetting.getParanValue())){
				holidayDays = new HashSet<>(JSON.parseArray(holidaySetting.getParanValue(), String.class));
			}
		}

        classGroupCourseSchedulesWithDate.sort(Comparator.comparing(CourseSchedule::getStartClassTime));

        //保存修改记录
        for (int i=0;i<classGroupCourseSchedulesWithDate.size();i++) {
            CourseSchedule courseSchedule=classGroupCourseSchedulesWithDate.get(i);
            if(Objects.nonNull(courseSchedule.getNewCourseId())){
            	throw new BizException("选择的班级中存在已合并课程，无法进行顺延操作");
			}
            if(Integer.valueOf(1).equals(courseSchedule.getIsLock())){
				throw new BizException("选择的班级中部分课程已被锁定，无法进行顺延操作");
			}
            calendar.setTime(courseSchedule.getClassDate());
            calendar.add(Calendar.DATE, betweenDays);

            if (coursePostPoneInfo.isSkipHoliday() && holidayDays.contains(DateUtil.format(calendar.getTime(), "yyyy-MM-dd"))) {
                betweenDays=betweenDays+7;
                calendar.add(Calendar.DATE, betweenDays);
                i=i-1;
                continue;
            }
            classGroupCourseSchedulesWithDate.get(i).setClassDate(calendar.getTime());
        }
        checkNewCourseSchedules(classGroupCourseSchedulesWithDate,false,false);
        courseScheduleDao.batchUpdate(classGroupCourseSchedulesWithDate);
        //保存操作日志
		saveModifyLog(modifyLogs,courseIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAppendVipGroupCourses(VipGroupCourseAdjustInfoDto vipGroupCourseAdjustInfo) {
        if (Objects.isNull(vipGroupCourseAdjustInfo.getVipGroupId())) {
            throw new BizException("请指定小课");
        }
        if (Objects.isNull(vipGroupCourseAdjustInfo.getCourseCreateStartTime())) {
            throw new BizException("请指定排课起始时间;");
        }
        if (CollectionUtils.isEmpty(vipGroupCourseAdjustInfo.getCourseTimes())) {
            throw new BizException("请指定排课周期");
        }
        if (Objects.isNull(vipGroupCourseAdjustInfo.getSingleClassPrice())) {
            throw new BizException("请指定课程单价");
        }
        if (Objects.isNull(vipGroupCourseAdjustInfo.getCourseCount())) {
            throw new BizException("请指定排课次数");
        }
        Date courseCreateStartTime = vipGroupCourseAdjustInfo.getCourseCreateStartTime();
        Date now = new Date();
        Date today = DateUtil.stringToDate(DateUtil.dateToString(now, DateUtil.ISO_EXPANDED_DATE_FORMAT),
                DateUtil.ISO_EXPANDED_DATE_FORMAT);
        if (courseCreateStartTime.before(today)) {
            throw new BizException("排课起始时间不能小于当前时间");
        }

        VipGroup vipGroup = vipGroupDao.get(vipGroupCourseAdjustInfo.getVipGroupId().longValue());
        if (Objects.isNull(vipGroup)) {
            throw new BizException("指定课程不存在");
        }

        if (vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)) {
            throw new BizException("报名中的课程不能加课");
        }

        ClassGroup classGroup = classGroupDao.findByGroupAndType(vipGroupCourseAdjustInfo.getVipGroupId().toString(), GroupType.VIP.getCode());
        if (Objects.isNull(classGroup)) {
            throw new BizException("对应班级不存在");
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(courseCreateStartTime);

		Set<String> holidayDays = new HashSet<>();

		if (vipGroupCourseAdjustInfo.isHoliday()) {
			SysConfig holidaySetting = sysConfigService.findByParamName(SysConfigService.HOLIDAY_SETTING);
			if(Objects.nonNull(holidaySetting)&&StringUtils.isNotBlank(holidaySetting.getParanValue())){
				holidayDays = new HashSet<>(JSON.parseArray(holidaySetting.getParanValue(), String.class));
			}
		}

        List<CourseSchedule> courseSchedules = new ArrayList<>();

        while (true) {
            if (vipGroupCourseAdjustInfo.isHoliday() && holidayDays.contains(DateUtil.format(calendar.getTime(), "yyyy-MM-dd"))) {
                calendar.add(Calendar.DATE, 1);
                continue;
            }
            int i = calendar.get(Calendar.DAY_OF_WEEK);
            if (i == 1) {
                i = 7;
            } else {
                i = --i;
            }
            for (CourseTimeDto courseTime : vipGroupCourseAdjustInfo.getCourseTimes()) {
                if (Objects.isNull(courseTime.getDayOfWeek())) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() < 1 || courseTime.getDayOfWeek() > 7) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() == i) {
                    String dateYmdStr = DateUtil.dateToString(calendar.getTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT);
                    dateYmdStr = dateYmdStr + " " + courseTime.getStartClassTime();
                    Date courseStartTime = DateUtil.stringToDate(dateYmdStr, "yyyy-MM-dd HH:mm");
                    Date courseEndTime = DateUtil.addMinutes(courseStartTime, vipGroup.getSingleClassMinutes());
                    CourseSchedule courseSchedule = new CourseSchedule();
                    courseSchedule.setGroupType(GroupType.VIP);
                    courseSchedule.setMusicGroupId(vipGroup.getId().toString());
                    courseSchedule.setClassGroupId(classGroup.getId());
                    courseSchedule.setClassDate(courseStartTime);
                    courseSchedule.setStartClassTime(courseStartTime);
                    courseSchedule.setEndClassTime(courseEndTime);
                    courseSchedule.setName(vipGroup.getName());

					if (!DateUtil.isSameDay(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime())) {
						throw new BizException("上课时间不允许跨天，请重新调整上课时间");
					}
					
                    if(vipGroupCourseAdjustInfo.getTeachMode().equals(TeachModeEnum.OFFLINE)){
						courseSchedule.setSchoolId(vipGroup.getTeacherSchoolId());
					}
                    courseSchedule.setStatus(CourseStatusEnum.NOT_START);
                    courseSchedule.setTeachMode(vipGroupCourseAdjustInfo.getTeachMode());
                    courseSchedules.add(courseSchedule);
                }
                if (courseSchedules.size() == vipGroupCourseAdjustInfo.getCourseCount()) {
                    break;
                }
            }
            if (courseSchedules.size() == vipGroupCourseAdjustInfo.getCourseCount()) {
                break;
            }
            calendar.add(Calendar.DATE, 1);
        }
//		checkNewCourseSchedules(courseSchedules,false);
//		courseScheduleDao.batchUpdate(courseSchedules);
        VipGroupApplyDto vipGroupApplyDto = new VipGroupApplyDto();
        VipGroupApplyBaseInfoDto vipGroupApplyBaseInfoDto = new VipGroupApplyBaseInfoDto();
        vipGroupApplyBaseInfoDto.setId(vipGroup.getId());
        vipGroupApplyDto.setVipGroupApplyBaseInfo(vipGroupApplyBaseInfoDto);
        vipGroupApplyDto.setCourseSchedules(courseSchedules);
        vipGroupApplyDto.setSingleClassPrice(vipGroupCourseAdjustInfo.getSingleClassPrice());
        vipGroupService.appendVipGroupCourseSchedules(vipGroupApplyDto);
        classGroupService.updateClassGroupInfo(classGroup.getId());
//        vipGroupService.checkVipCourseIsInScore(vipGroupCourseAdjustInfo.getVipGroupId().longValue());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void courseAdjust(List<CourseSchedule> newCourseSchedules) {
        Date date = new Date();
		// 课程信息处理
		List<Long> courseScheduleIds = newCourseSchedules.stream().map(CourseSchedule::getId).distinct().collect(Collectors.toList());

        //已结算的课不能调整
        /*List<Map<Long, Integer>> courseSettlementMaps = courseScheduleTeacherSalaryDao.checkCoursesIsSettlement(courseScheduleIds);
        if(courseSettlementMaps!=null && courseSettlementMaps.size()>0){
        	throw new BizException("调整的课程中存在已结算的课程");
        }*/

        //查询数据库中的课程信息
        List<CourseSchedule> oldCourseScheduleList = courseScheduleDao.findByCourseScheduleIds(courseScheduleIds);
        //记录操作日志
		SysUser sysUser = sysUserFeignService.queryUserInfo();
		if (null == sysUser) {
			throw new BizException("获取用户信息失败");
		}
		//获取修改日志
		List<CourseScheduleModifyLog> modifyLogs = getModifyLogs(courseScheduleIds,oldCourseScheduleList,sysUser.getId(),date);

		Map<Long, CourseSchedule> oldCourseScheduleMap = oldCourseScheduleList.stream().collect(Collectors.toMap(CourseSchedule::getId, c -> c));

        for(CourseSchedule newCourseSchedule : newCourseSchedules){

        	//获取数据库中的记录
            CourseSchedule oldCourseSchedule = oldCourseScheduleMap.get(newCourseSchedule.getId());

            if (Objects.isNull(newCourseSchedule.getGroupType())) {
                newCourseSchedule.setGroupType(oldCourseSchedule.getGroupType());
            }

            if(CourseStatusEnum.OVER.equals(oldCourseSchedule.getStatus())&&newCourseSchedule.getStartClassTime().compareTo(date)<0){
            	throw new BizException("调整无效,已结束不能调整至已结束");
			}
            
            //课程是否已结算
            int settlementNum = courseScheduleTeacherSalaryDao.checkCourseIsSettlement(oldCourseSchedule.getId().intValue());
            if (settlementNum > 0) {
                throw new BizException("{}[{}]{}-{}课程已结算的",
                        oldCourseSchedule.getName(),
                        oldCourseSchedule.getId(),
                        DateUtil.dateToString(oldCourseSchedule.getStartClassTime(),
                                DateUtil.EXPANDED_DATE_TIME_FORMAT),
                        DateUtil.dateToString(oldCourseSchedule.getEndClassTime(),
                                DateUtil.EXPANDED_DATE_TIME_FORMAT));
            }

			if (newCourseSchedule.getGroupType() != GroupType.COMM) {
				// 学生已点名不能调整（请假可以调整）
				List<StudentAttendance> studentAttendanceList = studentAttendanceDao.findByCourseId(oldCourseSchedule.getId());

				for (StudentAttendance studentAttendance : studentAttendanceList) {
					if (studentAttendance.getStatus() != StudentAttendanceStatusEnum.LEAVE
						|| (studentAttendance.getStatus() == StudentAttendanceStatusEnum.LEAVE
							&&StringUtils.isBlank(studentAttendance.getRemark()))) {
						throw new BizException("{}[{}] {}-{}课程已点名", oldCourseSchedule.getName(), oldCourseSchedule.getId(), DateUtil.dateToString(
								oldCourseSchedule.getStartClassTime(), DateUtil.EXPANDED_DATE_TIME_FORMAT), DateUtil.dateToString(
								oldCourseSchedule.getEndClassTime(), DateUtil.EXPANDED_DATE_TIME_FORMAT));
					}
				}
			}

            if(!CollectionUtils.isEmpty(newCourseSchedule.getTeachingTeacherIdList())){
                if (newCourseSchedule.getTeachingTeacherIdList().contains(newCourseSchedule.getActualTeacherId())){
                    throw new BizException("主教和助教不可重复");
                }
            }

            if(newCourseSchedule.getStatus() == oldCourseSchedule.getStatus() && newCourseSchedule.getStatus() == CourseStatusEnum.OVER){
            	throw new BizException("已结束的课程需要调整课程状态");
            }
            
            /*if (oldCourseSchedule.getType().equals(CourseSchedule.CourseScheduleType.VIP)) {
                VipGroup vipGroup = vipGroupDao.get(Long.valueOf(oldCourseSchedule.getMusicGroupId()));
                if(Objects.isNull(vipGroup)){
                    throw new BizException("课程不存在");
                }
                Date endClassTime = DateUtil.addMinutes(newCourseSchedule.getStartClassTime(), vipGroup.getSingleClassMinutes());
                newCourseSchedule.setEndClassTime(endClassTime);
            }*/

            if(Objects.isNull(newCourseSchedule.getMusicGroupId())){
                newCourseSchedule.setMusicGroupId(oldCourseSchedule.getMusicGroupId());
            }

            if (Objects.isNull(newCourseSchedule.getTeachMode())) {
                newCourseSchedule.setTeachMode(oldCourseSchedule.getTeachMode());
            }

			if (newCourseSchedule.getTeachMode() != oldCourseSchedule.getTeachMode()
					&& newCourseSchedule.getTeachMode() == TeachModeEnum.OFFLINE
					&& Objects.isNull(newCourseSchedule.getSchoolId())) {
				throw new BizException("请设置教学点");
			}

            if (Objects.isNull(newCourseSchedule.getSchoolId())) {
                newCourseSchedule.setSchoolId(oldCourseSchedule.getSchoolId());
            }
			if (newCourseSchedule.getTeachMode() != oldCourseSchedule.getTeachMode() && newCourseSchedule.getTeachMode() == TeachModeEnum.ONLINE) {
				newCourseSchedule.setSchoolId(null);
			}

            if (Objects.isNull(newCourseSchedule.getActualTeacherId())) {
                newCourseSchedule.setActualTeacherId(oldCourseSchedule.getActualTeacherId());
            }
            if (Objects.isNull(newCourseSchedule.getType())) {
                newCourseSchedule.setType(oldCourseSchedule.getType());
            }
            if(Objects.isNull(newCourseSchedule.getStartClassTime())){
                newCourseSchedule.setStartClassTime(oldCourseSchedule.getStartClassTime());
            }
            if(newCourseSchedule.getEndClassTime() == null){
            	int minutes = DateUtil.minutesBetween(oldCourseSchedule.getStartClassTime(), oldCourseSchedule.getEndClassTime());
            	newCourseSchedule.setEndClassTime(DateUtil.addMinutes(newCourseSchedule.getStartClassTime(), minutes));
            }
            //判断上课时间是否跨天
			if (!DateUtil.isSameDay(newCourseSchedule.getStartClassTime(), newCourseSchedule.getEndClassTime())) {
				throw new BizException("上课时间不允许跨天，请重新调整上课时间");
			}
            if(Objects.isNull(newCourseSchedule.getClassGroupId())){
                newCourseSchedule.setClassGroupId(oldCourseSchedule.getClassGroupId());
            }
            if(Objects.isNull(newCourseSchedule.getClassDate())){
                newCourseSchedule.setClassDate(oldCourseSchedule.getClassDate());
            }
            if (newCourseSchedule.getStartClassTime().after(date)) {
                newCourseSchedule.setStatus(CourseStatusEnum.NOT_START);
            }
            if (newCourseSchedule.getStartClassTime().before(date) && newCourseSchedule.getEndClassTime().after(date)) {
                newCourseSchedule.setStatus(CourseStatusEnum.UNDERWAY);
            }
            if (newCourseSchedule.getEndClassTime().before(date)) {
                newCourseSchedule.setStatus(CourseStatusEnum.OVER);
            }
            
			if (newCourseSchedule.getType() == CourseScheduleType.PRACTICE) {
				PracticeGroup practiceGroup = practiceGroupDao.get(Long.parseLong(newCourseSchedule.getMusicGroupId()));
				if (practiceGroup.getType() != TRIAL) {
					if (DateUtil.minutesBetween(newCourseSchedule.getStartClassTime(), practiceGroup.getCoursesStartDate()) > 0) {
						throw new BizException("调整失败: 调整时间不得早于开课时间");
					}
					if (DateUtil.minutesBetween(practiceGroup.getCoursesExpireDate(), newCourseSchedule.getEndClassTime()) > 0) {
						throw new BizException("调整失败: 截止时间超过课程有效期");
					}
					practiceGroup.setCoursesStartDate(courseScheduleDao.getFirstTime(practiceGroup.getId(),PRACTICE.getCode()));
					practiceGroup.setCoursesExpireDate(courseScheduleDao.getLastTime(practiceGroup.getId(),PRACTICE.getCode()));
					practiceGroup.setUpdateTime(date);
					practiceGroupDao.update(practiceGroup);
				}
			}
        }

        //课程冲突检测
        checkNewCourseSchedules(newCourseSchedules, false,false);

		Map<Long, List<TeacherAttendance>> teacherAttendanceMap = new HashMap<Long, List<TeacherAttendance>>();
		// 查询老师的考勤
		List<TeacherAttendance> teacherAttendances = teacherAttendanceDao.findTeacherIdByCourseSchedule(courseScheduleIds);

		for (TeacherAttendance ta : teacherAttendances) {
			List<TeacherAttendance> tas = teacherAttendanceMap.get(ta.getCourseScheduleId());
			if (tas == null) {
				tas = new ArrayList<TeacherAttendance>();
			}
			tas.add(ta);
			teacherAttendanceMap.put(ta.getCourseScheduleId(), tas);
		}

		Long courseScheduleId = null;
		List<TeacherAttendance> insertTeacherAttendanceList = new ArrayList<TeacherAttendance>();
		List<CourseScheduleTeacherSalary> insertCourseScheduleTeacherSalaryList = new ArrayList<CourseScheduleTeacherSalary>();

		// 获取课程对应教学点补贴
		List<Map<Long, BigDecimal>> courseSubsidyByCourses = courseScheduleTeacherSalaryDao.findCourseSubsidyByCourses(courseScheduleIds);
		Map<Integer, BigDecimal> courseSubsidyMap = MapUtil.convertIntegerMap(courseSubsidyByCourses);

		// 课程对应乐团结算方式集合
		List<Map<String, String>> musicGroupSettlementTypeByCourse = courseScheduleTeacherSalaryDao.findMusicGroupSettlementTypeByCourse(courseScheduleIds);
		Map<String, String> musicGroupSettlementsMap = MapUtil.convertMybatisMap(musicGroupSettlementTypeByCourse);

		Map<Long,Map<Integer,CourseScheduleTeacherSalary>> courseScheduleTeacherSalaryMap = new HashMap<Long, Map<Integer,CourseScheduleTeacherSalary>>();
		List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaryList = courseScheduleTeacherSalaryDao.findByCourseSchedules(courseScheduleIds);

		for (CourseScheduleTeacherSalary ts : courseScheduleTeacherSalaryList) {
			Map<Integer, CourseScheduleTeacherSalary> map = courseScheduleTeacherSalaryMap.get(ts.getCourseScheduleId());
			if (map == null) {
				map = new HashMap<Integer, CourseScheduleTeacherSalary>();
			}
			map.put(ts.getUserId(), ts);
			courseScheduleTeacherSalaryMap.put(ts.getCourseScheduleId(), map);
		}
		List<CourseScheduleStudentPayment> insertCourseScheduleStudentPaymentList = new ArrayList<CourseScheduleStudentPayment>();

		for (CourseSchedule newCourseSchedule : newCourseSchedules) {
			courseScheduleId = newCourseSchedule.getId();
			CourseSchedule oldCourseSchedule = oldCourseScheduleMap.get(courseScheduleId);

			// 修改了主教/助教/课程状态，需修改考勤记录
			List<TeacherAttendance> teacherAttendanceList = teacherAttendanceMap.get(courseScheduleId);

			List<Integer> oldTeacherIdList = new ArrayList<Integer>();
			if(teacherAttendanceList != null){
				oldTeacherIdList = teacherAttendanceList.stream().map(TeacherAttendance::getTeacherId).distinct().collect(Collectors.toList());
			}
			List<Integer> newTeacherIdList = new ArrayList<>();
            newTeacherIdList.addAll(newCourseSchedule.getTeachingTeacherIdList());
            newTeacherIdList.add(newCourseSchedule.getActualTeacherId());

			if (newCourseSchedule.getStatus() != CourseStatusEnum.OVER) {
				// 清理原来考勤
				teacherAttendanceDao.deletebyCourseScheduleId(courseScheduleId);

				// 新增考勤
				for (Integer teacherId : newTeacherIdList) {
					TeacherAttendance ta = new TeacherAttendance();
					ta.setClassGroupId(newCourseSchedule.getClassGroupId());
					ta.setCourseScheduleId(courseScheduleId);
					ta.setCreateTime(date);
					ta.setGroupType(newCourseSchedule.getGroupType());
					ta.setMusicGroupId(newCourseSchedule.getMusicGroupId());
					ta.setTeacherId(teacherId);
					insertTeacherAttendanceList.add(ta);
				}
				
			}

			if(newCourseSchedule.getStatus() == CourseStatusEnum.NOT_START && newCourseSchedule.getGroupType() == GroupType.MUSIC){
				//查询新生(之前排课没有这个人，后来新进来的学生)
				List<ClassGroupStudentMapper> newStudentList = classGroupStudentMapperDao.queryNewStudentListByCourseScheduleId(courseScheduleId);
				if(newStudentList.size() > 0){
					//生成courseScheduleStudentPayment记录
					for(ClassGroupStudentMapper cgsm : newStudentList){
						CourseScheduleStudentPayment sp = new CourseScheduleStudentPayment();
						sp.setClassGroupId(newCourseSchedule.getClassGroupId());
						sp.setCourseScheduleId(courseScheduleId);
						sp.setCreateTime(date);
						sp.setExpectPrice(new BigDecimal(0));
						sp.setGroupType(GroupType.MUSIC);
						sp.setMusicGroupId(newCourseSchedule.getMusicGroupId());
						sp.setUpdateTime(date);
						sp.setUserId(cgsm.getUserId());

						insertCourseScheduleStudentPaymentList.add(sp);
					}
				}
			}

			VipGroup vipGroup = vipGroupDao.findByCourseSchedule(courseScheduleId);

			if(Objects.nonNull(vipGroup)
					&&!VipGroupStatusEnum.PROGRESS.equals(vipGroup.getStatus())
					&&!VipGroupStatusEnum.FINISHED.equals(vipGroup.getStatus())){
				throw new BizException("非进行中或完成的课程组不允许进行此操作");
			}

			if(Objects.nonNull(vipGroup) && newCourseSchedule.getStartClassTime().after(date)){
				if(newCourseSchedule.getEndClassTime().compareTo(vipGroup.getCoursesExpireDate())>0){
					vipGroup.setCoursesExpireDate(newCourseSchedule.getEndClassTime());
				}
				vipGroup.setStatus(VipGroupStatusEnum.PROGRESS);
				vipGroup.setUpdateTime(date);
				vipGroupDao.update(vipGroup);
			}

			if (newCourseSchedule.getStatus() == CourseStatusEnum.NOT_START) {
				//如果已结束修改成了未开始，需要更新学生考勤记录
				studentAttendanceDao.deleteStudentAttendancesByCourse(courseScheduleId);
			}

			if ((newCourseSchedule.getStatus() != oldCourseSchedule.getStatus() && newCourseSchedule.getStatus() == CourseStatusEnum.NOT_START)) {
                
				// 清理课程作业
				courseHomeworkService.delHomwworkByCourseScheduleId(courseScheduleId);

				//删除申述
				courseScheduleComplaintsDao.delByCourseScheduleId(courseScheduleId);
				
				//删除评论
				courseScheduleReviewDao.delByCourseScheduleId(courseScheduleId);

				List<CourseScheduleStudentPayment> courseScheduleStudentPayments = courseScheduleStudentPaymentDao.findByCourseSchedule(courseScheduleId);
				if(!CollectionUtils.isEmpty(courseScheduleStudentPayments)){
					List<Integer> studentIds = courseScheduleStudentPayments.stream().map(CourseScheduleStudentPayment::getUserId).collect(Collectors.toList());
					studentServeService.updateExercisesSituation(oldCourseSchedule.getClassDate(), studentIds, oldCourseSchedule.getActualTeacherId());
				}
			}

			// 计算课程时长
			int oldMinutes = DateUtil.minutesBetween(oldCourseSchedule.getStartClassTime(), oldCourseSchedule.getEndClassTime());
			int newMinutes = DateUtil.minutesBetween(newCourseSchedule.getStartClassTime(), newCourseSchedule.getEndClassTime());

			// 如果修改了老师、课程类型、课程时长、教学模式，需要修改课酬
			if (!ListUtil.isEquals(oldTeacherIdList, newTeacherIdList) || newCourseSchedule.getType() != oldCourseSchedule.getType()
					|| newCourseSchedule.getTeachMode() != oldCourseSchedule.getTeachMode() || oldMinutes != newMinutes) {

				Map<Integer, Teacher> teacherMap = null;
				Map<Integer, Map<CourseScheduleType, TeacherDefaultMusicGroupSalary>> musicGroupSalaryMap = new HashMap<Integer, Map<CourseScheduleType, TeacherDefaultMusicGroupSalary>>();
				Map<Integer, Map<Integer, TeacherDefaultVipGroupSalary>> vipGroupSalaryMap = new HashMap<Integer, Map<Integer, TeacherDefaultVipGroupSalary>>();

				if (newCourseSchedule.getGroupType() == GroupType.MUSIC) {
					// 所有教师列表
					List<Teacher> teachers = teacherDao.findByTeacherIds(newTeacherIdList);
					teacherMap = teachers.stream().collect(Collectors.toMap(Teacher::getId, teacher -> teacher));

					// 所有老师默认乐团课酬
					List<TeacherDefaultMusicGroupSalary> teacherDefaultMusicGroupSalaries = teacherDefaultMusicGroupSalaryDao.findByTeacher(newTeacherIdList);
					for (TeacherDefaultMusicGroupSalary tdms : teacherDefaultMusicGroupSalaries) {
						Map<CourseScheduleType, TeacherDefaultMusicGroupSalary> map = musicGroupSalaryMap.get(tdms.getUserId());
						if (map == null) {
							map = new HashMap<CourseSchedule.CourseScheduleType, TeacherDefaultMusicGroupSalary>();
						}
						map.put(tdms.getCourseScheduleType(), tdms);
						musicGroupSalaryMap.put(tdms.getUserId(), map);
					}
				} else if (newCourseSchedule.getGroupType() == GroupType.VIP) {
					// 所有老师默认vip课酬
					List<TeacherDefaultVipGroupSalary> teacherDefaultVipGroupSalaries = teacherDefaultVipGroupSalaryDao.queryByUserIdList(newTeacherIdList);
					for (TeacherDefaultVipGroupSalary tdvs : teacherDefaultVipGroupSalaries) {
						Map<Integer, TeacherDefaultVipGroupSalary> map = vipGroupSalaryMap.get(tdvs.getUserId());
						if (map == null) {
							map = new HashMap<Integer, TeacherDefaultVipGroupSalary>();
						}
						map.put(tdvs.getVipGroupCategoryId(), tdvs);
						vipGroupSalaryMap.put(tdvs.getUserId(), map);
					}
				}

				// 删除课酬
				List<Long> courseScheduleIdList = new ArrayList<Long>();
				courseScheduleIdList.add(courseScheduleId);
				courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIdList);

				for (Integer teacherId : newTeacherIdList) {
					CourseScheduleTeacherSalary ts = new CourseScheduleTeacherSalary();
					ts.setClassGroupId(newCourseSchedule.getClassGroupId());
					ts.setCourseScheduleId(courseScheduleId);
					ts.setCreateTime(date);
					ts.setGroupType(newCourseSchedule.getGroupType());
					ts.setMusicGroupId(newCourseSchedule.getMusicGroupId());
					ts.setSubsidy(courseSubsidyMap.get(courseScheduleId));
					if (teacherId == newCourseSchedule.getActualTeacherId().intValue()) {
						ts.setTeacherRole(TeachTypeEnum.BISHOP);
					} else {
						ts.setTeacherRole(TeachTypeEnum.TEACHING);
					}
					ts.setUpdateTime(date);
					ts.setUserId(teacherId);
					// 重新生成课酬
					if (newCourseSchedule.getGroupType() == GroupType.MUSIC) {
						courseScheduleTeacherSalaryService.createMusicGroupCourseTeacherSalary(null, newCourseSchedule, ts);
					} else if (newCourseSchedule.getGroupType() == GroupType.VIP) {
						Map<String, BigDecimal> salaryMap = vipGroupService.countVipGroupPredictFee(vipGroup, teacherId, null, null);

						BigDecimal teacherSalary=BigDecimal.ZERO;

						if(Objects.nonNull(salaryMap)){
							teacherSalary=newCourseSchedule.getTeachMode() == TeachModeEnum.OFFLINE?salaryMap.get("offlineTeacherSalary"):salaryMap.get("onlineTeacherSalary");
						}

						ts.setExpectSalary(teacherSalary);

					} else if (newCourseSchedule.getGroupType() == PRACTICE) {
						List<TeacherDefaultPracticeGroupSalary> teacherDefaultPracticeGroupSalaryList = teacherDefaultPracticeGroupSalaryDao
								.queryByUserId(teacherId);
						if (teacherDefaultPracticeGroupSalaryList != null && teacherDefaultPracticeGroupSalaryList.size() > 0) {
							ts.setExpectSalary(teacherDefaultPracticeGroupSalaryList.get(0).getMainTeacherSalary());
						} else {
							throw new BizException("请设置老师 的网管课课酬");
						}
					}
					insertCourseScheduleTeacherSalaryList.add(ts);
				}
			}
		}

		if (insertTeacherAttendanceList.size() > 0) {
			teacherAttendanceDao.batchInsert(insertTeacherAttendanceList);
		}

		if (insertCourseScheduleTeacherSalaryList.size() > 0) {
			courseScheduleTeacherSalaryDao.batchInsert(insertCourseScheduleTeacherSalaryList);
		}

		if(newCourseSchedules.size() > 0){
			courseScheduleDao.batchUpdate(newCourseSchedules);
            List<Integer> classGroupIds = newCourseSchedules.stream().filter(courseSchedule -> Objects.nonNull(courseSchedule.getClassGroupId())).map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(classGroupIds)){
                classGroupService.updateClassGroupsCourseInfo(classGroupIds);
            }
        }

		if(insertCourseScheduleStudentPaymentList.size() > 0){
			courseScheduleStudentPaymentDao.batchInsert(insertCourseScheduleStudentPaymentList);
		}

		//保存日志调整信息
		saveModifyLog(modifyLogs,courseScheduleIds);

		courseEventSource.courseStatusChange(new HashSet<>(courseScheduleIds));

		imUserFriendService.refreshCourseImUserFriend(courseScheduleId);
		// 推送
		try {
			Set<Integer> teacherIds = newCourseSchedules.stream().map(e -> e.getActualTeacherId()).collect(Collectors.toSet());
			if (teacherIds == null) {
				teacherIds = new HashSet<>();
			}
			teacherIds.addAll(oldCourseScheduleList.stream().map(e -> e.getActualTeacherId()).collect(Collectors.toSet()));
			Map<Integer, String> map = new HashMap<>(teacherIds.size());
			teacherIds.removeAll(Collections.singleton(null));
			teacherIds.forEach(e -> {
				map.put(e, e.toString());
			});
			if (map != null && map.size() > 0) {
				sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_COURSE_SCHEDULE_CHANGE_RESULT, map, null, 0, "7",
						"TEACHER");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void classStartDateAdjust(List<CourseSchedule> newCourseSchedules) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (null == sysUser) {
            throw new BizException("获取用户信息失败");
        }
        List<Long> newCourseScheduleIds = newCourseSchedules.stream().map(CourseSchedule::getId).collect(Collectors.toList());
        //获取对应未修改的课程列表
        List<CourseSchedule> oldCourseScheduleList = courseScheduleDao.findByCourseScheduleIds(newCourseScheduleIds);
//		if(oldCourseScheduleList.size()!=newCourseSchedules.size()){
        if (oldCourseScheduleList.size() < newCourseSchedules.size()) {
            throw new BizException("课程信息错误");
        }

        Date now = new Date();

		//获取修改日志
		List<CourseScheduleModifyLog> modifyLogs = getModifyLogs(newCourseScheduleIds,oldCourseScheduleList,sysUser.getId(),now);
        //明天日期
//        Date tomorrow = DateUtil.addDays1(now, 1);

        //需要生成课程课酬的课程计划
        List<CourseSchedule> needCreateCourseScheduleTeacherSalaryCourse = new ArrayList<>();
        //需要重新学生缴费记录的课
        List<CourseSchedule> needCreateStudentPaymentCourses = new ArrayList<>();

        //课程对应助教集合
        List<CourseScheduleTeacherSalary> teachingTeacherSalarys = courseScheduleDao.findTeachingTeachers(newCourseScheduleIds);
        Map<Long, List<CourseScheduleTeacherSalary>> courseTeachingTeacherMaps = teachingTeacherSalarys.stream().collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getCourseScheduleId));

        Map<Long, List<CourseSchedule>> oldCourseScheduleMap = oldCourseScheduleList.stream().collect(Collectors.groupingBy(CourseSchedule::getId));

        Map<Long, CourseSchedule> oldCourseSchedules = new HashMap<>();

        List<Integer> classGroupIds = oldCourseScheduleList.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
//        List<ClassGroup> classGroups = classGroupDao.findByClassGroupIds(classGroupIds);
//        Map<Integer, ClassGroup> idClassGroupMap = classGroups.stream().collect(Collectors.toMap(ClassGroup::getId, classGroup -> classGroup));

        SysConfig advanceLeaveHoursConfig = sysConfigService.findByParamName(SysConfigService.ENABLE_TEACHER_COURSE_ADJUST_DEFAULT_HOURS);
        Integer advanceLeaveHours=advanceLeaveHoursConfig.getParanValue(Integer.class);
        List<Map<Long, Integer>> courseLeaveStudentNumMaps = studentAttendanceDao.countCourseLeaveStudentNumWithFourHoursAgo(newCourseScheduleIds, advanceLeaveHours);
        Map<Long,Long> courseLeaveStudentNumMap = MapUtil.convertIntegerMap((courseLeaveStudentNumMaps));

        List<Map<Integer, Integer>> classGroupStudentNumMaps = classGroupStudentMapperDao.countClassGroupsStudentNum(classGroupIds, ClassGroupStudentStatusEnum.NORMAL);
        Map<Integer, Long> classGroupStudentNumMap = MapUtil.convertIntegerMap(classGroupStudentNumMaps);


        newCourseSchedules.forEach(newCourseSchedule -> {
            CourseSchedule oldCourseSchedule = oldCourseScheduleMap.get(newCourseSchedule.getId()).get(0);
            if (!sysUser.getUserType().contains("SYSTEM") && sysUser.getUserType().contains("TEACHER")) {
                Long normalStudentNum = classGroupStudentNumMap.get(oldCourseSchedule.getClassGroupId());
                Long courseLeaveStudentNum = courseLeaveStudentNumMap.get(newCourseSchedule.getId());
                if(oldCourseSchedule.getGroupType().equals(GroupType.VIP)
                        &&Objects.nonNull(courseLeaveStudentNum)
                        &&Objects.nonNull(normalStudentNum)
                        &&courseLeaveStudentNum.intValue()==normalStudentNum.intValue()){
                    if(!DateUtil.isSameDay(now,oldCourseSchedule.getStartClassTime())&&now.after(oldCourseSchedule.getStartClassTime())){
                        throw new BizException("当前时间不可对相关课程进行调整");
                    }
                }else{
                    if(DateUtil.addHours(now,advanceLeaveHours).after(oldCourseSchedule.getStartClassTime())){
                        throw new BizException("请在课程开始前{}小时进行调整",advanceLeaveHours);
                    }
                }
            }

            oldCourseSchedules.put(newCourseSchedule.getId(), oldCourseSchedule);

            if (newCourseSchedule.getStartClassTime().after(now)){
                teacherAttendanceDao.cleanCourseTeacherSignInfo(newCourseSchedule.getId());
                needCreateStudentPaymentCourses.add(oldCourseSchedule);
                //删除申述
                courseScheduleComplaintsDao.delByCourseScheduleId(newCourseSchedule.getId());
                //清除考勤申述
                teacherAttendanceDao.clearAttendanceComplaint(newCourseSchedule.getId());
            }

            boolean courseTimeIsChange = false;
            int newCourseTime = DateUtil.minutesBetween(newCourseSchedule.getStartClassTime(), newCourseSchedule.getEndClassTime());
            int oldCourseTime = DateUtil.minutesBetween(oldCourseSchedule.getStartClassTime(), oldCourseSchedule.getEndClassTime());
            if (newCourseTime != oldCourseTime) {
                courseTimeIsChange = true;
            }

            if(newCourseSchedule.getStartClassTime().after(oldCourseSchedule.getStartClassTime())){
                teacherAttendanceDao.cleanCourseTeacherSignInfo(newCourseSchedule.getId());
                //删除申述
                courseScheduleComplaintsDao.delByCourseScheduleId(newCourseSchedule.getId());
                //清除考勤申述
                teacherAttendanceDao.clearAttendanceComplaint(newCourseSchedule.getId());
            }

            oldCourseSchedule.setClassDate(newCourseSchedule.getClassDate());
            oldCourseSchedule.setStartClassTime(newCourseSchedule.getStartClassTime());
            oldCourseSchedule.setEndClassTime(newCourseSchedule.getEndClassTime());
            oldCourseSchedule.setStatus(newCourseSchedule.getStatus());
            //被修改的教师编号列表，需要将预计薪水置零
            List<Integer> beReplaceTeacherIds = new ArrayList<>();

            if (oldCourseSchedule.getType() == CourseSchedule.CourseScheduleType.VIP) {
                boolean oldTeacherIsNull = Objects.isNull(oldCourseSchedule.getActualTeacherId());
                boolean newTeacherIsNull = Objects.isNull(newCourseSchedule.getActualTeacherId());
                if (newTeacherIsNull && !oldTeacherIsNull) {
                    newCourseSchedule.setActualTeacherId(oldCourseSchedule.getActualTeacherId());
                    newCourseSchedule.setTeachMode(oldCourseSchedule.getTeachMode());
                }
                boolean oldSchoolIsNull = Objects.isNull(oldCourseSchedule.getSchoolId());
                boolean newSchoolIsNull = Objects.isNull(newCourseSchedule.getSchoolId());
                boolean teacherIsChange = oldTeacherIsNull || (!newTeacherIsNull && !oldCourseSchedule.getActualTeacherId().equals(newCourseSchedule.getActualTeacherId()));
                boolean schoolIsChange = oldSchoolIsNull || (newSchoolIsNull && !oldCourseSchedule.getSchoolId().equals(newCourseSchedule.getSchoolId()));

                boolean needSchoolId = Objects.nonNull(newCourseSchedule.getTeachMode()) && newCourseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE) && Objects.isNull(newCourseSchedule.getSchoolId());

                if (needSchoolId) {
                    throw new BizException("请设置教学点");
                }

                if (schoolIsChange) {
                    oldCourseSchedule.setSchoolId(newCourseSchedule.getSchoolId());
                }

                if (teacherIsChange) {
                    VipGroup byCourseSchedule = vipGroupDao.findByCourseSchedule(newCourseSchedule.getId());

                    BigDecimal onlineTeacherSalary = new BigDecimal(0), offlineTeacherSalary = new BigDecimal(0);

					Map<String, BigDecimal> salaryMap = vipGroupService.countVipGroupPredictFee(byCourseSchedule, newCourseSchedule.getActualTeacherId(), null, null);

                    List<CourseSchedule> courseSchedules = new ArrayList<>();
                    courseSchedules.add(newCourseSchedule);
                    courseScheduleTeacherSalaryService.createCourseScheduleTeacherVipSalary(byCourseSchedule,
                            courseSchedules,
							salaryMap.get("onlineTeacherSalary"),
							salaryMap.get("offlineTeacherSalary"));
                    if (Objects.nonNull(oldCourseSchedule.getActualTeacherId()) && teacherIsChange) {
                        beReplaceTeacherIds.add(oldCourseSchedule.getActualTeacherId().intValue());
                    }
                }
            } else {
                if (courseTimeIsChange || (Objects.nonNull(newCourseSchedule.getActualTeacherId())
                        && (Objects.isNull(oldCourseSchedule.getActualTeacherId())
                        || !oldCourseSchedule.getActualTeacherId().equals(newCourseSchedule.getActualTeacherId())))) {
                    if (Objects.nonNull(oldCourseSchedule.getActualTeacherId())) {
                        beReplaceTeacherIds.add(oldCourseSchedule.getActualTeacherId().intValue());
                    }
                } else {
                    //如果主教未修改则不需要调整课酬记录
                    newCourseSchedule.setBishopTeacherSalaryNotCreate(true);
                }
                List<CourseScheduleTeacherSalary> courseTeachingTeacherList = courseTeachingTeacherMaps.get(newCourseSchedule.getId());
                //当前设置的课程助教编号列表
                List<Integer> currentCourseTeachingTeacherIds = new ArrayList<>();
                if (!CollectionUtils.isEmpty(courseTeachingTeacherList)) {
                    currentCourseTeachingTeacherIds = courseTeachingTeacherList.stream().map(CourseScheduleTeacherSalary::getUserId).collect(Collectors.toList());
                }
                //修改后的课程助教编号列表
                List<Integer> newTeachingTeacherIdList = newCourseSchedule.getTeachingTeacherIdList();

                if(Objects.isNull(newTeachingTeacherIdList)){
                    newTeachingTeacherIdList=new ArrayList<>();
                }

                List<Integer> newCreateSalaryTeachingTeacherIds;

                //找出重复的助教编号
                List<Integer> foundInCurrentCourseTeachingTeacherIds = newTeachingTeacherIdList.stream().filter(currentCourseTeachingTeacherIds::contains).collect(Collectors.toList());

                //需要重新生成课酬的助教列表
                newCreateSalaryTeachingTeacherIds = newTeachingTeacherIdList.stream()
                        .filter(userId -> !foundInCurrentCourseTeachingTeacherIds.contains(userId))
                        .collect(Collectors.toList());
                //被替换的助教列表
                List<Integer> beReplaceTeachingTeacherIds = currentCourseTeachingTeacherIds.stream()
                        .filter(userId -> !foundInCurrentCourseTeachingTeacherIds.contains(userId))
                        .collect(Collectors.toList());
                beReplaceTeacherIds.addAll(beReplaceTeachingTeacherIds);

                newCourseSchedule.setTeachingTeacherIdList(newCreateSalaryTeachingTeacherIds);


                if (!newCourseSchedule.isBishopTeacherSalaryNotCreate() || !CollectionUtils.isEmpty(newCreateSalaryTeachingTeacherIds)) {
                    newCourseSchedule.setGroupType(oldCourseSchedule.getGroupType());
                    newCourseSchedule.setMusicGroupId(oldCourseSchedule.getMusicGroupId());
                    //如果主教或者助教发生了变化，则需要重新生成课酬
                    needCreateCourseScheduleTeacherSalaryCourse.add(newCourseSchedule);
                }
            }
            if (Objects.nonNull(newCourseSchedule.getSchoolId())) {
                oldCourseSchedule.setSchoolId(newCourseSchedule.getSchoolId());
            }

            if (Objects.nonNull(newCourseSchedule.getTeachMode())) {
                if (newCourseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)) {
                    oldCourseSchedule.setSchoolId(null);
                }
                if(oldCourseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)
                    &&newCourseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)){
                    throw new BizException("暂不支持线上课程转为线下课");
                }
                oldCourseSchedule.setTeachMode(newCourseSchedule.getTeachMode());
            }

            oldCourseSchedule.setActualTeacherId(newCourseSchedule.getActualTeacherId());
            if(DateUtil.daysBetween(DateUtil.stringToDate(DateUtil.format(oldCourseSchedule.getStartClassTime(),DateUtil.DEFAULT_PATTERN),DateUtil.DEFAULT_PATTERN),
                    DateUtil.stringToDate(DateUtil.format(oldCourseSchedule.getEndClassTime(),DateUtil.DEFAULT_PATTERN),DateUtil.DEFAULT_PATTERN)) > 0){
                throw new BizException("单节课时不允许跨天");
            }
            courseScheduleDao.update(oldCourseSchedule);
            //删除被修改的教师课酬记录和考勤记录
            if (!CollectionUtils.isEmpty(beReplaceTeacherIds)) {
//				courseScheduleTeacherSalaryDao.batchUpdateTeacherExpectSalary(newCourseSchedule.getId().intValue(),beReplaceTeacherIds);
                courseScheduleTeacherSalaryDao.batchDeleteByCourseAndTeacher(newCourseSchedule.getId(), beReplaceTeacherIds);
                teacherAttendanceDao.batchDeleteByCourseAndUsers(newCourseSchedule.getId().intValue(), beReplaceTeacherIds);
            }
            classGroupService.updateClassGroupInfo(oldCourseSchedule.getClassGroupId());
        });
        //生成修改后的教师课酬
        if (!CollectionUtils.isEmpty(needCreateCourseScheduleTeacherSalaryCourse)) {
            classGroupTeacherMapperService.createCourseScheduleTeacherSalary(needCreateCourseScheduleTeacherSalaryCourse, oldCourseSchedules);
        }
        if(!CollectionUtils.isEmpty(needCreateStudentPaymentCourses)){
            courseScheduleStudentPaymentService.createCourseScheduleStudentPaymentByCourseSchedules(needCreateStudentPaymentCourses);
            studentAttendanceDao.deleteByCourseSchedules(needCreateStudentPaymentCourses.stream().map(CourseSchedule::getId).collect(Collectors.toList()));
        }

        if (!sysUser.getUserType().contains("SYSTEM") && sysUser.getUserType().contains("TEACHER")) {
            if (!CollectionUtils.isEmpty(oldCourseScheduleList) && oldCourseScheduleList.get(0).getGroupType().equals(GroupType.VIP)) {
                vipGroupService.checkVipCourseIsInScore(Long.valueOf(oldCourseScheduleList.get(0).getMusicGroupId()));
            }
        }
        //保存调整日志
		saveModifyLog(modifyLogs,newCourseScheduleIds);
//        if(oldCourseScheduleList.get(0).getGroupType().equals(GroupType.VIP)){
//            courseScheduleStudentPaymentService.updateVipGiveCourse(Long.valueOf(oldCourseScheduleList.get(0).getMusicGroupId()));
//        }

        try {
            //推送课时调整
            Set<Integer> teacherIds = newCourseSchedules.stream().map(e -> e.getActualTeacherId()).collect(Collectors.toSet());
            if (teacherIds == null) {
                teacherIds = new HashSet<>();
            }
            teacherIds.addAll(oldCourseScheduleList.stream().map(e -> e.getActualTeacherId()).collect(Collectors.toSet()));
            Map<Integer, String> map = new HashMap<>(teacherIds.size());
            teacherIds.removeAll(Collections.singleton(null));
            teacherIds.forEach(e -> {
                map.put(e, e.toString());
            });
//		HashMap<Integer,String> map = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertMybatisMap(teacherDao.queryPhoneByIds(StringUtils.join(teacherIds, ",")))), HashMap.class);
            if (map != null && map.size() > 0) {
                sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_COURSE_SCHEDULE_CHANGE_RESULT,
                        map, null, 0, "7","TEACHER");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

//		Set<Integer> roleIds = new HashSet<>(1);
//		roleIds.add(SysUserRole.SECTION_MANAGER);
//		classGroupDao.get();
//		sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds),MessageTypeEnum.BACKSTAGE_COURSE_CHANGE,
//				teacher.getRealName());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void courseSwap(Long courseScheduleId1, Long courseScheduleId2) {
        if (courseScheduleId1.equals(courseScheduleId2)) {
            throw new BizException("请选择不同的课程");
        }
        CourseSchedule courseSchedule1 = courseScheduleDao.get(courseScheduleId1);
        CourseSchedule courseSchedule2 = courseScheduleDao.get(courseScheduleId2);

        if (Objects.isNull(courseSchedule1) || Objects.isNull(courseSchedule2)) {
            throw new BizException("未找到对应课程");
        }

        if(!courseSchedule1.getGroupType().equals(courseSchedule2.getGroupType())
            ||!courseSchedule1.getMusicGroupId().equals(courseSchedule2.getMusicGroupId())){
            throw new BizException("不能跨乐团进行课时交换");
        }

        int course1CourseMinutes = DateUtil.minutesBetween(courseSchedule1.getStartClassTime(), courseSchedule1.getEndClassTime());
        int course2CourseMinutes = DateUtil.minutesBetween(courseSchedule2.getStartClassTime(), courseSchedule2.getEndClassTime());

        CourseSchedule temp=new CourseSchedule();
        BeanUtils.copyProperties(courseSchedule1, temp);

        courseSchedule1.setClassDate(courseSchedule2.getClassDate());
        courseSchedule1.setStartClassTime(courseSchedule2.getStartClassTime());
        courseSchedule1.setEndClassTime(DateUtil.addMinutes(courseSchedule1.getStartClassTime(),course1CourseMinutes));

        courseSchedule2.setClassDate(temp.getClassDate());
        courseSchedule2.setStartClassTime(temp.getStartClassTime());
        courseSchedule2.setEndClassTime(DateUtil.addMinutes(courseSchedule2.getStartClassTime(),course2CourseMinutes));

        List<CourseSchedule> courseSchedules = new ArrayList<>();
        courseSchedules.add(courseSchedule1);
        courseSchedules.add(courseSchedule2);
        classStartDateAdjust(courseSchedules);
    }

    @Override
    public void courseSwapWithDay(Date day1, Date day2) {

    }

    @Override
    public List<CourseSchedule> findClassGroupNoStartCourseSchedules(List<Integer> classGroupIds, GroupType groupType) {
        return courseScheduleDao.findClassGroupNoStartCourseSchedules(classGroupIds, groupType);
    }

    /**
     * @Author: Joburgess
     * @Date: 2019/9/24
     * 检测学生是否存在重复
     */
    private void checkStudentIsRepeat(List<Integer> studentIds) {
        Integer[] counts = courseScheduleDao.countStudentInClass(studentIds);
        for (Integer i : counts) {
            if (i > ParamEnum.ONE.getCode()) {
                throw new BizException("所选课程安排日期有学生重复!");
            }
        }
    }

    /**
     * @Author: Joburgess
     * @Date: 2019/9/24
     * 根据课时调整信息增加新课程
     */
    private void createNewCourseByAdjust(List<Date> dates, ClassDateAdjustDto classDateAdjustDto) {
        CourseSchedule schedule = courseScheduleDao.get(classDateAdjustDto.getId());
        List<CourseSchedule> courseSchedules = new ArrayList<>();
        courseScheduleDao.delete(classDateAdjustDto.getId());
        for (Date date : dates) {
            CourseSchedule courseSchedule = new CourseSchedule();
            BeanUtils.copyProperties(schedule, courseSchedule);
            courseSchedule.setClassDate(date);
            courseSchedule.setStartClassTime(classDateAdjustDto.getStartClassTime());
            courseSchedule.setEndClassTime(classDateAdjustDto.getEndClassTime());
            courseSchedule.setTeacherId(classDateAdjustDto.getTeacherId());
            courseSchedules.add(courseSchedule);
        }
        courseScheduleDao.batchAddCourseSchedules(courseSchedules);
    }

    @Override
    public Object findStudentCourseScheduleRecords(StudentCourseScheduleRecordQueryInfo queryInfo) {
        SysUser user = sysUserFeignService.queryUserInfo();
        queryInfo.setUserId(user.getId().longValue());
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

        if (queryInfo.getIsAttend() == YesOrNoEnum.YES) {
            List<StudentCourseScheduleRecordDto> notStartRecords = courseScheduleDao.findStudentCourseScheduleNotStartRecords(user.getId().longValue(),
                    queryInfo.getDate());
            if (notStartRecords != null && notStartRecords.size() > 0) {
//				Set<Integer> classGroupIds = notStartRecords.stream().map(e -> e.getClassGroupId()).collect(Collectors.toSet());
//				Map<Integer,Integer> totalNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countTotalNumByClassGroupId(classGroupIds,queryInfo.getDate()));
//				Map<Integer,Integer> currentNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countCurrentNumByClassGroupId(classGroupIds,queryInfo.getDate()));
                notStartRecords.forEach(e -> {
                    e.setRestOfClass(notStartRecords.size());
                });
            }
            pageInfo.setRows(notStartRecords);
            return pageInfo;
        }

        Map<String, Object> params = new HashMap<String, Object>();
        if (queryInfo.getType() != null && queryInfo.getType().equals("MUSICGROUP")) {
            queryInfo.setType("MUSIC");
        }
        MapUtil.populateMap(params, queryInfo);

        List dataList = null;
        int count = courseScheduleDao.countStudentCourseScheduleRecords(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = courseScheduleDao.findStudentCourseScheduleRecords(params);
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void courseScheduleCommplaint(CourseScheduleComplaints courseScheduleComplaints) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (Objects.isNull(user)) {
            throw new BizException("请登录");
        }

        if (Objects.isNull(courseScheduleComplaints.getCourseScheduleId())) {
            throw new BizException("请指定需要评价的课程");
        }

        if (StringUtils.isBlank(courseScheduleComplaints.getReason())) {
            throw new BizException("请说明写下您的评价");
        }

        if (StringUtils.length(courseScheduleComplaints.getReason()) > 150) {
            throw new BizException("字符长度超限");
        }

        int settlementTimes = courseScheduleTeacherSalaryDao.checkCourseIsSettlement(courseScheduleComplaints.getCourseScheduleId().intValue());
        if (settlementTimes > 0) {
            throw new BizException("该课程已结算");
        }

        courseScheduleComplaints.setUserId(user.getId());

        CourseScheduleComplaints byUserAndCourse = courseScheduleComplaintsDao.findByUserAndCourse(courseScheduleComplaints.getUserId().longValue(), courseScheduleComplaints.getCourseScheduleId());
        if (byUserAndCourse != null) {
            throw new BizException("您已经对该课程做出了评价!");
        }

        CourseScheduleDto courseSchedules = courseScheduleDao.getCourseSchedules(courseScheduleComplaints.getCourseScheduleId());
        Date now = new Date();
        if (courseSchedules.getEndClassTime().after(now)) {
            throw new BizException("该课程还未结束");
        }
        int i = DateUtil.daysBetween(courseSchedules.getEndClassTime(), now);
        if (i > Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.VIP_APPEAL_DAYS_RANGE))) {
            throw new BizException("该课程已超过可申诉时间范围!");
        }
        courseScheduleComplaints.setUserId(user.getId());
        courseScheduleComplaints.setStatus(AuditStatusEnum.ING);
        if (courseScheduleComplaints.getScore() > 2) {
            courseScheduleComplaints.setStatus(AuditStatusEnum.PASS);
        }
        courseScheduleComplaintsDao.insert(courseScheduleComplaints);
        if (courseScheduleComplaints.getScore() > 2) {
            return;
        }
        //学员提起申诉通知
        CourseSchedule courseSchedule = courseScheduleDao.get(courseScheduleComplaints.getCourseScheduleId());
        Set<Integer> roleIds = new HashSet<>(1);
        roleIds.add(SysUserRole.EDUCATIONAL_TEACHER);
        roleIds.add(SysUserRole.OPERATION_EXECUTIVE);
        roleIds.add(SysUserRole.SECTION_MANAGER);
        roleIds.add(SysUserRole.ADMINISTRATOR);
        Map<String, Long> memo = new HashMap<>(1);
        memo.put("courseScheduleComplaintsId", courseScheduleComplaints.getId());
        sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, user.getOrganId()), MessageTypeEnum.BACKSTAGE_STUDENT_APPEAL, JSONObject.toJSONString(memo), courseSchedule.getName(), user.getUsername());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void courseScheduleCommplaintAudit(Long id, Double teacherLiabilityRatio, Double studentLiabilityRatio, AuditStatusEnum status) {

        if (status == AuditStatusEnum.ING) {
            throw new BizException("审批状态不正确");
        }

        CourseScheduleComplaints courseScheduleComplaints = courseScheduleComplaintsDao.get(id);
        if (Objects.isNull(courseScheduleComplaints)) {
            throw new BizException("投诉记录不存在");
        }
        courseScheduleComplaints.setTeacherLiabilityRatio(teacherLiabilityRatio);
        courseScheduleComplaints.setStudentLiabilityRatio(studentLiabilityRatio);
        courseScheduleComplaints.setStatus(status);
        courseScheduleComplaintsDao.update(courseScheduleComplaints);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCourseScheduleToOverStatus() {

        Date date = new Date();
        //课程已结束，更新“未签到”学生的状态未“旷课”
		/*List<StudentAttendance> studentAttendanceList = courseScheduleDao.queryUnsignedStudentList();
		if (studentAttendanceList != null && studentAttendanceList.size() > 0) {
			// 获取老师的考勤记录
			Map<Long, TeacherAttendance> teacherAttendanceMap = teacherAttendanceDao
					.findTeacherIdByCourseSchedule(studentAttendanceList.stream().map(sa -> sa.getCourseScheduleId()).collect(Collectors.toList())).stream()
					.collect(Collectors.toMap(TeacherAttendance::getCourseScheduleId, ta -> ta));
			
			Date updateTime = DateUtil.stringToDate("19700101 000000", DateUtil.DATE_TIME_FORMAT);
			for (Iterator<StudentAttendance> list = studentAttendanceList.iterator(); list.hasNext();) {
				StudentAttendance studentAttendance = list.next();
				TeacherAttendance teacherAttendance = teacherAttendanceMap.get(studentAttendance.getCourseScheduleId());
				if (teacherAttendance != null && teacherAttendance.getSignOutTime() == null) {
					list.remove();
				} else {
					studentAttendance.setStatus(StudentAttendanceStatusEnum.TRUANT);
					studentAttendance.setRemark("课程已结束，自动补旷课");
					if (Objects.isNull(studentAttendance.getCurrentClassTimes())) {
						studentAttendance.setCurrentClassTimes(1);
					} else {
						studentAttendance.setCurrentClassTimes(studentAttendance.getCurrentClassTimes() + 1);
					}
					studentAttendance.setCreateTime(date);
					studentAttendance.setUpdateTime(updateTime);
				}
			}

			if (studentAttendanceList != null && studentAttendanceList.size() > 0) {
				studentAttendanceDao.addStudentAttendances(studentAttendanceList);
			}
		}*/

        //自动更新课程状态至“已结束”
        List<CourseSchedule> list = courseScheduleDao.queryFinishedWithNoUpdateStatus();

        List<CourseSchedule> updateList = new ArrayList<CourseSchedule>();
        List<Integer> classGroupIds = new ArrayList<Integer>();
        List<Long> courseScheduleIdList = new ArrayList<Long>();

        for (CourseSchedule courseSchedule : list) {
            courseSchedule.setStatus(CourseStatusEnum.OVER);
            courseSchedule.setUpdateTime(date);
            updateList.add(courseSchedule);

            if (!classGroupIds.contains(courseSchedule.getClassGroupId())) {
                classGroupIds.add(courseSchedule.getClassGroupId());
            }

            if (courseSchedule.getGroupType() == GroupType.VIP) {
                courseScheduleIdList.add(courseSchedule.getId());
            }
        }

		if (updateList.size() > 0) {
            courseScheduleDao.batchUpdate(updateList);
        }

        // 更新班级已上课次
        if (classGroupIds.size() > 0) {
            classGroupService.batchIncreaseClassTimes(classGroupIds);

            //查询班级信息
//            List<ClassGroup> classGroupList = classGroupService.findClassGroupByIds(classGroupIds.stream().map(e -> e.toString()).collect(Collectors.joining(",")));
//
//            List<String> vipGroupIdList = new ArrayList<String>();
//            for (ClassGroup classGroup : classGroupList) {
//                if (classGroup.getGroupType() == GroupType.VIP && classGroup.getCurrentClassTimes() == classGroup.getTotalClassTimes().intValue()) {
//                    if (!vipGroupIdList.contains(classGroup.getMusicGroupId())) {
//                        vipGroupIdList.add(classGroup.getMusicGroupId());
//                    }
//                }
//            }
//            if (vipGroupIdList.size() > 0) {
//                List<VipGroup> vipGroupList = vipGroupDao.queryByIds(vipGroupIdList.stream().collect(Collectors.joining(",")));
//                for (VipGroup vipGroup : vipGroupList) {
//                    if (!vipGroup.getStatus().equals(VipGroupStatusEnum.PAUSE)
//                            && !vipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL)) {
//                        vipGroup.setStatus(VipGroupStatusEnum.FINISHED);
//                    }
//                    vipGroup.setUpdateTime(date);
//                }
//                vipGroupDao.batchUpdate(vipGroupList);
//            }
        }

        /*if (courseScheduleIdList.size() > 0) {
            // vip课自动签退
            teacherAttendanceDao.updateViPSignOutStatus(courseScheduleIdList.stream().map(a -> a.toString()).collect(Collectors.joining(",")));
        }*/

		try {
			practiceGroupService.practiceGroupRenewRemind();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return true;
    }

    @Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateCourseScheduleToUnderway() {
    	Date date = new Date();
    	List<CourseSchedule> list = courseScheduleDao.queryUnderwayWithNoUpdateStatus();

        List<CourseSchedule> updateList = new ArrayList<CourseSchedule>();

        for (CourseSchedule courseSchedule : list) {
            courseSchedule.setStatus(CourseStatusEnum.UNDERWAY);
            courseSchedule.setUpdateTime(date);
            updateList.add(courseSchedule);
        }

        if (updateList.size() > 0) {
            courseScheduleDao.batchUpdate(updateList);
		}
		return true;
	}

	@Override
    public PageInfo queryTeacherClassCourseSchedule(CourseScheduleQueryInfo queryInfo) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("请登录");
        }
        if(!queryInfo.getFindTotal()){
            queryInfo.setUserId(user.getId().longValue());
        }
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

        if (Objects.isNull(queryInfo.getDate())) {
            queryInfo.setDate(new Date());
        }

        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);

        List<TeacherClassCourseSchudeleDto> dataList = null;
        int count = 0;
        if (Objects.isNull(queryInfo.getOnlyHistory()) || queryInfo.getOnlyHistory() == 0) {
            count = courseScheduleDao.countTeacherClassCourseSchedule(params);
        } else {
            count = courseScheduleDao.countTeacherHistoryClassCourseSchedule(params);
        }
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            if (Objects.isNull(queryInfo.getOnlyHistory()) || queryInfo.getOnlyHistory() == 0) {
                dataList = courseScheduleDao.queryTeacherClassCourseSchedule(params);
            } else {
                dataList = courseScheduleDao.queryTeacherHistoryClassCourseSchedule(params);
            }
            dataList.forEach(e -> {
                e.setCurrentClassTimes(courseScheduleDao.countCurrentTimes(e.getClassGroupId().intValue(),new Date()));
                e.setTotalClassTimes(courseScheduleDao.countCurrentCourseTime(e.getCourseScheduleId()));
            });
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

	@Override
	public PageInfo queryTeacherVipClassCourseSchedule(CourseScheduleQueryInfo queryInfo) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if (null == user) {
			throw new BizException("请登录");
		}
		if(!queryInfo.getFindTotal()){
			queryInfo.setUserId(user.getId().longValue());
		}
		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

		if (Objects.isNull(queryInfo.getDate())) {
			queryInfo.setDate(new Date());
		}

		Map<String, Object> params = new HashMap<>();
		MapUtil.populateMap(params, queryInfo);

		List<TeacherClassCourseSchudeleDto> dataList = null;
		int count = 0;
		if (Objects.isNull(queryInfo.getOnlyHistory()) || queryInfo.getOnlyHistory() == 0) {
			count = courseScheduleDao.countTeacherClassCourseSchedule(params);
		} else {
			count = courseScheduleDao.countTeacherHistoryClassCourseSchedule(params);
		}
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			if (Objects.isNull(queryInfo.getOnlyHistory()) || queryInfo.getOnlyHistory() == 0) {
				dataList = courseScheduleDao.queryTeacherClassCourseSchedule(params);
			} else {
				dataList = courseScheduleDao.queryTeacherHistoryClassCourseSchedule(params);
			}

			List<Integer> classGroupIds = dataList.stream().map(e->e.getClassGroupId().intValue()).collect(Collectors.toList());
			List<Map<Integer, Integer>> classGroupStudentNumMaps = classGroupStudentMapperDao.countClassGroupsStudentNum(classGroupIds, ClassGroupStudentStatusEnum.NORMAL);
			Map<Integer, Long> classGroupStudentNumMap = MapUtil.convertIntegerMap(classGroupStudentNumMaps);

			List<Long> allCourseScheduleIds = dataList.stream().map(TeacherClassCourseSchudeleDto::getCourseScheduleId).collect(Collectors.toList());
			SysConfig advanceLeaveHoursConfig = sysConfigService.findByParamName(SysConfigService.ADVANCE_LEAVE_HOURS);
			Integer advanceLeaveHours=advanceLeaveHoursConfig.getParanValue(Integer.class);
			List<Map<Long, Integer>> courseLeaveStudentNumMaps = studentAttendanceDao.countCourseLeaveStudentNumWithFourHoursAgo(allCourseScheduleIds, advanceLeaveHours);
			Map<Long,Long> courseLeaveStudentNumMap = MapUtil.convertIntegerMap((courseLeaveStudentNumMaps));

			dataList.forEach(e -> {
				e.setCurrentClassTimes(courseScheduleDao.countCurrentTimes(e.getClassGroupId().intValue(),new Date()));
				e.setTotalClassTimes(courseScheduleDao.countCurrentCourseTime(e.getCourseScheduleId()));

				Long leaveStudentNum = courseLeaveStudentNumMap.get(e.getCourseScheduleId());
				Long normalStudentNum = classGroupStudentNumMap.get(e.getClassGroupId());
				if(Objects.nonNull(leaveStudentNum)&&Objects.nonNull(normalStudentNum)&&leaveStudentNum.intValue()==normalStudentNum.intValue()){
					e.setEnableAdjustInToday(1);
				}
			});
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
    public CourseAttendanceDetailHeadInfoDto findCourseAttendanceDetailHeadInfo(Long courseScheduleId) {
        if (Objects.isNull(courseScheduleId)) {
            throw new BizException("请指定课程");
        }
        CourseAttendanceDetailHeadInfoDto courseAttendanceDetailHeadInfoDto = courseScheduleDao.findByCourse(courseScheduleId);
        courseAttendanceDetailHeadInfoDto.setLatestAttendanceTime(studentAttendanceDao.findLatestAttendanceDate(courseScheduleId));
        return courseAttendanceDetailHeadInfoDto;
    }

    @Override
    public void checkMusicGroupClassCourse(String musicGroupId) {
        if (Objects.isNull(musicGroupId)) {
            throw new BizException("请指定乐团");
        }
        List<Map<Integer, Long>> maps = courseScheduleDao.countClassCourseNumByMusicGroup(musicGroupId);
        Map<Integer, Long> classCourseNumMap = MapUtil.convertIntegerMap(maps);
        List<Integer> collect = classCourseNumMap
                .entrySet()
                .stream()
                .filter(integerLongEntry -> integerLongEntry.getValue() <= 0)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(collect)) {
            List<String> classGroupNamesByClassGroups = classGroupDao.findClassGroupNamesByClassGroups(collect);
            String classNamesStr = StringUtils.join(classGroupNamesByClassGroups, ",");
            throw new BizException(classNamesStr + "班级未排课");
        }
    }

    @Override
    public Map<Integer, Integer> findCourseScheduleCurrentTimes(List<Integer> courseSchedules) {
        List<Map<Integer, Integer>> courseScheduleCurrentTimes = courseScheduleDao.findCourseScheduleCurrentTimes(courseSchedules);
        return MapUtil.convertIntegerMap(courseScheduleCurrentTimes);
    }

    @Override
    public List<CourseSchedule> findNoStartCoursesByClassGroupId(Integer classGroupId) {
        return courseScheduleDao.findCoursesByClassGroupId(classGroupId, CourseStatusEnum.NOT_START);
    }


    @Override
    public void studentCoursesScheduleRemind() {
        List<Mapper> mapperList = courseScheduleDao.queryStudentCoursesTimesOfTomorrow();
        for (Mapper mapper : mapperList) {
            Integer userId = Integer.parseInt(mapper.getKey().toString());
            Integer size = Integer.parseInt(mapper.getValue().toString());

            Map<Integer, String> receivers = new HashMap<Integer, String>();
            receivers.put(userId, userId + "");

            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.STUDENT_PUSH_HAVE_COURSE_MESSAGE, receivers, null, 0, "2","STUDENT", size);
        }
    }

    @Override
    public void studentSignInRemind() {
        List<Mapper> mapperList = courseScheduleDao.queryStudentNotStartCourseScheduleIn90Mins();
        if (mapperList != null && mapperList.size() > 0) {
            for (Mapper mapper : mapperList) {
                Map<Integer, String> receivers = new HashMap<Integer, String>();
                receivers.put((Integer) mapper.getKey(), mapper.getKey() + "");

                sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.STUDENT_PUSH_ATTEND_COURSE_MESSAGE, receivers, null, 0, "2","STUDENT", mapper.getValue());
            }
        }
    }

    @Override
    public void teacherCoursesScheduleRemind() {
        List<Mapper> mapperList = courseScheduleDao.queryTeacherCoursesTimesOfTomorrow();
        for (Mapper mapper : mapperList) {
            Integer userId = (Integer) mapper.getKey();
            String teacherName = (String) mapper.getValue();

            Map<Integer, String> receivers = new HashMap<Integer, String>();
            receivers.put(userId, userId + "");

            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_HAVE_COURSE_MESSAGE,
                    receivers, null, 0, "2","TEACHER", teacherName);
        }
    }

    @Override
    public void teacherSignInRemind() {
        List<Mapper> mapperList = courseScheduleDao.queryTeacherNotStartCourseScheduleIn30Mins();
        for (Mapper mapper : mapperList) {
            Integer userId = (Integer) mapper.getKey();
            String scheduleName = (String) mapper.getValue();

            Map<Integer, String> receivers = new HashMap<Integer, String>();
            receivers.put(userId, userId + "");

            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_ATTEND_CLASS_MESSAGE,
                    receivers, null, 0, "2","TEACHER", scheduleName);
        }
    }

    @Override
    public List<CourseSchedule> findCourseScheduleByClassGroup(Integer classGroupId) {
        if (Objects.isNull(classGroupId)) {
            throw new BizException("请指定班级");
        }
        ClassGroup classGroup = classGroupDao.get(classGroupId);
        if (Objects.isNull(classGroup)) {
            throw new BizException("指定的班级不存在");
        }
        List<Integer> classGroupIds = new ArrayList<>();
        classGroupIds.add(classGroupId);
        if (classGroup.getType().equals(ClassGroupTypeEnum.MIX)) {
            List<ClassGroup> mixClassChildClassGroup = classGroupDao.findMixClassChildClassGroup(classGroupId);
            List<Integer> childClassGroupIds = mixClassChildClassGroup.stream()
                    .map(ClassGroup::getId)
                    .collect(Collectors.toList());
            classGroupIds.addAll(childClassGroupIds);
        }
        return courseScheduleDao.findByClassGroups(classGroupIds);
    }

    @Override
    public Object findVipGroupCourseSchedules(VipGroupQueryInfo queryInfo) {
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

        if (Objects.isNull(queryInfo.getVipGroupId())) {
            throw new BizException("请指定vip课程");
        }

        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);

        VipGroup vipGroup = vipGroupDao.get(queryInfo.getVipGroupId());
        if (Objects.isNull(vipGroup)) {
            throw new BizException("指定的vip课不存在");
        }

        List<CourseSchedule> dataList;
        if (vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)) {
            dataList = JSON.parseArray(vipGroup.getCourseSchedulesJson(), CourseSchedule.class);
        } else {
            dataList = courseScheduleDao.findGroupCourseSchedules(vipGroup.getId(),GroupType.VIP.getCode());
        }

        int count = dataList.size();
        if (count > 0) {
            pageInfo.setTotal(count);
            if (vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)) {
                dataList = dataList.stream().skip(pageInfo.getOffset()).limit(pageInfo.getLimit()).collect(Collectors.toList());
                dataList.forEach(courseSchedule -> {
                    courseSchedule.setIsSettlement(0);
                });
            } else {
                List<Long> courseScheduleIds = dataList.stream()
                        .map(courseSchedule -> courseSchedule.getId())
                        .distinct().collect(Collectors.toList());
                List<Map<Long, Integer>> courseSettlementMaps = courseScheduleTeacherSalaryDao.checkCoursesIsSettlement(courseScheduleIds);
                Map<Long, Long> courseSettlementMap = MapUtil.convertIntegerMap(courseSettlementMaps);
                Map<Integer, Long> studentNumCourseMap = MapUtil.convertIntegerMap(studentAttendanceDao.countStudentAttendancesByCourses(courseScheduleIds));
                dataList.forEach(courseSchedule -> {
                    Long isSettlement = courseSettlementMap.get(courseSchedule.getId().longValue());
                    if (Objects.isNull(isSettlement) || isSettlement <= 0) {
                        courseSchedule.setIsSettlement(0);
                    } else {
                        courseSchedule.setIsSettlement(1);
                    }
                    Long studentNum = studentNumCourseMap.get(courseSchedule.getId());
                    if (Objects.nonNull(studentNum)) {
                        courseSchedule.setIsCallNames(studentNum > 0 ? YesOrNoEnum.YES : YesOrNoEnum.NO);
                    } else {
                        courseSchedule.setIsCallNames(YesOrNoEnum.NO);
                    }
                });
            }
        }
        pageInfo.setRows(dataList);
        Map<String, Object> result = new HashMap<>();
        result.put("pageInfo", pageInfo);
        result.put("singleClassMinutes", vipGroup.getSingleClassMinutes());
        return result;
    }

    @Override
    public List<CourseSchedule> createCourses(CourseGenerateDto courseGenerateInfo, boolean excludePastCourse) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(courseGenerateInfo.getCourseCreateStartTime());

        if(Objects.isNull(courseGenerateInfo.getCourseCount())||courseGenerateInfo.getCourseCount()<=0){
        	throw new BizException("可排课次数不足");
		}

        Set<String> holidayDays = new HashSet<>();

		if (courseGenerateInfo.isSkipHoliday()) {
			SysConfig holidaySetting = sysConfigService.findByParamName(SysConfigService.HOLIDAY_SETTING);
			if(Objects.nonNull(holidaySetting)&&StringUtils.isNotBlank(holidaySetting.getParanValue())){
				holidayDays = new HashSet<>(JSON.parseArray(holidaySetting.getParanValue(), String.class));
			}
		}

        List<CourseSchedule> courseSchedules = new ArrayList<>();
        Date now=new Date();

        while (true) {
			if (courseGenerateInfo.isSkipHoliday() && holidayDays.contains(DateUtil.format(calendar.getTime(), "yyyy-MM-dd"))) {
				calendar.add(Calendar.DATE, 1);
				continue;
			}
            int i = calendar.get(Calendar.DAY_OF_WEEK);
            if (i == 1) {
                i = 7;
            } else {
                i = --i;
            }
            for (CourseTimeDto courseTime : courseGenerateInfo.getCourseTimes()) {
                if (Objects.isNull(courseTime.getDayOfWeek())) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() < 1 || courseTime.getDayOfWeek() > 7) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() == i) {
                    String dateYmdStr = DateUtil.dateToString(calendar.getTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT);
                    if(StringUtils.isBlank(courseTime.getStartClassTime())){
                    	throw new BizException("排课循环周期错误");
					}
                    dateYmdStr = dateYmdStr + " " + courseTime.getStartClassTime();
                    Date courseStartTime = DateUtil.stringToDate(dateYmdStr, "yyyy-MM-dd HH:mm");
                    if(excludePastCourse&&courseStartTime.before(now)){
                    	continue;
					}
                    Date courseEndTime = DateUtil.addMinutes(courseStartTime, courseGenerateInfo.getSingleClassMinutes());
                    if(!DateUtil.isSameDay(courseStartTime, courseEndTime)){
                    	throw new BizException("暂不支持单节课跨天");
					}
                    CourseSchedule courseSchedule = new CourseSchedule();
                    courseSchedule.setClassDate(courseStartTime);
                    courseSchedule.setStartClassTime(courseStartTime);
                    courseSchedule.setEndClassTime(courseEndTime);
                    courseSchedules.add(courseSchedule);
                }
                if (courseSchedules.size() == courseGenerateInfo.getCourseCount()) {
                    break;
                }
            }
            if (courseSchedules.size() == courseGenerateInfo.getCourseCount()) {
                break;
            }
            calendar.add(Calendar.DATE, 1);
        }
        return courseSchedules;
    }

    @Override
    public PageInfo<CourseScheduleEndDto> endFindCourseSchedules(EndCourseScheduleQueryInfo queryInfo) {
        PageInfo<CourseScheduleEndDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>(16);
        MapUtil.populateMap(params, queryInfo);

        List<CourseScheduleEndDto> results = new ArrayList<>();
        int count = courseScheduleDao.endCountCourseSchedules(params);
        if(queryInfo.getIsExport() && count > 50000){
            throw new BizException("数据集太大，不能导出.最大数据集不能超过50000");
        }
        if (count > 0) {
            pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
            results = courseScheduleDao.endFindCourseSchedules(params);
            List<Long> courseScheduleIds = results.stream().map(CourseScheduleEndDto::getId).collect(Collectors.toList());
            //Map<Long, String> studentIdMap = MapUtil.convertIntegerMap(courseScheduleStudentPaymentDao.getStudentIdMap(courseScheduleIds));
            List<Integer> teacherIds=results.stream().filter(t->Objects.nonNull(t.getActualTeacherId())).map(CourseSchedule::getActualTeacherId).collect(Collectors.toList());

            List<Map<Integer, String>> nameIdMaps = teacherDao.queryNameByIdList(teacherIds);
            Map<Integer, String> nameIdMap=MapUtil.convertIntegerMap(nameIdMaps);

			//List<Map<Long, String>> coursesSettlementTimeMaps = courseScheduleTeacherSalaryDao.getCoursesSettlementTime(courseScheduleIds);
			//Map<Long, String> coursesSettlementTimeMap = MapUtil.convertIntegerMap(coursesSettlementTimeMaps);

			/*List<Long> practiceIds = results.stream().filter(e -> PRACTICE.equals(e.getGroupType())).map(e -> Long.valueOf(e.getMusicGroupId())).collect(Collectors.toList());
			Map<Long, PracticeGroup> idPracticeMap = new HashMap<>();
			if(!CollectionUtils.isEmpty(practiceIds)){
				List<PracticeGroup> practiceGroups = practiceGroupDao.getWithIds(practiceIds);
                idPracticeMap = practiceGroups.stream().collect(Collectors.toMap(PracticeGroup::getId, e->e));
			}*/

			List<Map<Long, Long>> courseMergeCourseNum = courseScheduleDao.countCourseMergeCourseNum(courseScheduleIds);
			Map<Long, Long> courseMergeCourseNumMap = new HashMap<>();
			if(!CollectionUtils.isEmpty(courseMergeCourseNum)){
				courseMergeCourseNumMap = MapUtil.convertIntegerMap(courseMergeCourseNum);
			}


			//获取班级声部名称
            List<Map<Integer, String>> classGroupSubjectNameMaps = classGroupDao.findClassGroupSubjectNameMaps(courseScheduleIds);
            Map<Integer, String> classGroupSubjectNameMap = MapUtil.convertIntegerMap(classGroupSubjectNameMaps);
			for (CourseScheduleEndDto result : results) {
				result.setTeacher(null);
				result.setTeacherName(nameIdMap.get(result.getActualTeacherId()));
				result.setSubjectName(classGroupSubjectNameMap.get(result.getId()));
				//result.setStudentId(studentIdMap.get(result.getId()));
				//result.setPracticeGroup(idPracticeMap.get(Long.valueOf(result.getMusicGroupId())));
				//result.setSettlementTime(coursesSettlementTimeMap.get(result.getId()));
				result.setIsSettlement(Objects.isNull(result.getSettlementTime())?0:1);
				if(courseMergeCourseNumMap.containsKey(result.getId())){
					result.setBeMerged(courseMergeCourseNumMap.get(result.getId())>0?true:false);
				}
			}
        }
        pageInfo.setRows(results);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void practiceCourseAdjust(CourseSchedule courseSchedule) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        Long courseScheduleId = courseSchedule.getId();
        if(Objects.isNull(courseScheduleId)){
            throw new BizException("请指定课程");
        }
        if(Objects.isNull(courseSchedule.getStartClassTime())){
            throw new BizException("请指定上课时间");
        }
        CourseSchedule oldCourseSchedule = courseScheduleDao.get(courseScheduleId);
        if(Objects.isNull(oldCourseSchedule)){
            throw new BizException("课程不存在");
        }
        if(!oldCourseSchedule.getGroupType().equals(PRACTICE)){
            throw new BizException("请选择网管课");
        }
        //已点名的不允许调整
        List<StudentAttendance> studentAttendances = studentAttendanceDao.findByCourseId(courseScheduleId);
        if(studentAttendances != null && studentAttendances.size() > 0){
            throw new BizException("调整失败: 课程已点名");
        }
        //已结算的课酬不能调整
        CourseScheduleTeacherSalary teacherSalary = courseScheduleTeacherSalaryDao.queryByCourseScheduleIdAndUserId(oldCourseSchedule.getId(), oldCourseSchedule.getActualTeacherId());
        if(teacherSalary != null && teacherSalary.getSettlementTime() != null){
            throw new BizException("调整失败: 课程已结算");
        }
		Date date = new Date();
        //获取调整日志
		List<Long> courseIds = new ArrayList<>();
		courseIds.add(courseScheduleId);
		List<CourseSchedule> courseSchedules1 = new ArrayList<>();
		courseSchedules1.add(oldCourseSchedule);
		List<CourseScheduleModifyLog> modifyLogs = getModifyLogs(courseIds, courseSchedules1, user.getId(), date);

		PracticeGroup practiceGroup = practiceGroupDao.get(Long.parseLong(oldCourseSchedule.getMusicGroupId()));
        String classDate = DateUtil.format(courseSchedule.getClassDate(), DateUtil.DEFAULT_PATTERN);
        String startClassTime = DateUtil.format(courseSchedule.getStartClassTime(), DateUtil.EXPANDED_TIME_FORMAT);
        Date startDateTime = DateUtil.stringToDate(classDate + " " + startClassTime, DateUtil.EXPANDED_DATE_TIME_FORMAT);
        Date endDateTime = DateUtil.addMinutes(startDateTime,practiceGroup.getSingleClassMinutes());
		if(practiceGroup.getType() != TRIAL){
			if(DateUtil.minutesBetween(startDateTime,practiceGroup.getCoursesStartDate()) > 0){
				throw new BizException("调整失败: 调整时间不得早于开课时间");
			}
			if(DateUtil.minutesBetween(practiceGroup.getCoursesExpireDate(),endDateTime) > 0){
				throw new BizException("调整失败: 截止时间超过课程有效期");
			}
		}
        if(DateUtil.daysBetween(DateUtil.stringToDate(DateUtil.format(startDateTime,DateUtil.DEFAULT_PATTERN),DateUtil.DEFAULT_PATTERN),
                DateUtil.stringToDate(DateUtil.format(endDateTime,DateUtil.DEFAULT_PATTERN),DateUtil.DEFAULT_PATTERN)) > 0){
            throw new BizException("单节课时不允许跨天");
        }

        oldCourseSchedule.setUpdateTime(date);

        if(DateUtil.minutesBetween(endDateTime,date) > 0){
        	if(oldCourseSchedule.getStatus() == CourseStatusEnum.OVER){
        		throw new BizException("调整失败：已结束的课程无法调整至已结束");
			}
            oldCourseSchedule.setStatus(CourseStatusEnum.OVER);
        }else if(DateUtil.minutesBetween(date,startDateTime) > 0){
            oldCourseSchedule.setStatus(CourseStatusEnum.NOT_START);
        }else {
            oldCourseSchedule.setStatus(CourseStatusEnum.UNDERWAY);
        }
        Integer practiceCourseMinutes=25;
        SysConfig practiceCourseMinutesConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_MINUTES);
        if(Objects.nonNull(practiceCourseMinutesConfig)){
            practiceCourseMinutes=practiceCourseMinutesConfig.getParanValue(Integer.class);
        }
        oldCourseSchedule.setClassDate(courseSchedule.getStartClassTime());
        oldCourseSchedule.setStartClassTime(courseSchedule.getStartClassTime());
        oldCourseSchedule.setEndClassTime(DateUtil.addMinutes(courseSchedule.getStartClassTime(),practiceCourseMinutes));

        List<CourseSchedule> courseSchedules=new ArrayList<>();
        courseSchedules.add(oldCourseSchedule);
        checkNewCourseSchedules(courseSchedules,false,false);
        if(oldCourseSchedule.getStatus() == CourseStatusEnum.NOT_START){
            teacherAttendanceDao.batchUpdateTeacher(courseSchedules.stream().map(e->e.getId()).collect(Collectors.toSet()),oldCourseSchedule.getActualTeacherId());
            //清空学生签到记录
            studentAttendanceDao.deleteStudentAttendancesByCourse(courseScheduleId);
        }
		// 删除作业
		courseHomeworkService.delHomwworkByCourseScheduleId(courseScheduleId);
        //删除评论
		courseScheduleReviewDao.delByCourseScheduleId(courseScheduleId);
		//删除申述
		courseScheduleComplaintsDao.delByCourseScheduleId(courseScheduleId);
		//清除考勤申述
		teacherAttendanceDao.clearAttendanceComplaint(courseScheduleId);
        courseScheduleDao.update(oldCourseSchedule);
		if(practiceGroup.getType() == TRIAL){
			practiceGroup.setCoursesStartDate(courseScheduleDao.getFirstTime(practiceGroup.getId(),PRACTICE.getCode()));
			practiceGroup.setCoursesExpireDate(courseScheduleDao.getLastTime(practiceGroup.getId(),PRACTICE.getCode()));
			practiceGroup.setUpdateTime(date);
			practiceGroupDao.update(practiceGroup);
		}
		//保存修改记录
		saveModifyLog(modifyLogs,courseIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void practiceCourseTeacherAdjust(Long courseScheduleId,Integer teacherId) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        if(Objects.isNull(courseScheduleId)){
            throw new BizException("请指定课程");
        }
        if(Objects.isNull(teacherId)){
            throw new BizException("请指定上课老师");
        }
        CourseSchedule oldCourseSchedule = courseScheduleDao.getSurplusCourseWithGroup(courseScheduleId);
        if(Objects.isNull(oldCourseSchedule)){
            throw new BizException("调整失败: 课程已结束");
        }
        if(!oldCourseSchedule.getGroupType().equals(PRACTICE)){
            throw new BizException("请选择网管课");
        }
        if(teacherId.equals(oldCourseSchedule.getActualTeacherId())){
            throw new BizException("请选择不同的老师");
        }
        Date date = new Date();
		//获取调整日志
		List<Long> courseIds = new ArrayList<>();
		courseIds.add(courseScheduleId);
		List<CourseSchedule> courseSchedules1 = new ArrayList<>();
		courseSchedules1.add(oldCourseSchedule);
		List<CourseScheduleModifyLog> modifyLogs = getModifyLogs(courseIds, courseSchedules1, user.getId(), date);

        oldCourseSchedule.setUpdateTime(date);
        oldCourseSchedule.setActualTeacherId(teacherId);

        List<CourseSchedule> courseSchedules = new ArrayList<>();
        courseSchedules.add(oldCourseSchedule);
        Set<Long> courseScheduleIds = courseSchedules.stream().map(e -> e.getId()).collect(Collectors.toSet());
        checkNewCourseSchedules(courseSchedules,false,false);

        courseScheduleDao.update(oldCourseSchedule);

        PracticeGroup practiceGroup = practiceGroupDao.get(Long.valueOf(oldCourseSchedule.getMusicGroupId()));
		if(practiceGroup.getType() != TRIAL){
			if(practiceGroup.getType() != FREE){
				List<TeacherDefaultPracticeGroupSalary> teacherDefaultPracticeGroupSalaries = teacherDefaultPracticeGroupSalaryDao.queryByUserId(teacherId);
				if(teacherDefaultPracticeGroupSalaries == null || teacherDefaultPracticeGroupSalaries.size() == 0){
					throw new BizException("请设置老师默认课酬");
				}
				courseScheduleTeacherSalaryDao.batchUpdateTeacher(courseScheduleIds,teacherId);
			}else{
				List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = courseScheduleTeacherSalaryDao.findByCourseSchedule(courseScheduleId);
				if(!CollectionUtils.isEmpty(courseScheduleTeacherSalaries)){
					SysConfig practiceCourseSalaryConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_SALARY);
					BigDecimal teacherSalary = new BigDecimal(practiceCourseSalaryConfig.getParanValue());
					for (CourseScheduleTeacherSalary courseScheduleTeacherSalary : courseScheduleTeacherSalaries) {
						courseScheduleTeacherSalary.setUserId(teacherId);
						courseScheduleTeacherSalary.setExpectSalary(teacherSalary);
					}
					courseScheduleTeacherSalaryDao.batchUpdate(courseScheduleTeacherSalaries);
				}
			}
		}
        teacherAttendanceDao.batchUpdateTeacher(courseScheduleIds,teacherId);
		//删除申述
		courseScheduleComplaintsDao.delByCourseScheduleId(courseScheduleId);
		//删除申述
		courseScheduleComplaintsDao.delByCourseScheduleIds(courseScheduleIds);
		//清除考勤申述
		teacherAttendanceDao.clearAttendanceComplaints(courseScheduleIds);
		//添加通讯录
		imUserFriendService.refreshCourseImUserFriend(courseScheduleId);
		//保存修改记录
		saveModifyLog(modifyLogs,courseIds);

        Map<Integer, String> map = new HashMap<>(2);
        map.put(teacherId,teacherId.toString());
        map.put(oldCourseSchedule.getActualTeacherId(),oldCourseSchedule.getActualTeacherId().toString());
        if (map != null && map.size() > 0) {
            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_COURSE_SCHEDULE_CHANGE_RESULT,
                    map, null, 0, "7","TEACHER");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void practiceGroupTeacherAdjust(String practiceGroupId, Integer teacherId, Integer subjectId, Integer educationalTeacherId) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        if(StringUtils.isEmpty(practiceGroupId)){
            throw new BizException("请指定课程组");
        }
        if(Objects.isNull(teacherId)){
            throw new BizException("请指定上课老师");
        }
        List<CourseSchedule> courseSchedules = courseScheduleDao.findSurplusCourseWithGroup(PRACTICE,practiceGroupId);
        if(courseSchedules != null && courseSchedules.size() > 0){
            courseSchedules = courseSchedules.stream().filter(courseSchedule -> !courseSchedule.getActualTeacherId().equals(teacherId)).collect(Collectors.toList());
        }
		Date date = new Date();
		List<Long> courseIds1 = courseSchedules.stream().map(e -> e.getId()).collect(Collectors.toList());
		//获取修改日志
		List<CourseScheduleModifyLog> modifyLogs = new ArrayList<>();
		if(!CollectionUtils.isEmpty(courseIds1)){
			modifyLogs = getModifyLogs(courseIds1, courseSchedules, user.getId(), date);
		}
		PracticeGroup practiceGroup = practiceGroupDao.get(Long.valueOf(practiceGroupId));

		ClassGroup classGroup = classGroupDao.findByMusicGroupAndType(practiceGroupId, PRACTICE.getCode());
		//教务老师变更
        if(Objects.nonNull(educationalTeacherId)&&!educationalTeacherId.equals(practiceGroup.getEducationalTeacherId())){
			practiceGroup.setEducationalTeacherId(educationalTeacherId);
		}
		if(Objects.nonNull(subjectId)&&!subjectId.equals(practiceGroup.getSubjectId())){
			Subject subject = subjectDao.get(subjectId);
			String groupName = practiceGroup.getName();
			groupName=groupName.substring(groupName.indexOf("•"));
			groupName=subject.getName()+groupName;
			practiceGroup.setName(groupName);
			practiceGroup.setSubjectId(subjectId);
			classGroup.setSubjectIdList(subjectId.toString());
			classGroup.setName(groupName);
			classGroup.setSubjectIdList(subjectId.toString());
			classGroupDao.update(classGroup);
			courseScheduleDao.updateCourseNameByGroup(practiceGroupId, PRACTICE,groupName);
		}
		if(!teacherId.equals(practiceGroup.getUserId())){
			practiceGroup.setUserId(teacherId);
			classGroupTeacherMapperService.updateTeacher(practiceGroupId,teacherId, PRACTICE.getCode());
			classGroupTeacherSalaryDao.updateTeacher(practiceGroupId,teacherId, PRACTICE.getCode());
			if(courseSchedules == null || courseSchedules.size() == 0){
				return;
			}
			Map<Integer, String> teacherIdMap = new HashMap<>(10);
			teacherIdMap.put(teacherId,teacherId.toString());

			courseSchedules.forEach(e->{
				teacherIdMap.put(e.getActualTeacherId(),e.getActualTeacherId().toString());
				e.setUpdateTime(date);
				e.setActualTeacherId(teacherId);
			});
			checkNewCourseSchedules(courseSchedules,false,false);
			courseScheduleDao.batchUpdate(courseSchedules);
			Set<Long> courseScheduleIds = courseSchedules.stream().map(e -> e.getId()).collect(Collectors.toSet());
			if(practiceGroup.getType() != TRIAL){
				if(CHARGE == practiceGroup.getType()){
					List<TeacherDefaultPracticeGroupSalary> teacherDefaultPracticeGroupSalaries = teacherDefaultPracticeGroupSalaryDao.queryByUserId(teacherId);
					if(teacherDefaultPracticeGroupSalaries == null || teacherDefaultPracticeGroupSalaries.size() == 0){
						throw new BizException("请设置老师默认课酬");
					}
					courseScheduleTeacherSalaryDao.batchUpdateTeacher(courseScheduleIds,teacherId);
				}else{
					List<CourseSchedule> groupNotStartCourses = courseScheduleDao.findGroupNotStartCourses(practiceGroupId, PRACTICE);
					if(!CollectionUtils.isEmpty(groupNotStartCourses)){
						SysConfig practiceCourseSalaryConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_SALARY);
						BigDecimal teacherSalary = new BigDecimal(practiceCourseSalaryConfig.getParanValue());
						List<Long> courseIds = groupNotStartCourses.stream().map(CourseSchedule::getId).collect(Collectors.toList());
						List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = courseScheduleTeacherSalaryDao.findByCourseSchedules(courseIds);
						for (CourseScheduleTeacherSalary courseScheduleTeacherSalary : courseScheduleTeacherSalaries) {
							courseScheduleTeacherSalary.setUserId(teacherId);
							courseScheduleTeacherSalary.setExpectSalary(teacherSalary);
						}
						courseScheduleTeacherSalaryDao.batchUpdate(courseScheduleTeacherSalaries);
					}
				}
			}
			teacherAttendanceDao.batchUpdateTeacher(courseScheduleIds,teacherId);
			//删除申述
			courseScheduleComplaintsDao.delByCourseScheduleIds(courseScheduleIds);
			//清除考勤申述
			teacherAttendanceDao.clearAttendanceComplaints(courseScheduleIds);
			//保存修改记录
			if(!CollectionUtils.isEmpty(modifyLogs))
				saveModifyLog(modifyLogs,courseIds1);

			if (teacherIdMap != null && teacherIdMap.size() > 0) {
				sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_COURSE_SCHEDULE_CHANGE_RESULT,
						teacherIdMap, null, 0, "7","TEACHER");
			}
		}
		practiceGroupDao.update(practiceGroup);
		imUserFriendService.refreshGroupImUserFriend(practiceGroup.getId().toString(), PRACTICE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cleanAttendance(String courseScheduleIds) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        if(StringUtils.isEmpty(courseScheduleIds)){
            throw new BizException("参数校验失败");
        }
        LOGGER.info("清空老师和学生考勤,user:{},参数:{}",user.getId(),courseScheduleIds);
        List<Long> courseScheduleId = courseScheduleTeacherSalaryService.querySettlementScheduleId(courseScheduleIds);
        if(courseScheduleId == null || courseScheduleId.size() == 0){
            throw new BizException("课程已结算，无法清除考勤");
        }
        if(courseScheduleId.size()==1){
			VipGroup vipGroup = vipGroupDao.findByCourseSchedule(courseScheduleId.get(0));
			if(Objects.nonNull(vipGroup)
					&&!VipGroupStatusEnum.PROGRESS.equals(vipGroup.getStatus())
					&&!VipGroupStatusEnum.FINISHED.equals(vipGroup.getStatus())){
				throw new BizException("非进行中课程组不允许进行此操作");
			}
		}
        teacherAttendanceDao.batchCleanCourseTeacherSignInfo(courseScheduleId);
        studentAttendanceDao.deleteByCourseSchedules(courseScheduleId);
		//删除申述
		courseScheduleComplaintsDao.delByCourseScheduleIds(courseScheduleId);
		//清除考勤申述
		teacherAttendanceDao.clearAttendanceComplaints(courseScheduleId);
        //重置学生人数
		courseScheduleDao.resetStudentNum(courseScheduleId);
    }

	@Override
	public Object teacherCourseRemarkInfo(Long courseScheduleId) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if (null == user) {
			throw new BizException("获取用户信息失败");
		}
		if(courseScheduleId == null){
			throw new BizException("参数校验失败");
		}
		Map<String,Object> resultMap = new HashMap<>(7);
		//获取课程详情
		CourseSchedule schedule = courseScheduleDao.get(courseScheduleId);
		resultMap.put("courseScheduleName",schedule.getName());
		resultMap.put("courseScheduleClassDate",schedule.getClassDate());
		resultMap.put("courseScheduleStartClassTime",schedule.getStartClassTime());
		resultMap.put("courseScheduleEndClassTime",schedule.getEndClassTime());
		resultMap.put("courseScheduleContent",schedule.getTeachingContent());
		//获取当前课程的声部
		resultMap.put("subjectName",courseScheduleDao.getSubjectNameById(courseScheduleId));
		//获取学员评论详情
		resultMap.put("studentRemark",courseScheduleComplaintsDao.findByCourseScheduleId(courseScheduleId));
		//获取当前课程的学员列表
		resultMap.put("students",courseScheduleStudentPaymentDao.findStudents(courseScheduleId));
		//获取当前课程老师的评价列表
		resultMap.put("teacherRemark",courseScheduleEvaluateDao.findByCourseAndTeacher(user.getId(),courseScheduleId));
		return resultMap;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void teacherCourseRemarkCommit(TeacherRemarkCommitDto teacherRemarkCommitDt) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if (null == user) {
			throw new BizException("获取用户信息失败");
		}
		Long courseScheduleId = teacherRemarkCommitDt.getCourseScheduleId();
		CourseSchedule schedule = courseScheduleDao.get(courseScheduleId);
		if(schedule == null){
			throw new BizException("课程不存在");
		}
		if(StringUtils.isNotEmpty(schedule.getTeachingContent())){
			throw new BizException("您已提交过课程评价,请勿重复提交");
		}
		//是否提交过评论
		List<CourseScheduleEvaluate> byCourseAndTeacher = courseScheduleEvaluateDao.findByCourseAndTeacher(user.getId(), courseScheduleId);
		if(byCourseAndTeacher != null && byCourseAndTeacher.size() > 0){
			throw new BizException("您已提交过课程评价,请勿重复提交");
		}
		//修改教学内容
		if(StringUtils.isNotEmpty(teacherRemarkCommitDt.getTeachingContent())){
			schedule.setTeachingContent(teacherRemarkCommitDt.getTeachingContent());
			schedule.setUpdateTime(new Date());
			courseScheduleDao.update(schedule);
		}
		List<CourseScheduleEvaluate> courseScheduleEvaluates = teacherRemarkCommitDt.getCourseScheduleEvaluates();
		if(courseScheduleEvaluates != null || courseScheduleEvaluates.size() > 0){
			courseScheduleEvaluates.forEach(e->{
				e.setMusicGroupId(schedule.getMusicGroupId());
				e.setClassGroupId(schedule.getClassGroupId());
				e.setTeacherId(user.getId());
				e.setCourseScheduleId(courseScheduleId);
				e.setIsPushed(0);
				courseScheduleEvaluateDao.insert(e);
			});
		}
	}

	@Override
	public Object getTeacherCourseHeadInfo(GroupType groupType,String groupId,Long courseScheduleId){
		Map<String,Object> resultMap = new HashMap<>(8);
		Teacher teacher;
		switch (groupType){
			case PRACTICE:
				PracticeGroup practiceGroup = practiceGroupDao.get(Long.parseLong(groupId));
				resultMap.put("groupName",practiceGroup.getName());
				resultMap.put("groupStatus",practiceGroup.getGroupStatus().getCode());
				teacher = teacherDao.get(practiceGroup.getUserId());
				resultMap.put("groupTeacher",teacher.getRealName());
				resultMap.put("teacherIntroduction",teacher.getIntroduction());
				resultMap.put("teacherAvatar",teacher.getAvatar());
				//统计授课次数
				resultMap.put("teacherGiveLesson",courseScheduleTeacherSalaryDao.countTeacherGiveLesson(practiceGroup.getUserId()));
				break;
			case VIP:
				VipGroup vipGroup = vipGroupDao.get(Long.parseLong(groupId));
				resultMap.put("groupName",vipGroup.getName());
				resultMap.put("groupStatus",vipGroup.getStatus().getCode());
				teacher = teacherDao.get(vipGroup.getUserId());
				resultMap.put("groupTeacher",teacher.getRealName());
				resultMap.put("teacherIntroduction",teacher.getIntroduction());
				resultMap.put("teacherAvatar",teacher.getAvatar());
				//统计授课次数
				resultMap.put("teacherGiveLesson",courseScheduleTeacherSalaryDao.countTeacherGiveLesson(vipGroup.getUserId()));
				break;
			case COMM:
				CoursesGroup coursesGroup = coursesGroupDao.get(Long.parseLong(groupId));
				resultMap.put("groupName",coursesGroup.getName());
				resultMap.put("groupStatus",coursesGroup.getStatus().getCode());
				teacher = teacherDao.get(coursesGroup.getTeacherId());
				resultMap.put("groupTeacher",teacher.getRealName());
				resultMap.put("teacherIntroduction",teacher.getIntroduction());
				resultMap.put("teacherAvatar",teacher.getAvatar());
				//统计授课次数
				resultMap.put("teacherGiveLesson",courseScheduleTeacherSalaryDao.countTeacherGiveLesson(coursesGroup.getTeacherId()));
				break;
			case MUSIC:
				if(courseScheduleId != null){
					ClassGroup byCourseSchedule = classGroupDao.findByCourseSchedule(courseScheduleId.intValue(),null);
					resultMap.put("groupName",byCourseSchedule.getName());
					ClassGroupTeacherMapper groupTeachersRole = classGroupTeacherMapperService.getClassGroupTeachersRole(byCourseSchedule.getId(), "BISHOP");
					if(groupTeachersRole != null){
						teacher = teacherDao.get(groupTeachersRole.getUserId());
						resultMap.put("groupTeacher",teacher.getRealName());
						resultMap.put("teacherIntroduction",teacher.getIntroduction());
						resultMap.put("teacherAvatar",teacher.getAvatar());
						resultMap.put("teacherGiveLesson",courseScheduleTeacherSalaryDao.countTeacherGiveLesson(groupTeachersRole.getUserId()));
					}
				}
				break;
			default:
				throw new BizException("课程类型错误");
		}
		resultMap.put("startTime",courseScheduleDao.getMinCourseTime(groupType, groupId));
		resultMap.put("endTime",courseScheduleDao.getMaxCourseTime(groupType, groupId));
		return resultMap;
	}

	@Override
	public Object queryCourseInfoByGroupId(GroupType groupType, String groupId) {
    	List<CourseSchedule> courseSchedules = courseScheduleDao.findCourseByGroupId(groupType.getCode(),groupId);
    	Map<String,Object> resultMap = new HashMap<>(4);
    	resultMap.put("courseInfo",courseSchedules);
    	resultMap.put("count",courseSchedules.size());
		int online = courseSchedules.stream().filter(e -> e.getTeachMode() == TeachModeEnum.ONLINE).collect(Collectors.toList()).size();
		int offline = courseSchedules.stream().filter(e -> e.getTeachMode() == TeachModeEnum.OFFLINE).collect(Collectors.toList()).size();
		resultMap.put("online",online);
		resultMap.put("offline",offline);
		return resultMap;
	}

	@Override
	public Object teacherCourseMinutes(QueryInfo queryInfo) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if (null == user) {
			throw new BizException("获取用户信息失败");
		}
		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<>(16);
		MapUtil.populateMap(params, queryInfo);
		params.put("userId",user.getId());
		int count = coursesGroupDao.countTeacherCourseGroups(params);
		if(count > 0){
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			List<CoursesGroup> courseGroups = coursesGroupDao.queryTeacherCourseGroups(params);
			List<Long> collect = courseGroups.stream().map(e -> e.getId()).collect(Collectors.toList());
			//获取冻结课时
			Map<Long,Long> freezeMinutesMap = MapUtil.convertIntegerMap(coursesGroupDao.findFreezeMinutes(collect));
			//获取已消耗课时
			Map<Long,Long> consumeMinutesMap = MapUtil.convertIntegerMap(coursesGroupDao.findConsumeMinutes(collect));
			courseGroups.forEach(e->{
				Long aLong = freezeMinutesMap.get(e.getId());
				e.setFreezeMinutes(aLong == null?0:aLong.intValue());
				Long aLong1 = consumeMinutesMap.get(e.getId());
				e.setConsumeMinutes(aLong1 == null?0:aLong1.intValue());
			});
			pageInfo.setRows(courseGroups);
		}
		return pageInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateCoursesExpireDate(String practiceGroupId, Date coursesExpireDate) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if (null == user) {
			throw new BizException("获取用户信息失败");
		}
    	if(practiceGroupId == null || coursesExpireDate == null ){
    		throw new BizException("参数校验失败");
		}
		PracticeGroup practiceGroup = practiceGroupDao.get(Long.parseLong(practiceGroupId));
    	if(practiceGroup == null){
			throw new BizException("课程组不存在");
		}
		if(practiceGroup.getCoursesStartDate().after(coursesExpireDate)){
			throw new BizException("课程有效时间不能早于开始时间");
		}
		if(Objects.nonNull(practiceGroup.getBuyMonths())){
			LocalDate courseStartDay = LocalDateTime.ofInstant(practiceGroup.getCoursesStartDate().toInstant(), DateUtil.zoneId).toLocalDate();
			LocalDate currentExpiredDay = courseStartDay.plusMonths(practiceGroup.getBuyMonths()).plusDays(-1);
			Date courseExpiredDateTemp=Date.from(currentExpiredDay.atStartOfDay(DateUtil.zoneId).toInstant());
			if(coursesExpireDate.before(courseExpiredDateTemp)){
				throw new BizException("课程结束时间不得早于，{}", DateUtil.dateToString(courseExpiredDateTemp, "yyyy年MM月dd日"));
			}
		}
		CoursesGroupModifyLog coursesGroupModifyLog = new CoursesGroupModifyLog();
		coursesGroupModifyLog.setGroupId(practiceGroupId);
		coursesGroupModifyLog.setGroupType(PRACTICE.getCode());
		coursesGroupModifyLog.setOperatorId(user.getId());
		coursesGroupModifyLog.setPreviousGroup(JSONObject.toJSONString(practiceGroup));
		practiceGroup.setCoursesExpireDate(DateUtil.addSeconds(DateUtil.addDays(coursesExpireDate, 1),-1));
		practiceGroup.setUpdateTime(new Date());
		practiceGroupDao.update(practiceGroup);
		coursesGroupModifyLog.setCurrentGroup(JSONObject.toJSONString(practiceGroup));
		coursesGroupModifyLogDao.insert(coursesGroupModifyLog);
	}

	@Override
	public List<CourseSchedule> queryNoStartCourseByTeacherId(String classGroupIds, Integer teacherId, String teacherRole) {
		return courseScheduleDao.queryNoStartCourseByTeacherId(classGroupIds,teacherId,teacherRole);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void classGroupTeacherAdjust(String classGroupIds, Integer teacherId, Integer targetTeacherId) {
		List<Integer> teachingTeacherIdList = new ArrayList<Integer>();
		teachingTeacherIdList.add(targetTeacherId);
		List<CourseSchedule> courseSchedules = this.queryNoStartCourseByTeacherId(classGroupIds,teacherId,"BISHOP");
		//获取助教老师列表
		if(courseSchedules.size() > 0){
			courseSchedules.forEach(e->{
				e.setTeachingTeacherIdList(courseScheduleTeacherSalaryDao.queryTeacherByTeaching(e.getClassGroupId(),"TEACHING"));
				e.setActualTeacherId(targetTeacherId);
			});
			this.courseAdjust(courseSchedules);
			//修改老师考勤
			Set<Integer> collect1 = courseSchedules.stream().map(e -> e.getClassGroupId()).collect(Collectors.toSet());
//			teacherAttendanceDao.deleteByCourseAndTeacherId(collect1,teacherId);
			batchUpdateClassTeacher(new ArrayList<>(collect1),teacherId,targetTeacherId);
		}
		List<CourseSchedule> courseSchedules1 = this.queryNoStartCourseByTeacherId(classGroupIds, teacherId, "TEACHING");
		if(courseSchedules1.size() > 0){
			courseSchedules1.forEach(e->{
				e.setActualTeacherId(courseScheduleTeacherSalaryDao.queryTeacherByBishop(e.getClassGroupId()));
				e.setTeachingTeacherIdList(teachingTeacherIdList);
			});
			this.courseAdjust(courseSchedules1);
			Set<Integer> collect1 = courseSchedules1.stream().map(e -> e.getClassGroupId()).collect(Collectors.toSet());
////			teacherAttendanceDao.deleteByCourseAndTeacherId(collect1,teacherId);
			batchUpdateClassTeacher(new ArrayList<>(collect1),teacherId,targetTeacherId);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void batchPracticeGroupTeacherAdjust(String practiceGroupId, Integer teacherId, Integer subjectId, Integer educationalTeacherId,Integer oldTeacherId) {
		String[] split = practiceGroupId.split(",");
		for (int i = 0; i < split.length; i++) {
			this.practiceGroupTeacherAdjust(split[i],teacherId,subjectId,educationalTeacherId);
		}
		List<ClassGroup> classGroups = classGroupDao.queryClassGroups(practiceGroupId,"PRACTICE");
		if(classGroups.size() > 0){
			List<Integer> collect = classGroups.stream().map(e -> e.getId()).collect(Collectors.toList());
			batchUpdateClassTeacher(collect,oldTeacherId,teacherId);
		}
	}

	@Transactional(rollbackFor = Exception.class)
	public void batchUpdateClassTeacher(List<Integer> classGroupIds,Integer oldTeacherId,Integer newTeacherId){
		//修改班级老师
		List<ClassGroup> classGroupList = classGroupDao.findByClassGroupIds(classGroupIds,null);
		classGroupList.forEach(e->{
			e.setUserIds(newTeacherId.toString());
		});
		classGroupTeacherMapperService.batchUpdateTeacherByClassId(classGroupIds,oldTeacherId,newTeacherId);
		//旧老师退群,新老师加群
		if(classGroupList != null && classGroupIds.size() > 0){
			ImGroupMember[] oldImGroupMembers = {new ImGroupMember(oldTeacherId.toString())};
			ImGroupMember[] imGroupMembers = {new ImGroupMember(newTeacherId.toString())};
			for (ClassGroup classGroup:classGroupList) {
				imGroupMemberService.quit(classGroup.getId().longValue(), oldTeacherId);
				imGroupMemberService.join(classGroup.getId().longValue(), newTeacherId, "指导老师", false);
			}
		}
	}

	@Override
	public Object teacherCourseHeadInfo(Long courseScheduleId) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if (null == user) {
			throw new BizException("获取用户信息失败");
		}
		CourseSchedule schedule = courseScheduleDao.get(courseScheduleId);
		if(schedule == null){
			throw new BizException("课程不存在");
		}
		return getTeacherCourseHeadInfo(schedule.getGroupType(),schedule.getMusicGroupId(),courseScheduleId);
	}

	@Override
	public Object teacherCourseRates(Long courseScheduleId) {
		SysUser user = sysUserFeignService.queryUserInfo();
		if (null == user) {
			throw new BizException("获取用户信息失败");
		}
		CourseSchedule schedule = courseScheduleDao.get(courseScheduleId);
		if(schedule == null){
			throw new BizException("课程不存在");
		}
		//如果是乐团课
		List<CourseScheduleRateDto> courseScheduleRateDtos;
		CourseSchedule courseSchedule;
		if(schedule.getGroupType() == MUSIC){
			//获取当前班级
			courseScheduleRateDtos = courseScheduleDao.findCourseRate(null,schedule.getGroupType().getCode(),schedule.getClassGroupId());
			//获取最近一次已结束的课程
			courseSchedule = courseScheduleDao.getLastEndCourse(null,schedule.getGroupType().getCode(),schedule.getClassGroupId());
		}else {
			//获取课程列表
			courseScheduleRateDtos = courseScheduleDao.findCourseRate(schedule.getMusicGroupId(),schedule.getGroupType().getCode(),null);
			//获取最近一次已结束的课程
			courseSchedule = courseScheduleDao.getLastEndCourse(schedule.getMusicGroupId(),schedule.getGroupType().getCode(),null);
		}
		List<Long> courseScheduleIds = courseScheduleRateDtos.stream().map(CourseScheduleRateDto::getCourseScheduleId).collect(Collectors.toList());
		List<CourseScheduleReview> courseReviews = courseScheduleReviewDao.findByCourseSchedules(courseScheduleIds);
		Map<Integer, List<CourseScheduleReview>> reviews = courseReviews.stream().collect(Collectors.groupingBy(CourseScheduleReview::getCourseScheduleId));

		//标记当前课程的上一节课
		if(courseSchedule != null){
			for (CourseScheduleRateDto e:courseScheduleRateDtos) {
				if(reviews.containsKey(e.getCourseScheduleId().intValue())){
					List<CourseScheduleReview> review = reviews.get(e.getCourseScheduleId().intValue());
					e.setTeachingContent(review.get(0).getTeachingMaterial());
				}
			}
			for (CourseScheduleRateDto e:courseScheduleRateDtos) {
				if(e.getCourseScheduleId().equals(courseSchedule.getId())){
					e.setIsDefault(true);
					break;
				}
			}
		}
		return courseScheduleRateDtos;
	}

	@Override
	public List<CourseScheduleModifyLog> queryCourseAdjustDetail(Long courseScheduleId) {
		//获取所有的更改记录
		Map<String,Object> param = new HashMap(1);
		param.put("courseScheduleId",courseScheduleId);
		List<CourseScheduleModifyLog> scheduleModifyLogs = courseScheduleModifyLogDao.findAll(param);
		List<CourseScheduleAuditDetailDto> courseSchedules = new ArrayList<>();
		for (CourseScheduleModifyLog modifyLog : scheduleModifyLogs) {
			CourseScheduleAuditDetailDto auditDetailDto = JSON.parseObject(modifyLog.getPreviousCourseSchedule(), CourseScheduleAuditDetailDto.class);
			auditDetailDto.setOperatorId(modifyLog.getOperatorId());
			courseSchedules.add(auditDetailDto);
			CourseScheduleAuditDetailDto auditDetailDto1 = JSON.parseObject(modifyLog.getCurrentCourseSchedule(), CourseScheduleAuditDetailDto.class);
			auditDetailDto1.setOperatorId(modifyLog.getOperatorId());
			courseSchedules.add(auditDetailDto1);
		}
		if(courseSchedules.size() > 0){
			Set<Integer> actualTeacherIds = courseSchedules.stream().map(e -> e.getActualTeacherId()).collect(Collectors.toSet());
			actualTeacherIds.addAll(courseSchedules.stream().map(e -> e.getTeacherId()).collect(Collectors.toSet()));
			actualTeacherIds.addAll(courseSchedules.stream().map(e -> e.getOperatorId()).collect(Collectors.toSet()));
			Set<Integer> schoolIds = courseSchedules.stream().map(e -> e.getSchoolId()).collect(Collectors.toSet());
			Map<Integer, String> actualTeacherMap = getMap("sys_user", "id_", "real_name_", actualTeacherIds, Integer.class, String.class);
			Map<Integer, String> schoolMap = new HashMap<>();
			if(schoolIds != null && schoolIds.size() > 0){
				schoolMap = getMap("school", "id_", "name_", schoolIds, Integer.class, String.class);
			}
			for (CourseScheduleModifyLog modifyLog : scheduleModifyLogs) {
				CourseScheduleAuditDetailDto preAuditDetailDto = JSON.parseObject(modifyLog.getPreviousCourseSchedule(), CourseScheduleAuditDetailDto.class);
				preAuditDetailDto.setTeacherName(actualTeacherMap.get(preAuditDetailDto.getTeacherId()));
				preAuditDetailDto.setActualTeacherName(actualTeacherMap.get(preAuditDetailDto.getActualTeacherId()));
				preAuditDetailDto.setSchoolName(schoolMap.get(preAuditDetailDto.getSchoolId()));
				preAuditDetailDto.setOperatorName(actualTeacherMap.get(modifyLog.getOperatorId()));
				if(StringUtils.isNotEmpty(preAuditDetailDto.getTeachingTeacherIds())){
					preAuditDetailDto.setTeachingTeacherNames(teacherDao.queryTeacherNameByTeacherIds(preAuditDetailDto.getTeachingTeacherIds()));
				}
				modifyLog.setPreviousCourseSchedule(JSONObject.toJSONString(preAuditDetailDto));

				CourseScheduleAuditDetailDto auditDetailDto = JSON.parseObject(modifyLog.getCurrentCourseSchedule(), CourseScheduleAuditDetailDto.class);
				auditDetailDto.setTeacherName(actualTeacherMap.get(auditDetailDto.getTeacherId()));
				auditDetailDto.setActualTeacherName(actualTeacherMap.get(auditDetailDto.getActualTeacherId()));
				auditDetailDto.setSchoolName(schoolMap.get(auditDetailDto.getSchoolId()));
				auditDetailDto.setOperatorName(actualTeacherMap.get(modifyLog.getOperatorId()));
				if(StringUtils.isNotEmpty(auditDetailDto.getTeachingTeacherIds())){
					auditDetailDto.setTeachingTeacherNames(teacherDao.queryTeacherNameByTeacherIds(auditDetailDto.getTeachingTeacherIds()));
				}
				modifyLog.setCurrentCourseSchedule(JSONObject.toJSONString(auditDetailDto));
			}
			return scheduleModifyLogs;
		}
		return null;
	}

	@Override
	public void courseRepeatCheck() {
		List<CourseRepeatCheckDto> courseRepeatCheckInfos = courseScheduleDao.getCourseRepeatCheckInfos();
		courseRepeatCheckInfos.sort(Comparator.comparing(CourseRepeatCheckDto::getStartClassTime));
		Map<Date, List<CourseRepeatCheckDto>> dayCourseMap = courseRepeatCheckInfos.stream().collect(Collectors.groupingBy(CourseRepeatCheckDto::getClassDate));
		Map<Long, Map<String, Object>> courseRepeatIdMap = new HashMap<>();
		int needAdjustCourseNum = 0;
		for (CourseRepeatCheckDto cs1 : courseRepeatCheckInfos) {
			if(!courseRepeatIdMap.containsKey(cs1.getCourseId())){
				Map<String, Object> result = new HashMap<>();
				result.put("repeatCourseId", new ArrayList<>());
				courseRepeatIdMap.put(cs1.getCourseId(), result);
//				courseRepeatIdMap.get(cs1.getCourseId()).add(cs1.getCourseId());
			}else{
				continue;
			}
			List<CourseRepeatCheckDto> dayCourses = dayCourseMap.get(cs1.getClassDate());
			for (CourseRepeatCheckDto cs2 : dayCourses) {
				if(cs1.getCourseId().equals(cs2.getCourseId())){
					continue;
				}
				if(cs2.getEndClassTime().compareTo(cs1.getStartClassTime())<=0){
					continue;
				}

				if(courseRepeatIdMap.containsKey(cs2.getCourseId())
						&&((List<Long>)courseRepeatIdMap.get(cs2.getCourseId()).get("repeatCourseId")).contains(cs1.getCourseId())){
					continue;
				}
				if(cs2.getStartClassTime().compareTo(cs1.getEndClassTime())>=0){
					List<Long> repeatCourseId = (List<Long>) courseRepeatIdMap.get(cs1.getCourseId()).get("repeatCourseId");
					if(CollectionUtils.isEmpty(((List<Long>)courseRepeatIdMap.get(cs1.getCourseId()).get("repeatCourseId")))){
						courseRepeatIdMap.remove(cs1.getCourseId());
					}
					break;
				}
				if(cs1.getStartClassTime().compareTo(cs2.getEndClassTime())>=0||cs1.getEndClassTime().compareTo(cs2.getStartClassTime())<=0){
					continue;
				}
				Set<Integer> repeatTeacherIds = cs1.getTeacherIds().stream().filter(teacherId -> cs2.getTeacherIds().contains(teacherId)).collect(Collectors.toSet());
				if(repeatTeacherIds.size()>0){
					courseRepeatIdMap.get(cs1.getCourseId()).put("cause", "冲突教师编号:"+StringUtils.join(repeatTeacherIds));
					((List<Long>)courseRepeatIdMap.get(cs1.getCourseId()).get("repeatCourseId")).add(cs2.getCourseId());
					needAdjustCourseNum++;
					continue;
				}

				Set<Integer> repeatStudentIds = cs1.getStudentIds().stream().filter(studentId -> cs2.getStudentIds().contains(studentId)).collect(Collectors.toSet());
				if(repeatStudentIds.size()>0){
					courseRepeatIdMap.get(cs1.getCourseId()).put("cause", "学生冲突:"+StringUtils.join(repeatStudentIds));
					((List<Long>)courseRepeatIdMap.get(cs1.getCourseId()).get("repeatCourseId")).add(cs2.getCourseId());
					needAdjustCourseNum++;
					continue;
				}
			}
			if(courseRepeatIdMap.containsKey(cs1.getCourseId())&&CollectionUtils.isEmpty(((List<Long>)courseRepeatIdMap.get(cs1.getCourseId()).get("repeatCourseId")))){
				courseRepeatIdMap.remove(cs1.getCourseId());
			}
		}
		System.out.println("重复课程：" + JSON.toJSONString(courseRepeatIdMap));
		System.out.println("需调整课程数量：" + needAdjustCourseNum);
		System.out.println("重复课程数量：" + courseRepeatIdMap.size());
	}

	@Override
	public List<CourseSchedule> classGroupNotStartMergeCourseReplace(Long classGroupId) {
		List<CourseSchedule> courseSchedules = courseScheduleDao.getClassGroupCourses(classGroupId);
		Set<Long> newCourseIds = courseSchedules.stream().filter(c -> Objects.nonNull(c.getNewCourseId())).map(CourseSchedule::getNewCourseId).collect(Collectors.toSet());
		if(CollectionUtils.isEmpty(newCourseIds)){
			return Collections.EMPTY_LIST;
		}

		Date now = new Date();

		List<CourseSchedule> mainCourses = courseScheduleDao.findByCourseScheduleIds(new ArrayList<>(newCourseIds));
		Map<Long, CourseSchedule> idCourseMap = mainCourses.stream().collect(Collectors.toMap(CourseSchedule::getId, c -> c, (c1, c2) -> c1));
		Iterator<CourseSchedule> iterator = courseSchedules.iterator();
		while (iterator.hasNext()){
			CourseSchedule next = iterator.next();
			if(Objects.isNull(next.getNewCourseId())){
				continue;
			}
			CourseSchedule mainCourse = idCourseMap.get(next.getNewCourseId());
			if(next.getClassGroupId().equals(mainCourse.getClassGroupId())||mainCourse.getStartClassTime().compareTo(now)<0){
				iterator.remove();
			}
		}
		for (CourseSchedule courseSchedule : courseSchedules) {
			if(Objects.isNull(courseSchedule.getNewCourseId())){
				continue;
			}
			courseSchedule = idCourseMap.get(courseSchedule.getId());
		}
		return courseSchedules;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void courseMerge(CourseMergeDto courseMergeInfo) {
		Date now = new Date();

		if(CollectionUtils.isEmpty(courseMergeInfo.getMergeCourseIds())){
			throw new BizException("请选择需要合并的课程");
		}
		int courseMergeTime = courseScheduleDao.countCourseMergeTime(courseMergeInfo.getId());
		if(courseMergeTime>0){
			throw new BizException("存在已合并课程");
		}
		List<Long> allCourseIds = new ArrayList<>();
		allCourseIds.add(courseMergeInfo.getId());
		allCourseIds.addAll(courseMergeInfo.getMergeCourseIds());
		List<CourseSchedule> allCourses = courseScheduleDao.findByCourseScheduleIds(allCourseIds);
		int courseTypeNum = allCourses.stream().map(CourseSchedule::getType).collect(Collectors.toSet()).size();
//		if(courseTypeNum>1){
//			throw new BizException("课程合并仅支持同课程类型");
//		}
		for (CourseSchedule courseSchedule : allCourses) {
			if(Objects.nonNull(courseSchedule.getNewCourseId())){
				throw new BizException("存在已合并课程");
			}
			if(courseSchedule.getStartClassTime().compareTo(now)<=0){
				throw new BizException("课程合并仅支持未开始的课程");
			}
			if(VIP.equals(courseSchedule.getGroupType())||PRACTICE.equals(courseSchedule.getGroupType())){
				throw new BizException("VIP课、网管课暂不支持课程合并");
			}
			if(CourseScheduleType.MUSIC_NETWORK.equals(courseSchedule.getType())||CourseScheduleType.HIGH_ONLINE.equals(courseSchedule.getType())){
				throw new BizException("乐团网管课、线上基础技能课暂不支持课程合并");
			}
			if(Objects.isNull(courseMergeInfo.getClassGroupId())&&courseMergeInfo.getId().equals(courseSchedule.getId())){
				courseMergeInfo.setClassGroupId(courseSchedule.getClassGroupId());
				courseMergeInfo.setGroupType(courseSchedule.getGroupType());
				courseMergeInfo.setMusicGroupId(courseSchedule.getMusicGroupId());
			}
			courseSchedule.setNote("课程合并");
		}
		List<CourseScheduleStudentPayment> courseScheduleStudentPayments = courseScheduleStudentPaymentDao.findByCourseScheduleIds(allCourseIds);
		Map<Long, Set<Integer>> courseStudentIdsMap = courseScheduleStudentPayments.stream().collect(Collectors.groupingBy(CourseScheduleStudentPayment::getCourseScheduleId, Collectors.mapping(CourseScheduleStudentPayment::getUserId, Collectors.toSet())));
		Set<Integer> allStudentIds = courseScheduleStudentPayments.stream().map(CourseScheduleStudentPayment::getUserId).collect(Collectors.toSet());

		Map<Integer, CourseScheduleStudentPayment> mainStudentCourseMap = courseScheduleStudentPayments.stream().filter(c -> courseMergeInfo.getId().equals(c.getCourseScheduleId())).collect(Collectors.toMap(CourseScheduleStudentPayment::getUserId, c -> c, (c1, c2) -> c1));

		Map<Integer, List<CourseScheduleStudentPayment>> otherStudentCourseMap = courseScheduleStudentPayments.stream().filter(c -> !courseMergeInfo.getId().equals(c.getCourseScheduleId())).collect(Collectors.groupingBy(CourseScheduleStudentPayment::getUserId));


		List<CourseScheduleStudentPayment> newPayments = new ArrayList<>();
		List<CourseScheduleStudentPayment> updatePayments = new ArrayList<>();

		for (Map.Entry<Integer, List<CourseScheduleStudentPayment>> otherStudentCourseMapEntry : otherStudentCourseMap.entrySet()) {
			List<CourseScheduleStudentPayment> studentCoursePayments = otherStudentCourseMapEntry.getValue();
			BigDecimal salary = studentCoursePayments.stream().map(CourseScheduleStudentPayment::getExpectPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
			if(mainStudentCourseMap.containsKey(otherStudentCourseMapEntry.getKey())){
				CourseScheduleStudentPayment updatePayment = mainStudentCourseMap.get(otherStudentCourseMapEntry.getKey());
				updatePayment.setExpectPrice(updatePayment.getExpectPrice().add(salary));
				updatePayments.add(updatePayment);

				for (CourseScheduleStudentPayment studentCoursePayment : studentCoursePayments) {
					studentCoursePayment.setExpectPrice(BigDecimal.ZERO);
					updatePayments.add(studentCoursePayment);
				}
				continue;
			}
			CourseScheduleStudentPayment newPayment = new CourseScheduleStudentPayment();
			BeanUtils.copyProperties(studentCoursePayments.get(0), newPayment);
			newPayment.setCourseScheduleId(courseMergeInfo.getId());
			newPayment.setClassGroupId(courseMergeInfo.getClassGroupId());
			newPayment.setMusicGroupId(courseMergeInfo.getMusicGroupId());
			newPayment.setGroupType(courseMergeInfo.getGroupType());
			newPayment.setExpectPrice(salary);
			newPayment.setId(null);
			newPayments.add(newPayment);
			for (CourseScheduleStudentPayment studentCoursePayment : studentCoursePayments) {
				studentCoursePayment.setExpectPrice(BigDecimal.ZERO);
				updatePayments.add(studentCoursePayment);
			}
		}

		List<CourseSchedule> courseSchedules=new ArrayList<>();
		courseMergeInfo.setNewCourseId(courseMergeInfo.getId());
		courseSchedules.add(courseMergeInfo);
		List<CourseScheduleModifyLog> insertCourseScheduleModifyLogList = new ArrayList<>();

		List<CourseSchedule> mergeCourses = allCourses.stream().filter(c->courseMergeInfo.getMergeCourseIds().contains(c.getId())&&!c.getId().equals(courseMergeInfo.getId())).collect(Collectors.toList());
		for (CourseSchedule courseSchedule : mergeCourses) {
			CourseScheduleModifyLog courseScheduleModifyLog = new CourseScheduleModifyLog();
			courseScheduleModifyLog.setCourseScheduleId(courseSchedule.getId());
			courseScheduleModifyLog.setCreateTime(now);
			courseScheduleModifyLog.setPreviousCourseSchedule(JsonUtil.toJSONString(courseSchedule));

			//课程信息变更
			courseSchedule.setNewCourseId(courseMergeInfo.getId());
//			courseSchedule.setClassDate(courseMergeInfo.getClassDate());
//			courseSchedule.setStartClassTime(courseMergeInfo.getStartClassTime());
//			courseSchedule.setEndClassTime(courseMergeInfo.getEndClassTime());
//			courseSchedule.setActualTeacherId(courseMergeInfo.getActualTeacherId());
//			courseSchedule.setClassGroupId(courseMergeInfo.getClassGroupId());
//			courseSchedule.setSchoolId(courseMergeInfo.getSchoolId());

			courseScheduleModifyLog.setCurrentCourseSchedule(JsonUtil.toJSONString(courseSchedule));
			courseScheduleModifyLog.setOperatorId(courseMergeInfo.getOperatorId());
			insertCourseScheduleModifyLogList.add(courseScheduleModifyLog);
		}
		courseScheduleDao.batchUpdate(mergeCourses);

		courseScheduleStudentPaymentDao.batchUpdate(updatePayments);
		if(!CollectionUtils.isEmpty(newPayments))
			courseScheduleStudentPaymentDao.batchInsert(newPayments);

		courseAdjust(courseSchedules);

		if (insertCourseScheduleModifyLogList.size() > 0) {
			courseScheduleModifyLogDao.batchInsert(insertCourseScheduleModifyLogList);
		}
	}
}
