Browse Source

相关业务 修改为读取缓存的方式

haogh 1 year ago
parent
commit
0bed10d051

+ 1 - 1
src/main/java/com/qmth/exam/reserve/controller/admin/StudentApplyController.java

@@ -129,7 +129,7 @@ public class StudentApplyController extends BaseController {
         if (!Role.ADMIN.equals(user.getRole())) {
             throw new StatusException("没有权限");
         }
-        studentApplyService.autoAssign(taskId);
+        studentApplyService.autoAssign(taskId, user.getId());
     }
 
     @ApiOperation(value = "打印签到表")

+ 1 - 1
src/main/java/com/qmth/exam/reserve/service/StudentApplyService.java

@@ -21,7 +21,7 @@ public interface StudentApplyService extends IService<StudentApplyEntity> {
 
     List<Map<String, Object>> importPreExam(Long userId, Long teachingId, Integer level, InputStream inputStream);
 
-    void autoAssign(Long taskId);
+    void autoAssign(Long taskId, Long userId);
 
     void autoLayout(Long teachingId);
 

+ 225 - 120
src/main/java/com/qmth/exam/reserve/service/impl/StudentApplyServiceImpl.java

@@ -3,10 +3,8 @@ package com.qmth.exam.reserve.service.impl;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.time.Instant;
 import java.time.LocalDate;
 import java.time.ZoneId;
-import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -15,10 +13,8 @@ import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.concurrent.locks.Lock;
 import java.util.stream.Collectors;
 
@@ -29,7 +25,6 @@ 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;
@@ -43,6 +38,8 @@ 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.boot.tools.io.ZipWriter;
+import com.qmth.exam.reserve.bean.Constants;
+import com.qmth.exam.reserve.bean.apply.ApplyRecordCacheBean;
 import com.qmth.exam.reserve.bean.login.LoginUser;
 import com.qmth.exam.reserve.bean.stdapply.AgentAndTimeVO;
 import com.qmth.exam.reserve.bean.stdapply.MaterialTitleInfo;
@@ -130,21 +127,51 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
     public void cancel(LoginUser user, Long id) {
         // 时间判断
         StudentApplyEntity studentApply = this.baseMapper.selectById(id);
-        if (studentApply == null || studentApply.getTimePeriodId() == null)
+        if (studentApply == null || studentApply.getTimePeriodId() == null) {
             throw new StatusException("考生没有预约,无法取消!");
-        TimePeriodEntity timePeroid = timePeriodService.getById(studentApply.getTimePeriodId());
-        if (timePeroid == null)
+        }
+        TimePeriodEntity timePeriod = timePeriodService.getById(studentApply.getTimePeriodId());
+        if (timePeriod == null) {
             throw new StatusException("考试时段不存在,请检查考试时段数据!");
+        }
         ApplyTaskEntity task = getApplyTask();
-        Date applyDate = DateUtils.truncate(new Date(timePeroid.getStartTime()), Calendar.DATE);
+        Date applyDate = DateUtils.truncate(new Date(timePeriod.getStartTime()), Calendar.DATE);
         Date canCancelDay = DateUtil.addValues(applyDate, Calendar.DAY_OF_MONTH, -task.getAllowApplyCancelDays());
-        if (new Date().after(canCancelDay))
+        if (new Date().after(canCancelDay)) {
             throw new StatusException("可取消时间已过,无法取消!");
-        studentApply.setCancel(Boolean.TRUE);
-        this.baseMapper.updateById(studentApply);
+        }
 
-        // redis更新:该时段redis已预约的数量减1
-        cacheService.decreaseApplyFinishCount(studentApply.getExamSiteId(), studentApply.getTimePeriodId());
+        String studentApplyLockKey = String.format(CacheConstants.LOCK_STUDENT_APPLY, studentApply.getStudentId());
+        Lock studentApplyLock = concurrentService.getLock(studentApplyLockKey);
+        try {
+            if (!studentApplyLock.tryLock()) {
+                log.warn("获取锁失败,同一个考生不允许同时操作预约!lockKey:{}", studentApplyLockKey);
+                throw new StatusException(Constants.SYSTEM_BUSY);
+            }
+            if (studentApplyLock.tryLock()) {
+                studentApply.setCancel(Boolean.TRUE);
+                this.baseMapper.updateById(studentApply);
+
+                ApplyRecordCacheBean bean = new ApplyRecordCacheBean();
+                bean.setStudentId(studentApply.getStudentId());
+                bean.setExamSiteId(studentApply.getExamSiteId());
+                bean.setTimePeriodId(studentApply.getTimePeriodId());
+                bean.setCancel(Boolean.TRUE);
+                bean.setOperateId(user.getId());
+                bean.setOperateTime(System.currentTimeMillis());
+                cacheService.saveStudentApplyRecord(bean);
+                cacheService.pushStudentApplyRecordQueue(bean);
+                cacheService.decreaseApplyFinishCount(studentApply.getExamSiteId(), studentApply.getTimePeriodId());
+            }
+        } catch (Exception e) {
+            throw new StatusException("取消预约失败,请稍后再试!", e);
+        } finally {
+            try {
+                studentApplyLock.unlock();
+            } catch (Exception e) {
+                log.warn(e.getMessage());
+            }
+        }
 
         operateLogService.insertOperateLog(user.getId(), EventType.CANCEL_APPLY, JsonHelper.toJson(studentApply));
     }
@@ -153,7 +180,6 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
     @Override
     public List<Map<String, Object>> importPreExam(Long userId, Long teachingId, Integer level,
             InputStream inputStream) {
-        /* checkInOpenTime(); */
         List<DataMap> lineList = null;
         ExcelReader reader = ExcelReader.create(ExcelType.XLSX, inputStream, 0);
         try {
@@ -321,16 +347,12 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
 
         checkStudentApplyTime(applyList, getApplyTask().getAllowApplyCancelDays(), failRecords);
         if (CollectionUtils.isNotEmpty(failRecords)) {
-            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+            // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
             return failRecords;
         }
         checkAvailableTimePeriod(applyList);
-        List<AgentAndTimeVO> toBeUpdateAgentTimeList = new ArrayList<>();
         for (int i = 0; i < applyList.size(); i++) {
             StudentImportVO vo = applyList.get(i);
-            if (!vo.getAgentTimeList().isEmpty()) {
-                toBeUpdateAgentTimeList.addAll(vo.getAgentTimeList());
-            }
             try {
                 saveStdApply(i, vo, userId, failRecords);
             } catch (StatusException e) {
@@ -340,12 +362,10 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
         }
 
         if (CollectionUtils.isNotEmpty(failRecords)) {
-            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+            // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
             return failRecords;
         }
 
-        // 导入预考后,更新redis
-        updateRedisCount(toBeUpdateAgentTimeList);
         return failRecords;
 
     }
@@ -355,23 +375,29 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
             StudentImportVO vo = applyList.get(i);
             List<AgentAndTimeVO> agentTimeList = vo.getAgentTimeList();
             List<StudentApplyEntity> haveApplyList = listStudentApply(vo.getStudentId(), Boolean.FALSE);
+            int studentApplyFinishCount = cacheService.getStudentApplyFinishCount(vo.getStudentId());
+            if (studentApplyFinishCount == 0) {
+                studentApplyFinishCount = haveApplyList.size();
+            }
             Collections.sort(agentTimeList, Comparator.comparing(AgentAndTimeVO::getStartTime));
-            // 考生已经预约,不做处理,跳过
             List<AgentAndTimeVO> tobeInsertTimeList = new ArrayList<>();
-            if (haveApplyList.size() >= agentTimeList.size()) {
-                vo.setAgentTimeList(tobeInsertTimeList);
+
+            // 考生已经完成预约-不做处理
+            if (studentApplyFinishCount == vo.getApplyNumber().intValue()) {
                 continue;
             }
+
             // 只预约了部分
-            if (haveApplyList.size() > 0 && haveApplyList.size() < agentTimeList.size()) {
+            if (studentApplyFinishCount > 0 && studentApplyFinishCount < vo.getApplyNumber()) {
                 List<AgentAndTimeVO> availableList = listAvailableTime(haveApplyList, agentTimeList);
                 // 需要填充的次数
-                for (int j = 0; j < agentTimeList.size() - haveApplyList.size(); j++) {
+                for (int j = 0; j < availableList.size(); j++) {
                     tobeInsertTimeList.add(availableList.get(j));
                 }
             }
+
             // 未预约
-            if (haveApplyList.size() == 0) {
+            if (studentApplyFinishCount == 0) {
                 tobeInsertTimeList = agentTimeList;
             }
             vo.setAgentTimeList(tobeInsertTimeList);
@@ -420,12 +446,6 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
         }
     }
 
-    private void updateRedisCount(List<AgentAndTimeVO> toBeUpdateAgentTimeList) {
-        for (AgentAndTimeVO time : toBeUpdateAgentTimeList) {
-            cacheService.increaseApplyFinishCount(time.getAgentId(), time.getTimePeriodId());
-        }
-    }
-
     private ApplyTaskEntity getApplyTask() {
         LambdaQueryWrapper<ApplyTaskEntity> wrapper = new LambdaQueryWrapper<ApplyTaskEntity>()
                 .eq(ApplyTaskEntity::getEnable, Boolean.TRUE);
@@ -439,20 +459,57 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
             List<Map<String, Object>> failRecords) {
         List<StudentApplyEntity> ApplyList = new ArrayList<>();
         List<AgentAndTimeVO> agentTimeList = vo.getAgentTimeList();
-        for (AgentAndTimeVO agentTime : agentTimeList) {
-            StudentApplyEntity entity = new StudentApplyEntity();
-            entity.setStudentId(vo.getStudentId());
-            entity.setExamSiteId(agentTime.getAgentId());
-            entity.setTimePeriodId(agentTime.getTimePeriodId());
-            entity.setCancel(Boolean.FALSE);
-            entity.setOperateId(userId);
-            int haveApplyCount = countApplyFinishForExamSiteAndTimePeriod(agentTime.getAgentId(),
-                    agentTime.getTimePeriodId());
-            ExamSiteEntity examSite = examSiteService.getById(agentTime.getAgentId());
-            if (haveApplyCount >= examSite.getCapacity().intValue()) {
-                failRecords.add(newError(row + 1, " 考点【" + examSite.getName() + "】的容量已满"));
+        String studentApplyLockKey = String.format(CacheConstants.LOCK_STUDENT_APPLY, vo.getStudentId());
+        Lock studentApplyLock = concurrentService.getLock(studentApplyLockKey);
+        try {
+            if (!studentApplyLock.tryLock()) {
+                log.warn("获取锁失败,考生在同时操作预约!lockKey:{}", studentApplyLockKey);
             } else {
-                this.baseMapper.insert(entity);
+                for (AgentAndTimeVO agentTime : agentTimeList) {
+                    // 已经预约的容量和考点的容量从redis中获取
+                    int haveApplyCount = cacheService.getApplyFinishCount(agentTime.getAgentId(),
+                            agentTime.getTimePeriodId());
+                    int examSiteCount = cacheService.getApplyTotalCount(agentTime.getAgentId());
+                    if (haveApplyCount >= examSiteCount) {
+                        ExamSiteEntity examSite = examSiteService.getById(agentTime.getAgentId());
+                        failRecords.add(newError(row + 1, " 考点【" + examSite.getName() + "】的容量已满"));
+                    } else {
+                        StudentApplyEntity entity = new StudentApplyEntity();
+                        entity.setStudentId(vo.getStudentId());
+                        entity.setExamSiteId(agentTime.getAgentId());
+                        entity.setTimePeriodId(agentTime.getTimePeriodId());
+                        entity.setCancel(Boolean.FALSE);
+                        entity.setOperateId(userId);
+
+                        StudentApplyEntity existStudentApply = findStudentApply(entity);
+                        if (existStudentApply != null) {
+                            existStudentApply.setCancel(Boolean.FALSE);
+                            baseMapper.updateById(existStudentApply);
+                        } else {
+                            baseMapper.insert(entity);
+                        }
+
+                        ApplyRecordCacheBean bean = new ApplyRecordCacheBean();
+                        bean.setStudentId(vo.getStudentId());
+                        bean.setExamSiteId(agentTime.getAgentId());
+                        bean.setTimePeriodId(agentTime.getTimePeriodId());
+                        bean.setCancel(Boolean.FALSE);
+                        bean.setOperateId(userId);
+                        bean.setOperateTime(System.currentTimeMillis());
+                        cacheService.saveStudentApplyRecord(bean);
+                        cacheService.pushStudentApplyRecordQueue(bean);
+                        cacheService.increaseApplyFinishCount(agentTime.getAgentId(), agentTime.getTimePeriodId());
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("导入预考失败,错误原因:", e.getMessage());
+            throw new StatusException("导入预考失败,请稍后再试!", e);
+        } finally {
+            try {
+                studentApplyLock.unlock();
+            } catch (Exception e) {
+                log.warn(e.getMessage());
             }
         }
         return ApplyList;
@@ -527,10 +584,9 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
 
     @Transactional
     @Override
-    public void autoAssign(Long taskId) {
+    public void autoAssign(Long taskId, Long userId) {
         checkAfterOpenTime();
         Lock lock = concurrentService.getLock(CacheConstants.LOCK_AUTO_APPLY);
-        List<StudentApplyEntity> updateToRedisList = new ArrayList<>();
         try {
             if (!lock.tryLock()) {
                 log.warn("获取锁失败,不允许同时执行自动分配!lockKey:{}", CacheConstants.LOCK_AUTO_APPLY);
@@ -538,23 +594,26 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
             }
             // 1、未完成预约的考生
             List<StudentEntity> studentList = studentService.listNoFinishStudent(taskId, Boolean.FALSE);
-            Map<Long, List<StudentEntity>> map = studentList.stream()
+            Map<Long, List<StudentEntity>> noFinishApplyMap = studentList.stream()
                     .collect(Collectors.groupingBy(StudentEntity::getCategoryId));
             // 2、考位是否充足
             List<TimePeriodEntity> timeList = listTimePeroid(taskId);
-            checkTeachingCapacity(map, timeList, taskId);
+            checkTeachingCapacity(noFinishApplyMap, timeList, taskId);
             // 3、按照教学点安排考位。规则:不能和已预约的时间上有冲突
-            for (Long key : map.keySet()) {
+            for (Long key : noFinishApplyMap.keySet()) {
                 List<ExamSiteEntity> siteList = listExamSite(key, null);
-                List<StudentEntity> teachingStudentList = map.get(key);
+                List<StudentEntity> teachingStudentList = noFinishApplyMap.get(key);
                 for (ExamSiteEntity site : siteList) {
                     for (TimePeriodEntity time : timeList) {
                         // 该时段已预约的考生
-                        Integer haveApplyNum = getHaveApplyNum(site.getId(), time.getId());
+                        Integer haveApplyNum = cacheService.getApplyFinishCount(site.getId(), time.getId());
+                        if (haveApplyNum == null || haveApplyNum == 0) {
+                            haveApplyNum = getHaveApplyNum(site.getId(), time.getId());
+                        }
                         // 剩余的考位
                         Integer remainNum = site.getCapacity() - haveApplyNum;
-                        updateToRedisList
-                                .addAll(assignStudentApply(site.getId(), time.getId(), teachingStudentList, remainNum));
+
+                        assignStudentApply(userId, site.getId(), time.getId(), teachingStudentList, remainNum);
                     }
                 }
                 // 4、判断是否还有剩余考生未完成预约,提醒考位不够
@@ -565,51 +624,94 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
             log.error(e.getMessage());
             throw new StatusException(e.getMessage());
         } finally {
-            lock.unlock();
-        }
-        // 更新缓存
-        for (StudentApplyEntity apply : updateToRedisList) {
-            cacheService.increaseApplyFinishCount(apply.getExamSiteId(), apply.getTimePeriodId());
+            try {
+                lock.unlock();
+            } catch (Exception e) {
+                log.warn(e.getMessage());
+            }
         }
 
     }
 
-    private List<StudentApplyEntity> assignStudentApply(Long siteId, Long timeId,
+    private List<StudentApplyEntity> assignStudentApply(Long userId, Long siteId, Long timeId,
             List<StudentEntity> teachingStudentList, Integer remainNum) {
         List<StudentApplyEntity> insertApplyList = new ArrayList<>();
         int num = 0;
+        String studentApplyLockKey = null;
+        Lock studentApplyLock = null;
         for (Iterator<StudentEntity> iterator = teachingStudentList.iterator(); iterator.hasNext();) {
             StudentEntity student = iterator.next();
-            String studentApplyLockKey = String.format(CacheConstants.LOCK_STUDENT_APPLY, student.getId());
-            Lock studentApplyLock = concurrentService.getLock(studentApplyLockKey);
             if (num >= remainNum)
                 break;
-            List<StudentApplyEntity> 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.setStudentId(student.getId());
-                studentApply.setExamSiteId(siteId);
-                studentApply.setCancel(Boolean.FALSE);
-                studentApply.setTimePeriodId(timeId);
-                if (studentApplyLock.tryLock()) {
-                    baseMapper.insert(studentApply);
-                    insertApplyList.add(studentApply);
-                    studentApplyLock.unlock();
+            studentApplyLockKey = String.format(CacheConstants.LOCK_STUDENT_APPLY, student.getId());
+            studentApplyLock = concurrentService.getLock(studentApplyLockKey);
+            try {
+                if (!studentApplyLock.tryLock()) {
+                    log.warn("获取锁失败,考生在同时操作预约!lockKey:{}", studentApplyLockKey);
+                    iterator.remove();
                 } else {
-                    log.warn("获取锁失败,不允许同一个考生同时操作预约!lockKey:{}", studentApplyLockKey);
+                    List<StudentApplyEntity> 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.setStudentId(student.getId());
+                        studentApply.setExamSiteId(siteId);
+                        studentApply.setCancel(Boolean.FALSE);
+                        studentApply.setTimePeriodId(timeId);
+
+                        StudentApplyEntity existStudentApply = findStudentApply(studentApply);
+                        if (existStudentApply != null) {
+                            existStudentApply.setCancel(Boolean.FALSE);
+                            baseMapper.updateById(existStudentApply);
+                        } else {
+                            baseMapper.insert(studentApply);
+                        }
+                        insertApplyList.add(studentApply);
+
+                        studentApplyLock.unlock();
+                        num++;
+                        if (student.getApplyNumber() - (studentApplyList.size() + 1) == 0) {
+                            iterator.remove();
+                            student.setApplyFinished(true);
+                            this.studentService.updateById(student);
+                        }
+
+                        ApplyRecordCacheBean bean = new ApplyRecordCacheBean();
+                        bean.setStudentId(studentApply.getStudentId());
+                        bean.setExamSiteId(studentApply.getExamSiteId());
+                        bean.setTimePeriodId(studentApply.getTimePeriodId());
+                        bean.setCancel(Boolean.FALSE);
+                        bean.setOperateId(userId);
+                        bean.setOperateTime(System.currentTimeMillis());
+                        cacheService.saveStudentApplyRecord(bean);
+                        cacheService.pushStudentApplyRecordQueue(bean);
+                        cacheService.increaseApplyFinishCount(studentApply.getExamSiteId(),
+                                studentApply.getTimePeriodId());
+                    }
                 }
-                num++;
-                if (student.getApplyNumber() - (studentApplyList.size() + 1) == 0) {
-                    iterator.remove();
-                    student.setApplyFinished(true);
-                    this.studentService.updateById(student);
+            } catch (Exception e) {
+                log.error("自动安排预约失败,错误信息:" + e.getMessage());
+                throw new StatusException("自动安排预约失败,请稍后再试!");
+            } finally {
+                try {
+                    studentApplyLock.unlock();
+                } catch (Exception e) {
+                    log.warn(e.getMessage());
                 }
             }
+
         }
         return insertApplyList;
     }
 
+    private StudentApplyEntity findStudentApply(StudentApplyEntity studentApply) {
+        LambdaQueryWrapper<StudentApplyEntity> lm = new LambdaQueryWrapper<>();
+        lm.eq(StudentApplyEntity::getExamSiteId, studentApply.getExamSiteId());
+        lm.eq(StudentApplyEntity::getTimePeriodId, studentApply.getTimePeriodId());
+        lm.eq(StudentApplyEntity::getStudentId, studentApply.getStudentId());
+        return baseMapper.selectOne(lm);
+    }
+
     private boolean haveApplySameTimePeriod(Long siteId, Long timeId, Long studentId) {
         LambdaQueryWrapper<StudentApplyEntity> wrapper = new LambdaQueryWrapper<>();
         wrapper.eq(StudentApplyEntity::getExamSiteId, siteId);
@@ -625,8 +727,7 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
         wrapper.eq(StudentApplyEntity::getExamSiteId, siteId);
         wrapper.eq(StudentApplyEntity::getTimePeriodId, timeId);
         wrapper.eq(StudentApplyEntity::getCancel, Boolean.FALSE);
-        List<StudentApplyEntity> haveAplyList = baseMapper.selectList(wrapper);
-        return haveAplyList == null ? 0 : haveAplyList.size();
+        return baseMapper.selectCount(wrapper);
     }
 
     private void checkAfterOpenTime() {
@@ -646,8 +747,14 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
             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 haveApplyNum = 0;
+            for (ExamSiteEntity site : siteList) {
+                haveApplyNum += cacheService.getApplyTotalCount(site.getId());
+            }
+            if (haveApplyNum == 0) {
+                haveApplyNum = getBaseMapper().getHaveApplyCount(
+                        siteList.stream().map(site -> site.getId()).collect(Collectors.toList()), Boolean.FALSE);
+            }
             // 未预约的数量
             Integer noApplyNum = getNoApplyNum(map.get(key));
             if (noApplyNum > total - haveApplyNum) {
@@ -664,8 +771,9 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
             if (student.getApplyNumber().intValue() == 1) {
                 noApplyNum++;
             } else if (student.getApplyNumber().intValue() > 1) {
-                noApplyNum = noApplyNum
-                        + (student.getApplyNumber() - listStudentApply(student.getId(), Boolean.FALSE).size());
+                // listStudentApply(student.getId(), Boolean.FALSE).size()
+                int haveApplyNum = cacheService.getStudentApplyFinishCount(student.getId());
+                noApplyNum = noApplyNum + (student.getApplyNumber() - haveApplyNum);
             }
         }
         return noApplyNum;
@@ -904,46 +1012,43 @@ public class StudentApplyServiceImpl extends ServiceImpl<StudentApplyDao, Studen
         if (taskId != null) {
             task = applyTaskService.getById(taskId);
         } else {
-            task = getApplyTask();
+            LambdaQueryWrapper<ApplyTaskEntity> wrapper = new LambdaQueryWrapper<ApplyTaskEntity>()
+                    .eq(ApplyTaskEntity::getEnable, Boolean.TRUE);
+            task = applyTaskService.getOne(wrapper);
         }
+        if (task == null) {
+            log.warn("当前没有开启的任务");
+            return signInList;
+        }
+
         List<TimePeriodEntity> timePeriodList = listTimePeroid(task.getId());
         if (timePeriodList.isEmpty()) {
-            throw new StatusException("未配置考试时段");
+            log.warn("未配置考试时段");
+            return signInList;
         }
-        TimePeriodEntity time = timePeriodList.get(0);
-        List<TimePeriodEntity> noCancelTimePeroidList = listNoCancelApplyTimePeroid(timePeriodList,
-                task.getAllowApplyCancelDays());
-        if (noCancelTimePeroidList.isEmpty()) {
-            throw new StatusException("未到可以取消预约的时间");
+        Long startTime = timePeriodList.get(0).getStartTime();
+        Long endTime = timePeriodList.get(timePeriodList.size() - 1).getEndTime();
+
+        String todayStr = DateUtil.formatShortSplitDateString(new Date());
+        Long longToday = DateUtil.getLongTimeByDate(todayStr + " 00:00:00");
+        Date today = new Date(longToday);
+        if (longToday >= startTime && longToday <= endTime) {
+            SignInVO vo = new SignInVO();
+            vo.setExamDate(longToday);
+            signInList.add(vo);
         }
-        LinkedHashMap<LocalDate, LocalDate> map = groupTimestampsByDay(noCancelTimePeroidList);
-        long between = ChronoUnit.DAYS.between(LocalDate.now(), map.entrySet().iterator().next().getKey());
-        for (long i = 0; i < between; i++) {
-            LocalDate day = LocalDate.now().plusDays(i);
-            long epochMilli = day.plusDays(1).atStartOfDay(ZoneId.systemDefault()).minusSeconds(1).toInstant()
-                    .toEpochMilli();
-            // 判断是否在考试时段内
-            if (epochMilli >= time.getStartTime()) {
-                map.put(day, day);
+
+        for (int i = 1; i <= task.getAllowApplyCancelDays().intValue(); i++) {
+            Date otherDay = DateUtil.addValues(today, Calendar.DAY_OF_MONTH, i);
+            Long longOtherDay = DateUtil.getLongTimeByDate(DateUtil.formatShortSplitDateString(otherDay) + " 00:00:00");
+            if (longOtherDay >= startTime && longOtherDay <= endTime) {
+                SignInVO vo = new SignInVO();
+                vo.setExamDate(longToday);
+                signInList.add(vo);
             }
         }
-        for (Entry<LocalDate, LocalDate> entry : map.entrySet()) {
-            SignInVO signIn = new SignInVO();
-            signIn.setExamDate(entry.getKey().atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli());
-            signInList.add(signIn);
-        }
         Collections.sort(signInList, Comparator.comparing(SignInVO::getExamDate));
         return signInList;
     }
 
-    private LinkedHashMap<LocalDate, LocalDate> groupTimestampsByDay(List<TimePeriodEntity> timeList) {
-        LinkedHashMap<LocalDate, LocalDate> map = new LinkedHashMap<>();
-        for (TimePeriodEntity time : timeList) {
-            Instant instant = Instant.ofEpochMilli(time.getStartTime());
-            LocalDate date = instant.atZone(ZoneId.systemDefault()).toLocalDate();
-            map.putIfAbsent(date, date);
-        }
-        return map;
-    }
-
 }

+ 3 - 15
src/main/java/com/qmth/exam/reserve/service/impl/StudentImportAsyncServiceImpl.java

@@ -131,13 +131,10 @@ public class StudentImportAsyncServiceImpl implements StudentImportAsyncService
             updateStudentImportTask(task, ImportStatus.FAILURE.toString(), failRecords);
             return;
         }
-        List<StudentEntity> toAddStudentList = new ArrayList<>();
         for (int i = 0; i < studentList.size(); i++) {
             StudentEntity studentEntity = studentList.get(i);
             try {
-                StudentEntity student = updateStudent(studentEntity);
-                if (student != null)
-                    toAddStudentList.add(student);
+                saveStudent(studentEntity);
             } catch (StatusException e) {
                 failRecords.add(newError(i + 1, e.getMessage()));
             } catch (Exception e) {
@@ -147,14 +144,6 @@ public class StudentImportAsyncServiceImpl implements StudentImportAsyncService
                 return;
             }
         }
-        // 批量写入
-        try {
-            studentService.saveBatch(toAddStudentList);
-        } catch (Exception e) {
-            log.error("导入异常", e);
-            updateStudentImportTask(task, ImportStatus.FAILURE.toString(), failRecords);
-            return;
-        }
         updateStudentImportTask(task, ImportStatus.SUCCESS.toString(), failRecords);
     }
 
@@ -165,7 +154,7 @@ public class StudentImportAsyncServiceImpl implements StudentImportAsyncService
         importTaskService.saveOrUpdate(task);
     }
 
-    private StudentEntity updateStudent(StudentEntity studentEntity) {
+    private void saveStudent(StudentEntity studentEntity) {
         LambdaQueryWrapper<StudentEntity> wrapper = new LambdaQueryWrapper<StudentEntity>()
                 .eq(StudentEntity::getStudentCode, studentEntity.getStudentCode());
         StudentEntity existStudent = studentService.getOne(wrapper);
@@ -179,9 +168,8 @@ public class StudentImportAsyncServiceImpl implements StudentImportAsyncService
             cacheService.clearStudentApplyNumberCache(existStudent.getId());
         } else {
             studentEntity.setApplyFinished(Boolean.FALSE);
-            return studentEntity;
+            studentService.save(studentEntity);
         }
-        return null;
     }
 
     private String trimAndNullIfBlank(String s) {

+ 5 - 1
src/main/java/com/qmth/exam/reserve/util/DateUtil.java

@@ -93,7 +93,7 @@ public class DateUtil {
         // Date date = new Date(1715749200000l);
         // String result = format(date, "yyyy-MM-dd HH:mm:ss");
         // System.out.println(result);
-        System.out.println(getLongDateByLongTime(1713888000000l));
+        System.out.println(getLongDateByLongTime(1714093200000L));
     }
 
     public static Date addValues(int filed, int value) {
@@ -129,6 +129,10 @@ public class DateUtil {
         return formatShortString(date, ShortDateStringWithoutSplit);
     }
 
+    public static String formatShortSplitDateString(Date date) {
+        return formatShortString(date, ShortDateString);
+    }
+
     public static Date parse(String source, String pattern) {
         if (StringUtils.isEmpty(pattern))
             pattern = LongDateString;

+ 1 - 1
src/main/resources/application-test.properties

@@ -34,7 +34,7 @@ com.qmth.redis.db=16
 # ********** file config **********
 #
 com.qmth.fss.config=/home/admin/project/exam-reserve/static
-com.qmth.fss.server=https://qmth-test.oss-cn-shenzhen.aliyuncs.com/apply
+com.qmth.fss.server=http://192.168.10.83:8980/files/apply
 #
 # ********** sys config **********
 #