haogh 1 vuosi sitten
vanhempi
commit
1fa05aa1d1

+ 21 - 0
src/main/java/com/qmth/exam/reserve/bean/stdapply/AgentAndTimeVO.java

@@ -0,0 +1,21 @@
+package com.qmth.exam.reserve.bean.stdapply;
+
+import com.qmth.exam.reserve.bean.IModel;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AgentAndTimeVO implements IModel {
+
+    private static final long serialVersionUID = -3009183043042947269L;
+
+    @ApiModelProperty("预约的考点")
+    private Long agentId;
+
+    @ApiModelProperty("预约的时段")
+    private Long timePeriodId;
+
+}

+ 23 - 0
src/main/java/com/qmth/exam/reserve/bean/stdapply/StdImportVO.java

@@ -0,0 +1,23 @@
+package com.qmth.exam.reserve.bean.stdapply;
+
+import java.util.List;
+
+import com.qmth.exam.reserve.bean.IModel;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class StdImportVO implements IModel {
+
+    private static final long serialVersionUID = 4346725022580732100L;
+
+    @ApiModelProperty("考生ID")
+    private Long studentId;
+
+    @ApiModelProperty("考生预约的考点和时段")
+    private List<AgentAndTimeVO> agentTimeList;
+
+}

+ 33 - 8
src/main/java/com/qmth/exam/reserve/controller/admin/StudentApplyControl.java → src/main/java/com/qmth/exam/reserve/controller/admin/StudentApplyController.java

@@ -1,6 +1,12 @@
 package com.qmth.exam.reserve.controller.admin;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -10,9 +16,11 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
 
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.boot.core.collection.PageResult;
+import com.qmth.boot.core.exception.StatusException;
 import com.qmth.exam.reserve.bean.login.LoginUser;
 import com.qmth.exam.reserve.bean.stdapply.CategoryVO;
 import com.qmth.exam.reserve.bean.stdapply.StdApplyReq;
@@ -22,6 +30,7 @@ import com.qmth.exam.reserve.service.ApplyTaskService;
 import com.qmth.exam.reserve.service.CategoryService;
 import com.qmth.exam.reserve.service.ExamSiteService;
 import com.qmth.exam.reserve.service.StudentApplyService;
+import com.qmth.exam.reserve.util.ResourceUtil;
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -31,7 +40,7 @@ import io.swagger.annotations.ApiParam;
 @Api(tags = "考生预约明细相关接口")
 @RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/apply")
 @Aac(strict = false, auth = false)
