package com.qmth.exam.reserve.service.impl; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.qmth.boot.core.collection.PageResult; import com.qmth.boot.core.exception.StatusException; import com.qmth.boot.tools.excel.ExcelReader; import com.qmth.boot.tools.excel.enums.ExcelType; import com.qmth.boot.tools.excel.model.DataMap; import com.qmth.exam.reserve.bean.login.LoginUser; import com.qmth.exam.reserve.bean.stdapply.AgentAndTimeVO; import com.qmth.exam.reserve.bean.stdapply.StudentApplyReq; import com.qmth.exam.reserve.bean.stdapply.StudentApplyVO; import com.qmth.exam.reserve.bean.stdapply.StudentImportVO; import com.qmth.exam.reserve.cache.CacheConstants; import com.qmth.exam.reserve.cache.RedisClient; import com.qmth.exam.reserve.dao.StudentApplyDao; import com.qmth.exam.reserve.entity.ApplyTaskEntity; import com.qmth.exam.reserve.entity.CategoryEntity; import com.qmth.exam.reserve.entity.ExamRoomEntity; import com.qmth.exam.reserve.entity.ExamSiteEntity; import com.qmth.exam.reserve.entity.StudentApplyEntity; import com.qmth.exam.reserve.entity.StudentEntity; import com.qmth.exam.reserve.entity.TimePeriodEntity; import com.qmth.exam.reserve.enums.CategoryLevel; import com.qmth.exam.reserve.enums.DateField; import com.qmth.exam.reserve.enums.EventType; import com.qmth.exam.reserve.service.ApplyTaskService; import com.qmth.exam.reserve.service.CategoryService; import com.qmth.exam.reserve.service.ExamRoomService; import com.qmth.exam.reserve.service.ExamSiteService; import com.qmth.exam.reserve.service.OperateLogService; import com.qmth.exam.reserve.service.StudentApplyService; import com.qmth.exam.reserve.service.StudentService; import com.qmth.exam.reserve.service.TimePeriodService; import com.qmth.exam.reserve.util.DateUtil; import com.qmth.exam.reserve.util.JsonHelper; import com.qmth.exam.reserve.util.PageUtil; @Service public class StudentApplyServiceImpl extends ServiceImpl implements StudentApplyService { private final static Logger log = LoggerFactory.getLogger(StudentApplyServiceImpl.class); private static final String[] EXCEL_HEADER = new String[] { "学号", "姓名", "证件号", "所属教学点", "预约考点1", "预约时段1", "预约考点2", "预约时段2", "预约考点3", "预约时段3", "预约考点4", "预约时段4" }; private final long TIMEOUT = 60; @Autowired private TimePeriodService timePeriodService; @Autowired private ApplyTaskService applyTaskService; @Autowired private CategoryService categoryService; @Autowired private StudentService studentService; @Autowired private ExamSiteService examSiteService; @Autowired private OperateLogService operateLogService; @Autowired private RedisClient redisClient; @Autowired private ExamRoomService examRoomService; @Override public PageResult page(StudentApplyReq req) { IPage iPage = this.baseMapper .page(new Page(req.getPageNumber(), req.getPageSize()), req); return PageUtil.of(iPage); } @Transactional @Override public void cancel(LoginUser user, Long id) { // 时间判断 StudentApplyEntity studentApply = this.baseMapper.selectById(id); if (studentApply == null || studentApply.getTimePeriodId() == null) throw new StatusException("考生没有预约,无法取消!"); TimePeriodEntity timePeroid = timePeriodService.getById(studentApply.getTimePeriodId()); if (timePeroid == null) throw new StatusException("考试时段不存在,请检查考试时段数据!"); ApplyTaskEntity task = getApplyTask(); Date applyDate = DateUtil.parse(DateUtil.getShortDateByLongTime(timePeroid.getStartTime()), "yyyy-MM-dd"); Date canCancelDay = DateUtil.addValues(applyDate, DateField.DAY.getValue(), -task.getAllowApplyCancelDays()); if (new Date().after(canCancelDay)) throw new StatusException("可取消时间已过,无法取消!"); studentApply.setCancel(Boolean.TRUE); this.baseMapper.updateById(studentApply); // TODO redis更新:该时段redis已预约的数量减1 operateLogService.insertOperateLog(user.getId(), EventType.CANCEL_APPLY, JsonHelper.toJson(studentApply)); } @Transactional @Override public List> importPreExam(LoginUser user, Long teachingId, InputStream inputStream) { checkInOpenTime(); List lineList = null; ExcelReader reader = ExcelReader.create(ExcelType.XLSX, inputStream, 0); try { lineList = reader.getDataMapList(); } catch (Exception e) { throw new StatusException("Excel 解析失败"); } if (!Arrays.equals(EXCEL_HEADER, reader.getColumnNames())) { throw new StatusException("Excel表头错误"); } if (CollectionUtils.isEmpty(lineList)) { throw new StatusException("Excel无内容"); } List> failRecords = new ArrayList>(); Map teachingCache = getTeachingCache(); Map agentCache = getAgentCache(teachingId); Map timeCache = getTimePeriodCache(); List applyList = new ArrayList<>(); AgentAndTimeVO agentTime = new AgentAndTimeVO(); for (int i = 0; i < lineList.size(); i++) { List agentTimeList = new ArrayList<>(); DataMap line = lineList.get(i); StudentImportVO apply = new StudentImportVO(); StringBuilder msg = new StringBuilder(); String studentCode = trimAndNullIfBlank(line.get(EXCEL_HEADER[0])); if (StringUtils.isBlank(studentCode)) { msg.append(" 学号不能为空"); } String name = trimAndNullIfBlank(line.get(EXCEL_HEADER[1])); if (StringUtils.isBlank(name)) { msg.append(" 姓名不能为空"); } String identityNumber = trimAndNullIfBlank(line.get(EXCEL_HEADER[2])); if (StringUtils.isBlank(identityNumber)) { msg.append(" 证件号不能为空"); } StudentEntity student = null; try { student = checkStd(studentCode, name, identityNumber); apply.setStudentId(student.getId()); } catch (StatusException e) { msg.append(" " + e.getMessage()); failRecords.add(newError(i + 1, msg.toString())); continue; } String teachingName = trimAndNullIfBlank(line.get(EXCEL_HEADER[3])); if (StringUtils.isBlank(teachingName)) { msg.append(" 所属教学点不能为空"); } Long categoryId = teachingCache.get(teachingName); if (categoryId == null) { msg.append(" 所属教学点不存在"); } if (!student.getCategoryId().equals(categoryId)) { msg.append(" 考生所属教学点和库中的考生教学点不匹配"); } String agentName1 = trimAndNullIfBlank(line.get(EXCEL_HEADER[4])); if (StringUtils.isBlank(agentName1)) { msg.append(" 预约考点1不能为空"); } agentTime = new AgentAndTimeVO(); Long agentId = agentCache.get(agentName1); if (agentId == null) { msg.append(" 预约考点1不存在"); } String timePeriod1 = trimAndNullIfBlank(line.get(EXCEL_HEADER[5])); if (StringUtils.isBlank(timePeriod1)) { msg.append(" 预约时段1不能为空"); } Long timePeriodId = null; try { timePeriodId = checkTimePeriod(timePeriod1, timeCache); agentTime.setAgentId(agentId); agentTime.setTimePeriodId(timePeriodId); agentTimeList.add(agentTime); } catch (StatusException e) { msg.append(" " + e.getMessage()); } String agentName2 = trimAndNullIfBlank(line.get(EXCEL_HEADER[6])); String timePeriod2 = trimAndNullIfBlank(line.get(EXCEL_HEADER[7])); if (StringUtils.isBlank(agentName2) && StringUtils.isBlank(timePeriod2)) { apply.setAgentTimeList(agentTimeList); applyList.add(apply); if (msg.length() > 0) failRecords.add(newError(i + 1, msg.toString())); continue; } else { agentId = agentCache.get(agentName2); if (agentId == null) msg.append(" 预约考点2不存在"); try { timePeriodId = checkTimePeriod(timePeriod2, timeCache); agentTime = new AgentAndTimeVO(); agentTime.setAgentId(agentId); agentTime.setTimePeriodId(timePeriodId); agentTimeList.add(agentTime); } catch (StatusException e) { msg.append(" " + e.getMessage()); } } String agentName3 = trimAndNullIfBlank(line.get(EXCEL_HEADER[8])); String timePeriod3 = trimAndNullIfBlank(line.get(EXCEL_HEADER[9])); if (StringUtils.isBlank(agentName3) && StringUtils.isBlank(timePeriod3)) { apply.setAgentTimeList(agentTimeList); applyList.add(apply); if (msg.length() > 0) failRecords.add(newError(i + 1, msg.toString())); continue; } else { agentId = agentCache.get(agentName3); if (agentId == null) msg.append(" 预约考点3不存在"); try { timePeriodId = checkTimePeriod(timePeriod3, timeCache); agentTime = new AgentAndTimeVO(); agentTime.setAgentId(agentId); agentTime.setTimePeriodId(timePeriodId); agentTimeList.add(agentTime); } catch (StatusException e) { msg.append(" " + e.getMessage()); } } String agentName4 = trimAndNullIfBlank(line.get(EXCEL_HEADER[10])); String timePeriod4 = trimAndNullIfBlank(line.get(EXCEL_HEADER[11])); if (StringUtils.isBlank(agentName4) && StringUtils.isBlank(timePeriod4)) { apply.setAgentTimeList(agentTimeList); applyList.add(apply); if (msg.length() > 0) failRecords.add(newError(i + 1, msg.toString())); continue; } else { agentId = agentCache.get(agentName4); if (agentId == null) msg.append(" 预约考点4不存在"); try { timePeriodId = checkTimePeriod(timePeriod4, timeCache); agentTime = new AgentAndTimeVO(); agentTime.setAgentId(agentId); agentTime.setTimePeriodId(timePeriodId); agentTimeList.add(agentTime); apply.setAgentTimeList(agentTimeList); applyList.add(apply); } catch (StatusException e) { msg.append(" " + e.getMessage()); } } } if (CollectionUtils.isNotEmpty(failRecords)) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return failRecords; } for (int i = 0; i < applyList.size(); i++) { StudentImportVO vo = applyList.get(i); try { saveStdApply(user.getId(), vo); } catch (StatusException e) { failRecords.add(newError(i + 1, e.getMessage())); } catch (Exception e) { failRecords.add(newError(i + 1, " 系统异常")); log.error("导入异常", e); } } if (CollectionUtils.isNotEmpty(failRecords)) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } if (CollectionUtils.isEmpty(failRecords)) { new Thread(() -> { checkStudentApplyFinish(applyList); }).start(); } // TODO 更新redis return failRecords; } private void checkStudentApplyFinish(List applyList) { for (StudentImportVO importVO : applyList) { StudentEntity student = studentService.getById(importVO.getStudentId()); List haveApplyList = listStudentApply(importVO.getStudentId(), Boolean.TRUE); if (student.getApplyNumber().intValue() == haveApplyList.size()) { // 更新考生的完成状态 student.setApplyFinished(Boolean.TRUE); studentService.updateById(student); } } } private void checkInOpenTime() { ApplyTaskEntity task = getApplyTask(); Date start = DateUtil.parse(DateUtil.getLongDateByLongTime(task.getOpenApplyStartTime()), null); Date end = DateUtil.parse(DateUtil.getLongDateByLongTime(task.getOpenApplyEndTime()), null); if (!DateUtil.isBetwwen(start, end)) { throw new StatusException("导入预考,必须要在第一阶段导入!"); } } private ApplyTaskEntity getApplyTask() { LambdaQueryWrapper wrapper = new LambdaQueryWrapper() .eq(ApplyTaskEntity::getEnable, Boolean.TRUE); return applyTaskService.getOne(wrapper); } private void saveStdApply(Long userId, StudentImportVO vo) { List agentTimeList = vo.getAgentTimeList(); LambdaQueryWrapper lm = new LambdaQueryWrapper<>(); lm.eq(StudentApplyEntity::getStudentId, vo.getStudentId()); LogStdApply(userId, this.baseMapper.selectList(lm)); this.baseMapper.delete(lm); for (AgentAndTimeVO agentTime : agentTimeList) { StudentApplyEntity entity = new StudentApplyEntity(); entity.setStudentId(vo.getStudentId()); entity.setCreateTime(System.currentTimeMillis()); entity.setUpdateTime(System.currentTimeMillis()); entity.setExamSiteId(agentTime.getAgentId()); entity.setTimePeriodId(agentTime.getTimePeriodId()); entity.setCancel(Boolean.FALSE); this.baseMapper.insert(entity); } } private void LogStdApply(Long userId, List existList) { if (!existList.isEmpty()) { for (StudentApplyEntity studentApply : existList) { this.operateLogService.insertOperateLog(userId, EventType.DELETE_APPLY, JsonHelper.toJson(studentApply)); } } } private Long checkTimePeriod(String timePeriod, Map timeCache) { if (timePeriod.split(" ").length != 2) { throw new StatusException(" 预约时段格式不正确"); } String[] arr = timePeriod.split("-"); String startTime = arr[0] + ":00"; String endTime = startTime.substring(0, startTime.indexOf("日") + 1) + " " + arr[1] + ":00"; Long startTimeLong = DateUtil.getLongTimeByZHDate(startTime); Long endTimeLong = DateUtil.getLongTimeByZHDate(endTime); if (timeCache.get(startTimeLong + "-" + endTimeLong) == null) { throw new StatusException(" 预约时段不存在"); } return timeCache.get(startTimeLong + "-" + endTimeLong); } private Map getTimePeriodCache() { Map map = new HashMap<>(); LambdaQueryWrapper lm = new LambdaQueryWrapper<>(); List timeList = timePeriodService.list(lm); for (TimePeriodEntity time : timeList) { map.put(time.getStartTime() + "-" + time.getEndTime(), time.getId()); } return map; } private Map getTeachingCache() { LambdaQueryWrapper lm = new LambdaQueryWrapper<>(); lm.eq(CategoryEntity::getEnable, Boolean.TRUE); lm.eq(CategoryEntity::getLevel, CategoryLevel.TEACHING.getValue()); List categoryList = categoryService.list(lm); return categoryList.stream().collect(Collectors.toMap(CategoryEntity::getName, CategoryEntity::getId)); } private Map getAgentCache(Long categoryId) { LambdaQueryWrapper lm = new LambdaQueryWrapper<>(); lm.eq(ExamSiteEntity::getEnable, Boolean.TRUE); lm.eq(ExamSiteEntity::getCategoryId, categoryId); List categoryList = examSiteService.list(lm); return categoryList.stream().collect(Collectors.toMap(ExamSiteEntity::getName, ExamSiteEntity::getId)); } private StudentEntity checkStd(String studentCode, String name, String identityNumber) { LambdaQueryWrapper lm = new LambdaQueryWrapper<>(); lm.eq(StudentEntity::getStudentCode, studentCode); lm.eq(StudentEntity::getName, name); lm.eq(StudentEntity::getIdentityNumber, identityNumber); StudentEntity student = studentService.getOne(lm); if (student == null) { throw new StatusException(" 考生信息填写错误"); } return student; } private Map newError(int lineNum, String msg) { Map map = new HashMap<>(); map.put("lineNum", lineNum); map.put("msg", msg); return map; } private String trimAndNullIfBlank(String s) { if (StringUtils.isBlank(s)) { return null; } return s.trim(); } @Transactional @Override public void autoAssign(Long taskId) { checkAfterOpenTime(); try { // 1、未完成预约的考生 LambdaQueryWrapper lm = new LambdaQueryWrapper<>(); lm.eq(StudentEntity::getApplyFinished, Boolean.FALSE); List studentList = studentService.list(lm); Map> map = studentList.stream() .collect(Collectors.groupingBy(StudentEntity::getCategoryId)); // 2、考位是否充足 List timeList = listTimePeroid(taskId); checkTeachingCapacity(map, timeList, taskId); // 3、按照教学点安排考位。规则:不能和已预约的时间上有冲突 for (Long key : map.keySet()) { List siteList = listExamSite(key); List teachingStudentList = map.get(key); for (TimePeriodEntity time : timeList) { for (ExamSiteEntity site : siteList) { // 该时段已预约的考生 Integer haveApplyNum = getHaveApplyNum(site.getId(), time.getId()); // 剩余的考位 Integer remainNum = site.getCapacity() - haveApplyNum; assignStudentApply(site.getId(), time.getId(), teachingStudentList, remainNum); } } // 4、判断是否还有剩余考生未完成预约,提醒考位不够 if (teachingStudentList.size() > 0) throw new StatusException("【" + categoryService.getById(key).getName() + "】教学点考位不足"); } } catch (Exception e) { log.error(e.getMessage()); throw new StatusException(e.getMessage()); } finally { } } private void assignStudentApply(Long siteId, Long timeId, List teachingStudentList, Integer remainNum) { int num = 0; for (Iterator iterator = teachingStudentList.iterator(); iterator.hasNext();) { StudentEntity student = iterator.next(); if (num >= remainNum) break; List studentApplyList = listStudentApply(student.getId(), Boolean.FALSE); int toApplyNum = student.getApplyNumber() - studentApplyList.size(); if (toApplyNum > 0 && !haveApplySameTimePeriod(siteId, timeId, student.getId())) { StudentApplyEntity studentApply = new StudentApplyEntity(); studentApply.setCreateTime(System.currentTimeMillis()); studentApply.setUpdateTime(System.currentTimeMillis()); studentApply.setStudentId(student.getId()); studentApply.setExamSiteId(siteId); studentApply.setCancel(Boolean.FALSE); studentApply.setTimePeriodId(timeId); baseMapper.insert(studentApply); num++; if (toApplyNum - (studentApplyList.size() + 1) == 0) { iterator.remove(); student.setApplyFinished(true); this.studentService.updateById(student); } } } } private boolean haveApplySameTimePeriod(Long siteId, Long timeId, Long studentId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StudentApplyEntity::getExamSiteId, siteId); wrapper.eq(StudentApplyEntity::getTimePeriodId, timeId); wrapper.eq(StudentApplyEntity::getStudentId, studentId); wrapper.eq(StudentApplyEntity::getCancel, Boolean.FALSE); StudentApplyEntity studentApply = baseMapper.selectOne(wrapper); return studentApply == null ? false : true; } private Integer getHaveApplyNum(Long siteId, Long timeId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StudentApplyEntity::getExamSiteId, siteId); wrapper.eq(StudentApplyEntity::getTimePeriodId, timeId); wrapper.eq(StudentApplyEntity::getCancel, Boolean.FALSE); List haveAplyList = baseMapper.selectList(wrapper); return haveAplyList == null ? 0 : haveAplyList.size(); } private void checkAfterOpenTime() { ApplyTaskEntity task = getApplyTask(); Date openEndTime = DateUtil.parse(DateUtil.getLongDateByLongTime(task.getOpenApplyEndTime()), null); Date selfStartTime = DateUtil.parse(DateUtil.getLongDateByLongTime(task.getSelfApplyStartTime()), null); if (!DateUtil.isBetwwen(openEndTime, selfStartTime)) { throw new StatusException("自动分配,时间必须要在第一阶段结束之后,第三阶段开始之前"); } } private void checkTeachingCapacity(Map> map, List timeList, Long taskId) { for (Long key : map.keySet()) { List siteList = listExamSite(key); // 总考位数量 Integer total = siteList.stream().collect(Collectors.summingInt(ExamSiteEntity::getCapacity)) * timeList.size(); // 已经预约的数量 Integer haveApplyNum = this.getBaseMapper().getHaveApplyCount( siteList.stream().map(site -> site.getId()).collect(Collectors.toList()), Boolean.FALSE); // 未预约的数量 Integer noApplyNum = getNoApplyNum(map.get(key)); if (noApplyNum > total - haveApplyNum) { CategoryEntity category = categoryService.getById(key); throw new StatusException("【" + category.getName() + "】教学点考位不足!剩余的考位数量:【" + (total - haveApplyNum) + "】,实际需要的考位数量:【" + noApplyNum + "】"); } } } private Integer getNoApplyNum(List list) { Integer noApplyNum = 0; for (StudentEntity student : list) { if (student.getApplyNumber().intValue() == 1) { noApplyNum++; } else if (student.getApplyNumber().intValue() > 1) { noApplyNum = noApplyNum + (student.getApplyNumber() - listStudentApply(student.getId(), Boolean.TRUE).size()); } } return noApplyNum; } private List listStudentApply(Long stdId, Boolean cancel) { LambdaQueryWrapper lm = new LambdaQueryWrapper<>(); lm.eq(StudentApplyEntity::getStudentId, stdId); lm.eq(StudentApplyEntity::getCancel, cancel); return this.baseMapper.selectList(lm); } private List listTimePeroid(Long taskId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(TimePeriodEntity::getApplyTaskId, taskId); wrapper.orderByAsc(TimePeriodEntity::getStartTime); List timeList = timePeriodService.list(wrapper); if (timeList.isEmpty()) { throw new StatusException("考试时段未设置"); } return timeList; } private List listExamSite(Long categoryId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ExamSiteEntity::getCategoryId, categoryId); return examSiteService.list(wrapper); } @Override public void autoLayout(Long teachingId) { ApplyTaskEntity applyTask = getApplyTask(); if (applyTask == null) { log.info("没有开启的预约任务"); return; } boolean isSuccess = redisClient.tryLock( CacheConstants.LOCK_ARRANGE_EXAM + DateUtil.formatShortDateString(new Date()), UUID.randomUUID(), TIMEOUT, TimeUnit.MINUTES); try { if (isSuccess) { // 1.根据当前日期,查询不能取消的时段 List timePeriodList = listTimePeroid(applyTask.getId()); List noCancelTimePeroidList = listNoCancelApplyTimePeroid(timePeriodList, applyTask.getAllowApplyCancelDays()); if (noCancelTimePeroidList.isEmpty()) { log.info("当前时间,没有取消的时段。"); return; } // 2.查询考试日期的待排考的考生 List toBeLayoutStudentList = this.baseMapper.listTimePeriod( noCancelTimePeroidList.stream().map(item -> item.getId()).collect(Collectors.toList()), Boolean.FALSE); // 3.开始排考 Map> toBeLayoutStudentMap = toBeLayoutStudentList.stream() .collect(Collectors.groupingBy(StudentApplyEntity::getExamSiteId)); for (Long examSiteId : toBeLayoutStudentMap.keySet()) { Map> timeLayoutStudentMap = toBeLayoutStudentMap.get(examSiteId) .stream().collect(Collectors.groupingBy(StudentApplyEntity::getTimePeriodId)); List roomList = listExamRoom(examSiteId); if (roomList.isEmpty()) { throw new StatusException(examSiteId + ":未设置考场"); } ExamSiteEntity examSite = examSiteService.getById(examSiteId); layoutStudentByTimePeriod(applyTask.getId(), examSite, roomList, timeLayoutStudentMap); } } } catch (StatusException e) { log.error(e.getMessage()); e.printStackTrace(); } finally { redisClient.delete(CacheConstants.LOCK_ARRANGE_EXAM + DateUtil.formatShortDateString(new Date())); } } private void layoutStudentByTimePeriod(Long taskId, ExamSiteEntity examSite, List roomList, Map> timeLayoutStudentMap) { for (Long timePeriodId : timeLayoutStudentMap.keySet()) { List studentApplyList = timeLayoutStudentMap.get(timePeriodId); layoutStudentToRoom(taskId, examSite, roomList, studentApplyList, timePeriodService.getById(timePeriodId)); } } private void layoutStudentToRoom(Long taskId, ExamSiteEntity examSite, List roomList, List studentApplyList, TimePeriodEntity timePeriod) { Integer timePeriodOrder = getTimePeriodOrder(taskId, timePeriod); for (ExamRoomEntity room : roomList) { Integer num = 0; for (Iterator iterator = studentApplyList.iterator(); iterator.hasNext();) { StudentApplyEntity student = iterator.next(); if (num >= room.getCapacity()) break; String seatNumber = StringUtils.leftPad(String.valueOf(++num), 3, '0'); student.setExamRoomId(room.getId()); student.setSeatNumber(seatNumber); student.setTicketNumber( generateTicketNumber(timePeriodOrder, examSite.getCode(), room.getCode(), seatNumber)); this.baseMapper.updateById(student); iterator.remove(); } } } private Integer getTimePeriodOrder(Long taskId, TimePeriodEntity timePeriod) { List timeList = listTimePeroid(taskId); List sameDayTimeList = listSameDayTimePeroid(timeList, timePeriod.getStartTime()); for (int i = 0; i < sameDayTimeList.size(); i++) { TimePeriodEntity time = sameDayTimeList.get(i); if (time.getStartTime().equals(timePeriod.getStartTime())) return i + 1; } return 0; } private List listSameDayTimePeroid(List timeList, Long startTime) { String day = DateUtil.getShortDateWithoutSplitByLongTime(startTime); List resultList = new ArrayList<>(); for (TimePeriodEntity time : timeList) { if (DateUtil.getShortDateWithoutSplitByLongTime(startTime).equals(day)) resultList.add(time); } return resultList.stream().sorted(Comparator.comparing(TimePeriodEntity::getStartTime)) .collect(Collectors.toList()); } private String generateTicketNumber(Integer timePeriodOrder, String examSiteCode, String roomCode, String seatNumber) { return DateUtil.formatShortDateString(new Date()) + timePeriodOrder + examSiteCode + roomCode + seatNumber; } public List listExamRoom(Long examSiteId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ExamRoomEntity::getExamSiteId, examSiteId); wrapper.orderByAsc(ExamRoomEntity::getCode); return examRoomService.list(wrapper); } private List listNoCancelApplyTimePeroid(List list, Integer allowApplyCancelDays) { String noCancelDate = getNoCancelApplyDate(allowApplyCancelDays); List noCancelTimePeroidList = new ArrayList<>(); for (TimePeriodEntity time : list) { if (DateUtil.getShortDateWithoutSplitByLongTime(time.getStartTime()).equals(noCancelDate)) noCancelTimePeroidList.add(time); } return noCancelTimePeroidList; } private String getNoCancelApplyDate(Integer allowApplyCancelDays) { return DateUtil.formatShortDateString(DateUtil.addValues(DateField.DAY.getValue(), allowApplyCancelDays)); } }