-public class StudentApplyControl extends BaseController {
+public class StudentApplyController extends BaseController {
 
     @Autowired
     private StudentApplyService studentApplyService;
@@ -73,19 +82,35 @@ public class StudentApplyControl extends BaseController {
     @ApiOperation(value = "取消预约")
     @PostMapping(value = "/std/cancel")
     public void cancel(@ApiParam("预约结果ID") @RequestParam Long id) {
-        // TODO 在可取消预约范围内
+        LoginUser user = this.curLoginUser();
+        studentApplyService.cancel(user, id);
     }
 
     @ApiOperation(value = "导入预考模版下载")
-    @PostMapping(value = "/std/preexam/template/download")
-    public void download() {
-        // TODO
+    @PostMapping(value = "/imp/template")
+    public void download(HttpServletResponse response) {
+        exportFile("导入预考模板.xlsx", ResourceUtil.getStream("templates/preExamImport.xlsx"));
     }
 
     @ApiOperation(value = "导入预考")
-    @PostMapping(value = "/std/upload")
-    public void upload(MultipartFile file, @ApiParam("教学点ID") @RequestParam Long teachingId) {
-        // TODO
+    @PostMapping(value = "/import")
+    public Map<String, Object> importPreExamStd(@ApiParam("教学点ID") @RequestParam Long teachingId,
+            @RequestParam MultipartFile file) {
+        /*
+         * LoginUser user = this.curLoginUser(); if
+         * (!Role.TEACHING.equals(user.getRole())) { throw new StatusException("没有权限");
+         * }
+         */
+        List<Map<String, Object>> failRecords = new ArrayList<Map<String, Object>>();
+        try {
+            failRecords = studentApplyService.importPreExam(null, teachingId, file.getInputStream());
+        } catch (IOException e) {
+            throw new StatusException("文件读取出错", e);
+        }
+        Map<String, Object> map = new HashMap<>();
+        map.put("hasError", CollectionUtils.isNotEmpty(failRecords));
+        map.put("failRecords", failRecords);
+        return map;
     }
 
     @ApiOperation(value = "一键自动分配")

+ 3 - 3
src/main/java/com/qmth/exam/reserve/controller/admin/StudentImpControl.java → src/main/java/com/qmth/exam/reserve/controller/admin/StudentImportTaskController.java

@@ -9,7 +9,7 @@ import org.springframework.web.multipart.MultipartFile;
 import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.exam.reserve.controller.BaseController;
-import com.qmth.exam.reserve.service.StudentImpService;
+import com.qmth.exam.reserve.service.StudentImportTaskService;
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -18,10 +18,10 @@ import io.swagger.annotations.ApiOperation;
 @Api(tags = "考生信息导入相关接口")
 @RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + "/admin/std")
 @Aac(strict = false, auth = false)
-public class StudentImpControl extends BaseController {
+public class StudentImportTaskController extends BaseController {
 
     @Autowired
-    private StudentImpService studentImpService;
+    private StudentImportTaskService studentImportService;
 
     @ApiOperation(value = "考生信息导入")
     @PostMapping(value = "/upload")

+ 7 - 6
src/main/java/com/qmth/exam/reserve/enums/CategoryLevel.java

@@ -7,17 +7,18 @@ import lombok.Getter;
 @AllArgsConstructor
 public enum CategoryLevel {
 
-    FIRST("第一层级"),
+    SCHOOL(1, "第一层级"),
 
-    SECOND("第二层级"),
+    CITY(2, "第二层级"),
 
-    THIRD("第三层级");
+    TEACHING(3, "第三层级");
 
-    private String title;
+    private Integer value;
+    private String name;
 
-    public static CategoryLevel getByTitle(String title) {
+    public static CategoryLevel getByName(String name) {
         for (CategoryLevel r : CategoryLevel.values()) {
-            if (r.getTitle().equals(title)) {
+            if (r.getName().equals(name)) {
                 return r;
             }
         }

+ 22 - 0
src/main/java/com/qmth/exam/reserve/enums/EventType.java

@@ -0,0 +1,22 @@
+package com.qmth.exam.reserve.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum EventType {
+
+    CANCEL("取消预约");
+
+    private String name;
+
+    public static EventType getByName(String name) {
+        for (EventType r : EventType.values()) {
+            if (r.getName().equals(name)) {
+                return r;
+            }
+        }
+        return null;
+    }
+}

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

@@ -1,7 +1,12 @@
 package com.qmth.exam.reserve.service;
 
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.boot.core.collection.PageResult;
+import com.qmth.exam.reserve.bean.login.LoginUser;
 import com.qmth.exam.reserve.bean.stdapply.StdApplyReq;
 import com.qmth.exam.reserve.bean.stdapply.StdApplyVO;
 import com.qmth.exam.reserve.entity.StudentApplyEntity;
@@ -10,4 +15,8 @@ public interface StudentApplyService extends IService<StudentApplyEntity> {
 
     PageResult<StdApplyVO> page(StdApplyReq req);
 
+    void cancel(LoginUser user, Long id);
+
+    List<Map<String, Object>> importPreExam(LoginUser user, Long teachingId, InputStream inputStream);
+
 }

+ 0 - 8
src/main/java/com/qmth/exam/reserve/service/StudentImpService.java

@@ -1,8 +0,0 @@
-package com.qmth.exam.reserve.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.qmth.exam.reserve.entity.StudentEntity;
-
-public interface StudentImpService extends IService<StudentEntity> {
-
-}

+ 8 - 0
src/main/java/com/qmth/exam/reserve/service/StudentImportTaskService.java

@@ -0,0 +1,8 @@
+package com.qmth.exam.reserve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.exam.reserve.entity.StudentImportTaskEntity;
+
+public interface StudentImportTaskService extends IService<StudentImportTaskEntity> {
+
+}

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

@@ -28,7 +28,7 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity
         // 学校管理员
         if (user.getRole().equals(Role.ADMIN)) {
             lw.eq(CategoryEntity::getEnable, Boolean.TRUE);
-            lw.eq(CategoryEntity::getLevel, CategoryLevel.THIRD.ordinal() + 1);
+            lw.eq(CategoryEntity::getLevel, CategoryLevel.TEACHING.getValue());
             categoryList = this.getBaseMapper().selectList(wrapper);
         } else if (user.getRole().equals(Role.TEACHING)) { // 教学点管理员
             lw.eq(CategoryEntity::getId, user.getCategoryId());

+ 364 - 2
src/main/java/com/qmth/exam/reserve/service/impl/StudentApplyServiceImp.java

@@ -1,22 +1,81 @@
 package com.qmth.exam.reserve.service.impl;
 
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+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.core.toolkit.StringUtils;
 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.StdApplyReq;
 import com.qmth.exam.reserve.bean.stdapply.StdApplyVO;
+import com.qmth.exam.reserve.bean.stdapply.StdImportVO;
+import com.qmth.exam.reserve.dao.ApplyTaskDao;
+import com.qmth.exam.reserve.dao.OperateLogDao;
 import com.qmth.exam.reserve.dao.StudentApplyDao;
+import com.qmth.exam.reserve.dao.TimePeriodDao;
+import com.qmth.exam.reserve.entity.ApplyTaskEntity;
+import com.qmth.exam.reserve.entity.CategoryEntity;
+import com.qmth.exam.reserve.entity.ExamSiteEntity;
+import com.qmth.exam.reserve.entity.OperateLogEntity;
 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.EventType;
+import com.qmth.exam.reserve.service.CategoryService;
+import com.qmth.exam.reserve.service.ExamSiteService;
 import com.qmth.exam.reserve.service.StudentApplyService;
+import com.qmth.exam.reserve.service.StudentService;
+import com.qmth.exam.reserve.util.DateUtil;
+import com.qmth.exam.reserve.util.JsonHelper;
 import com.qmth.exam.reserve.util.PageUtil;
 
 @Service
 public class StudentApplyServiceImp extends ServiceImpl<StudentApplyDao, StudentApplyEntity>
         implements StudentApplyService {
 
+    private static final String[] EXCEL_HEADER = new String[] { "学号", "姓名", "证件号", "所属教学点", "预约考点1", "预约时段1", "预约考点2",
+            "预约时段2", "预约考点3", "预约时段3", "预约考点4", "预约时段4" };
+
+    @Autowired
+    private TimePeriodDao timePeriodDao;
+
+    @Autowired
+    private ApplyTaskDao applyTaskDao;
+
+    @Autowired
+    private OperateLogDao operateLogDao;
+
+    @Autowired
+    private CategoryService categoryService;
+
+    @Autowired
+    private StudentService studentService;
+
+    @Autowired
+    private ExamSiteService examSiteService;
+
     @Override
     public PageResult<StdApplyVO> page(StdApplyReq req) {
         IPage<StdApplyVO> iPage = this.baseMapper.page(new Page<StdApplyVO>(req.getPageNumber(), req.getPageSize()),
@@ -24,8 +83,311 @@ public class StudentApplyServiceImp extends ServiceImpl<StudentApplyDao, Student
         return PageUtil.of(iPage);
     }
 
-    public static void main(String[] args) {
-        System.out.println(System.currentTimeMillis());
+    @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 = this.timePeriodDao.selectById(studentApply.getTimePeriodId());
+        if (timePeroid == null)
+            throw new StatusException("考试时段不存在,请检查考试时段数据!");
+        LambdaQueryWrapper<ApplyTaskEntity> wrapper = new LambdaQueryWrapper<ApplyTaskEntity>()
+                .eq(ApplyTaskEntity::getEnable, Boolean.TRUE);
+        ApplyTaskEntity task = applyTaskDao.selectOne(wrapper);
+        Date applyDate = DateUtil.parse(DateUtil.getShortDateByLongTime(timePeroid.getStartTime()), "yyyy-MM-dd");
+        Date canCancelDay = DateUtil.addValues(applyDate, 5, -task.getAllowApplyCancelDays());
+        if (new Date().after(canCancelDay))
+            throw new StatusException("可取消时间已过,无法取消!");
+        studentApply.setCancel(Boolean.TRUE);
+        this.baseMapper.updateById(studentApply);
+        // TODO redis更新:该时段redis已预约的数量减1
+
+        // 写入日志
+        OperateLogEntity log = new OperateLogEntity();
+        log.setCreateTime(System.currentTimeMillis());
+        log.setUpdateTime(System.currentTimeMillis());
+        log.setOperateId(user.getId());
+        log.setEventType(EventType.CANCEL.toString());
+        log.setContent(JsonHelper.toJson(studentApply));
+        operateLogDao.insert(log);
+    }
+
+    @Transactional
+    @Override
+    public List<Map<String, Object>> importPreExam(LoginUser user, Long teachingId, InputStream inputStream) {
+        checkInTime();
+        List<DataMap> 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<Map<String, Object>> failRecords = new ArrayList<Map<String, Object>>();
+        Map<String, Long> teachingCache = getTeachingCache();
+        Map<String, Long> agentCache = getAgentCache(teachingId);
+        Map<String, Long> timeCache = getTimePeriodCache();
+        List<StdImportVO> applyList = new ArrayList<>();
+        AgentAndTimeVO agentTime = new AgentAndTimeVO();
+        for (int i = 0; i < lineList.size(); i++) {
+            List<AgentAndTimeVO> agentTimeList = new ArrayList<>();
+            DataMap line = lineList.get(i);
+            StdImportVO apply = new StdImportVO();
+            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++) {
+            StdImportVO vo = applyList.get(i);
+            try {
+                saveStdApply(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();
+        }
+        // TODO 更新redis
+        return failRecords;
+
+    }
+
+    private void checkInTime() {
+        LambdaQueryWrapper<ApplyTaskEntity> wrapper = new LambdaQueryWrapper<ApplyTaskEntity>()
+                .eq(ApplyTaskEntity::getEnable, Boolean.TRUE);
+        ApplyTaskEntity task = applyTaskDao.selectOne(wrapper);
+        Date start = DateUtil.parse(DateUtil.getLongDateByLongTime(task.getOpenApplyStartTime()), null);
+        // DateUtil.isBetwwen(start, end)
+    }
+
+    private void saveStdApply(StdImportVO vo) {
+        List<AgentAndTimeVO> agentTimeList = vo.getAgentTimeList();
+        LambdaQueryWrapper<StudentApplyEntity> lm = new LambdaQueryWrapper<>();
+        lm.eq(StudentApplyEntity::getStudentId, vo.getStudentId());
+        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 Long checkTimePeriod(String timePeriod, Map<String, Long> 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<String, Long> getTimePeriodCache() {
+        Map<String, Long> map = new HashMap<>();
+        LambdaQueryWrapper<TimePeriodEntity> lm = new LambdaQueryWrapper<>();
+        List<TimePeriodEntity> timeList = timePeriodDao.selectList(lm);
+        for (TimePeriodEntity time : timeList) {
+            map.put(time.getStartTime() + "-" + time.getEndTime(), time.getId());
+        }
+        return map;
+    }
+
+    private Map<String, Long> getTeachingCache() {
+        LambdaQueryWrapper<CategoryEntity> lm = new LambdaQueryWrapper<>();
+        lm.eq(CategoryEntity::getEnable, Boolean.TRUE);
+        lm.eq(CategoryEntity::getLevel, CategoryLevel.TEACHING.getValue());
+        List<CategoryEntity> categoryList = categoryService.list(lm);
+        return categoryList.stream().collect(Collectors.toMap(CategoryEntity::getName, CategoryEntity::getId));
+    }
+
+    private Map<String, Long> getAgentCache(Long categoryId) {
+        LambdaQueryWrapper<ExamSiteEntity> lm = new LambdaQueryWrapper<>();
+        lm.eq(ExamSiteEntity::getEnable, Boolean.TRUE);
+        lm.eq(ExamSiteEntity::getCategoryId, categoryId);
+        List<ExamSiteEntity> categoryList = examSiteService.list(lm);
+        return categoryList.stream().collect(Collectors.toMap(ExamSiteEntity::getName, ExamSiteEntity::getId));
+    }
+
+    private StudentEntity checkStd(String studentCode, String name, String identityNumber) {
+        LambdaQueryWrapper<StudentEntity> 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<String, Object> newError(int lineNum, String msg) {
+        Map<String, Object> 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();
     }
 
 }

+ 14 - 0
src/main/java/com/qmth/exam/reserve/service/impl/StudentImportTaskServiceImpl.java

@@ -0,0 +1,14 @@
+package com.qmth.exam.reserve.service.impl;
+
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.exam.reserve.dao.StudentImportTaskDao;
+import com.qmth.exam.reserve.entity.StudentImportTaskEntity;
+import com.qmth.exam.reserve.service.StudentImportTaskService;
+
+@Service
+public class StudentImportTaskServiceImpl extends ServiceImpl<StudentImportTaskDao, StudentImportTaskEntity>
+        implements StudentImportTaskService {
+
+}

+ 0 - 13
src/main/java/com/qmth/exam/reserve/service/impl/StudentInfoServiceImpl.java

@@ -1,13 +0,0 @@
-package com.qmth.exam.reserve.service.impl;
-
-import org.springframework.stereotype.Service;
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.qmth.exam.reserve.dao.StudentDao;
-import com.qmth.exam.reserve.entity.StudentEntity;
-import com.qmth.exam.reserve.service.StudentImpService;
-
-@Service
-public class StudentInfoServiceImpl extends ServiceImpl<StudentDao, StudentEntity> implements StudentImpService {
-
-}

+ 156 - 0
src/main/java/com/qmth/exam/reserve/util/DateUtil.java

@@ -0,0 +1,156 @@
+package com.qmth.exam.reserve.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.qmth.boot.core.exception.StatusException;
+
+public class DateUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(DateUtil.class);
+
+    public final static String LongDateString = "yyyy-MM-dd HH:mm:ss";
+    public final static String LongZHDateString = "yyyy年MM月dd日 HH:mm:ss";
+    public final static String ShortDateString = "yyyy-MM-dd";
+    public final static String ShortDateStringWithoutSplit = "yyyyMMdd";
+    public final static String ShortTimeString = "HH:mm:ss";
+    public final static String ShortTimeStringWithoutSplit = "HHmmss";
+    public final static String LongDateStringWithoutSplit = "yyyyMMddHHmmss";
+    public final static String MillisecondDateString = "yyyyMMddHHmmssSSS";
+    public final static String HourMinuteString = "HH:mm";
+
+    private static Map<String, ThreadLocal<SimpleDateFormat>> SimpleDateForamtThreadLocalMap = new HashMap<String, ThreadLocal<SimpleDateFormat>>();
+
+    static {
+        // 初始化常见的日期类型
+        synchronized (DateUtil.class) {
+            SimpleDateForamtThreadLocalMap.put(ShortDateString, InitThreadLocal(ShortDateString));
+            SimpleDateForamtThreadLocalMap.put(ShortDateStringWithoutSplit,
+                    InitThreadLocal(ShortDateStringWithoutSplit));
+            SimpleDateForamtThreadLocalMap.put(LongDateString, InitThreadLocal(LongDateString));
+            SimpleDateForamtThreadLocalMap.put(LongDateStringWithoutSplit, InitThreadLocal(LongDateStringWithoutSplit));
+            SimpleDateForamtThreadLocalMap.put(MillisecondDateString, InitThreadLocal(MillisecondDateString));
+            SimpleDateForamtThreadLocalMap.put(ShortTimeString, InitThreadLocal(ShortTimeString));
+            SimpleDateForamtThreadLocalMap.put(ShortTimeStringWithoutSplit,
+                    InitThreadLocal(ShortTimeStringWithoutSplit));
+        }
+    }
+
+    public static String getLongDateByLongTime(Long time) {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(LongDateString);
+        Date date = new Date(time);
+        return simpleDateFormat.format(date);
+    }
+
+    public static String getShortDateByLongTime(Long time) {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ShortDateString);
+        Date date = new Date(time);
+        return simpleDateFormat.format(date);
+    }
+
+    public static Long getLongTimeByDate(String dateStr) {
+        SimpleDateFormat sdf = new SimpleDateFormat(LongDateString);
+        try {
+            Date date = sdf.parse(dateStr);
+            Long timestamp = date.getTime();
+            return timestamp;
+        } catch (ParseException e) {
+            log.error(e.getMessage());
+            throw new StatusException("日期转换失败!");
+        }
+    }
+
+    public static Long getLongTimeByZHDate(String dateStr) {
+        SimpleDateFormat sdf = new SimpleDateFormat(LongZHDateString);
+        try {
+            Date date = sdf.parse(dateStr);
+            Long timestamp = date.getTime();
+            return timestamp;
+        } catch (ParseException e) {
+            log.error(e.getMessage());
+            throw new StatusException("日期转换失败!");
+        }
+    }
+
+    public static void main(String[] args) {
+        parse("2024-10-01 10:00:00", null);
+    }
+
+    public static Date addValues(int filed, int value) {
+        return addValues(new Date(), filed, value);
+    }
+
+    public static Date addValues(Date date, int filed, int value) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(date);
+        c.add(filed, value);
+        return c.getTime();
+    }
+
+    public static String format(Date date, String pattern) {
+        SimpleDateFormat sdf = getFormatter(pattern);
+        try {
+            return sdf.format(date);
+        } catch (Exception e) {
+
+        }
+        return null;
+    }
+
+    public static Date parse(String source, String pattern) {
+        if (StringUtils.isEmpty(source))
+            return null;
+        SimpleDateFormat sdf = getFormatter(pattern);
+        try {
+            return sdf.parse(source);
+        } catch (Exception e) {
+
+        }
+        return null;
+    }
+
+    public static SimpleDateFormat getFormatter(final String pattern) {
+        ThreadLocal<SimpleDateFormat> tl = SimpleDateForamtThreadLocalMap.get(pattern);
+        if (tl == null) {
+            synchronized (DateUtil.class) {
+                if (tl == null) {
+                    tl = SimpleDateForamtThreadLocalMap.get(pattern);
+                    if (tl == null)
+                        SimpleDateForamtThreadLocalMap.put(pattern, InitThreadLocal(pattern));
+                }
+            }
+            tl = SimpleDateForamtThreadLocalMap.get(pattern);
+        }
+        return tl.get();
+    }
+
+    public static boolean isBetwwen(Date start, Date end) {
+        return isBetwwen(new Date(), start, end);
+    }
+
+    public static boolean isBetwwen(Date now, Date start, Date end) {
+        if (now.after(start) && now.before(end))
+            return true;
+        else
+            return false;
+    }
+
+    public static ThreadLocal<SimpleDateFormat> InitThreadLocal(final String pattern) {
+        ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
+            @Override
+            protected SimpleDateFormat initialValue() {
+                return new SimpleDateFormat(pattern);
+            }
+        };
+        return sdf;
+    }
+
+}

+ 89 - 0
src/main/java/com/qmth/exam/reserve/util/FileUtil.java

@@ -0,0 +1,89 @@
+package com.qmth.exam.reserve.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import com.qmth.boot.core.exception.StatusException;
+
+public class FileUtil {
+    public static String readFileContent(InputStream in) {
+        StringBuilder content = new StringBuilder();
+        InputStreamReader streamReader = null;
+        BufferedReader bufferedReader = null;
+        try {
+            String encoding = "UTF-8";
+            streamReader = new InputStreamReader(in, encoding);
+            bufferedReader = new BufferedReader(streamReader);
+            String line;
+            while ((line = bufferedReader.readLine()) != null) {
+                content.append(line);
+            }
+            return content.toString();
+        } catch (IOException e) {
+            throw new StatusException("出错", e);
+        } finally {
+            if (streamReader != null) {
+                try {
+                    streamReader.close();
+                } catch (IOException e) {
+                }
+            }
+            if (bufferedReader != null) {
+                try {
+                    bufferedReader.close();
+                } catch (IOException e) {
+                }
+            }
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * 获得文件的byte数组
+     * 
+     * @param filePath
+     * @return
+     * @throws IOException
+     */
+    public static byte[] getBytes(String filePath) throws IOException {
+        File file = new File(filePath);
+        if (!file.exists()) {
+            throw new FileNotFoundException(filePath);
+        }
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(((int) file.length()));
+        BufferedInputStream in = null;
+        try {
+            in = new BufferedInputStream(new FileInputStream(file));
+            int bufSize = 1024;
+            byte[] buffer = new byte[bufSize];
+            int len = 0;
+            while (-1 != (len = in.read(buffer, 0, bufSize))) {
+                bos.write(buffer, 0, len);
+            }
+            return bos.toByteArray();
+        } finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            bos.close();
+        }
+    }
+
+}

+ 39 - 0
src/main/java/com/qmth/exam/reserve/util/ResourceUtil.java

@@ -0,0 +1,39 @@
+package com.qmth.exam.reserve.util;
+
+import java.io.InputStream;
+import java.net.URL;
+
+public class ResourceUtil {
+    public static URL getUrl(String path) {
+        try {
+            ClassLoader classLoader = ResourceUtil.class.getClassLoader();
+
+            URL url = classLoader.getResource(path);
+            return url;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static InputStream getStream(String path) {
+        try {
+            ClassLoader classLoader = ResourceUtil.class.getClassLoader();
+
+            URL url = classLoader.getResource(path);
+            return url.openStream();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String getContent(String path) {
+        try {
+            ClassLoader classLoader = ResourceUtil.class.getClassLoader();
+
+            URL url = classLoader.getResource(path);
+            return FileUtil.readFileContent(url.openStream());
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

BIN
src/main/resources/templates/preExamImport.xlsx