Ver código fonte

考试批次相关

caozixuan 1 ano atrás
pai
commit
2b1b097a04

+ 2 - 0
install/mysql/init/init.sql

@@ -92,6 +92,7 @@ CREATE TABLE `pm_exam_student`
     `exam_number`  varchar(255) COLLATE utf8_bin NOT NULL,
     `exam_site`    varchar(255) COLLATE utf8_bin DEFAULT NULL,
     `exam_room`    varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `exam_unit` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '服务单元',
     PRIMARY KEY (`exam_id`, `sort_no`),
     KEY `IDX_EXAM_STUDENT_001` (`org_id`, `exam_id`),
     KEY `IDX_EXAM_STUDENT_002` (`exam_id`)
@@ -156,6 +157,7 @@ CREATE TABLE `pm_user`
     `name`        varchar(255) COLLATE utf8_bin DEFAULT NULL,
     `enable`      bit(1)                        NOT NULL,
     `password`    varchar(255) COLLATE utf8_bin DEFAULT NULL,
+    `password_count` int NOT NULL DEFAULT '0' COMMENT '密码修改次数',
     `role`        varchar(64) COLLATE utf8_bin  NOT NULL,
     PRIMARY KEY (`id`),
     UNIQUE KEY `IDX_USER_01` (`login_name`)

+ 4 - 1
install/mysql/upgrade/1.1.0.sql

@@ -1,2 +1,5 @@
 ALTER TABLE pm_user
-    ADD COLUMN password_count INT NOT NULL DEFAULT 0 COMMENT '密码修改次数' AFTER password;
+    ADD COLUMN password_count INT NOT NULL DEFAULT 0 COMMENT '密码修改次数' AFTER password;
+
+ALTER TABLE pm_exam_student
+    ADD COLUMN exam_unit VARCHAR(255) NULL COMMENT '服务单元' AFTER exam_room;

+ 13 - 0
pom.xml

@@ -128,6 +128,19 @@
 			<artifactId>poi-ooxml-schemas</artifactId>
 			<version>3.17</version>
 		</dependency>
+		<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-core -->
+		<dependency>
+			<groupId>cn.hutool</groupId>
+			<artifactId>hutool-core</artifactId>
+			<version>5.8.22</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j -->
+		<!-- https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j -->
+		<dependency>
+			<groupId>net.lingala.zip4j</groupId>
+			<artifactId>zip4j</artifactId>
+			<version>1.3.2</version>
+		</dependency>
 		<dependency>
 			<groupId>org.quartz-scheduler</groupId>
 			<artifactId>quartz</artifactId>

+ 12 - 4
src/main/java/cn/com/qmth/print/manage/controller/ExamController.java

@@ -9,10 +9,7 @@ import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.boot.api.constant.ApiConstant;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestAttribute;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 /**
  * @Date: 2021/11/16.
@@ -70,4 +67,15 @@ public class ExamController extends BaseController {
         Long userId = getAccessUserId(accessEntity);
         return examService.listByUserId(userId);
     }
+
+    /**
+     * 删除考试批次
+     *
+     * @param accessEntity 鉴权
+     * @param examId       考试id
+     */
+    @RequestMapping(value = "/delete", method = RequestMethod.POST)
+    public void delete(@RequestAttribute PmSession accessEntity, @RequestParam Long examId) {
+        examService.deleteExam(examId);
+    }
 }

+ 1 - 1
src/main/java/cn/com/qmth/print/manage/controller/ExamStudentController.java

@@ -38,7 +38,7 @@ public class ExamStudentController extends BaseController {
      */
     @RequestMapping(value = "/import", method = RequestMethod.POST)
     public Object importFile(@RequestParam Long examId, @RequestParam MultipartFile file) throws IOException {
-        return examStudentService.importStudents(examId, file);
+        return examStudentService.analyzeZipAndImportStudents(examId, file);
     }
 
     /**

+ 1 - 1
src/main/java/cn/com/qmth/print/manage/dto/ExamDTO.java

@@ -8,7 +8,7 @@ import cn.com.qmth.print.manage.utils.excel.ExcelProperty;
  * @Date: 2023-10-16
  */
 public class ExamDTO {
-    @ExcelProperty(index = 1, name = "学校名称", type = 0)
+    @ExcelProperty(index = 1, name = "学校名称", type = 2)
     private String schoolName;
 
     public String getSchoolName() {

+ 178 - 0
src/main/java/cn/com/qmth/print/manage/dto/ExamStudentExportDTO.java

@@ -0,0 +1,178 @@
+package cn.com.qmth.print.manage.dto;
+
+import cn.com.qmth.print.manage.utils.excel.ExcelProperty;
+
+import java.io.Serializable;
+
+/**
+ * @Description: 云阅卷考生导出对象
+ * @Author: CaoZixuan
+ * @Date: 2023-10-19
+ */
+public class ExamStudentExportDTO implements Serializable {
+
+    @ExcelProperty(index = 1, name = "课程代码*", type = 2)
+    private String courseCode;
+
+    @ExcelProperty(index = 2, name = "课程名称*", type = 2)
+    private String courseName;
+
+    @ExcelProperty(index = 3, name = "准考证号*", type = 2)
+    private String examNumber;
+
+    @ExcelProperty(index = 4, name = "学号*", type = 2)
+    private String studentCode;
+
+    @ExcelProperty(index = 5, name = "姓名*", type = 2)
+    private String studentName;
+
+    @ExcelProperty(index = 6, name = "签到表编号", type = 2)
+    private String signCode;
+
+    @ExcelProperty(index = 7, name = "考点信息", type = 2)
+    private String examSite;
+
+    @ExcelProperty(index = 8, name = "考场信息", type = 2)
+    private String examRoom;
+
+    @ExcelProperty(index = 9, name = "考生备注信息", type = 2)
+    private String examStudentRemark;
+
+    @ExcelProperty(index = 10, name = "层次", type = 2)
+    private String level;
+
+    @ExcelProperty(index = 11, name = "专业类型", type = 2)
+    private String major;
+
+    @ExcelProperty(index = 12, name = "学院*", type = 2)
+    private String college;
+
+    @ExcelProperty(index = 13, name = "班级*", type = 2)
+    private String clazz;
+
+    @ExcelProperty(index = 14, name = "任课老师*", type = 2)
+    private String teacher;
+
+    @ExcelProperty(index = 15, name = "科目备注信息", type = 2)
+    private String courseRemark;
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public String getStudentName() {
+        return studentName;
+    }
+
+    public void setStudentName(String studentName) {
+        this.studentName = studentName;
+    }
+
+    public String getSignCode() {
+        return signCode;
+    }
+
+    public void setSignCode(String signCode) {
+        this.signCode = signCode;
+    }
+
+    public String getExamSite() {
+        return examSite;
+    }
+
+    public void setExamSite(String examSite) {
+        this.examSite = examSite;
+    }
+
+    public String getExamRoom() {
+        return examRoom;
+    }
+
+    public void setExamRoom(String examRoom) {
+        this.examRoom = examRoom;
+    }
+
+    public String getExamStudentRemark() {
+        return examStudentRemark;
+    }
+
+    public void setExamStudentRemark(String examStudentRemark) {
+        this.examStudentRemark = examStudentRemark;
+    }
+
+    public String getLevel() {
+        return level;
+    }
+
+    public void setLevel(String level) {
+        this.level = level;
+    }
+
+    public String getMajor() {
+        return major;
+    }
+
+    public void setMajor(String major) {
+        this.major = major;
+    }
+
+    public String getCollege() {
+        return college;
+    }
+
+    public void setCollege(String college) {
+        this.college = college;
+    }
+
+    public String getClazz() {
+        return clazz;
+    }
+
+    public void setClazz(String clazz) {
+        this.clazz = clazz;
+    }
+
+    public String getTeacher() {
+        return teacher;
+    }
+
+    public void setTeacher(String teacher) {
+        this.teacher = teacher;
+    }
+
+    public String getCourseRemark() {
+        return courseRemark;
+    }
+
+    public void setCourseRemark(String courseRemark) {
+        this.courseRemark = courseRemark;
+    }
+}

+ 318 - 0
src/main/java/cn/com/qmth/print/manage/dto/ExamStudentImportDTO.java

@@ -0,0 +1,318 @@
+package cn.com.qmth.print.manage.dto;
+
+import cn.com.qmth.print.manage.utils.excel.ExcelProperty;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * @Description: 考生导入dto
+ * @Author: CaoZixuan
+ * @Date: 2023-10-19
+ */
+public class ExamStudentImportDTO implements Serializable {
+
+    @ExcelProperty(index = 1, name = "总流水", type = 2)
+    private String serialNumber;
+
+    @ExcelProperty(index = 2, name = "考试单元ID", type = 2)
+    private String examUnitId;
+
+    @ExcelProperty(index = 3, name = "考试单元", type = 2)
+    @NotNull
+    private String examUnit;
+
+    @ExcelProperty(index = 4, name = "考点代码", type = 2)
+    private String examPlaceCode;
+
+    @ExcelProperty(index = 5, name = "考点名称", type = 2)
+    @NotNull
+    private String examPlaceName;
+
+    @ExcelProperty(index = 6, name = "报考单位代码", type = 2)
+    private String examAgencyCode;
+
+    @ExcelProperty(index = 7, name = "报考单位名称", type = 2)
+    private String examAgencyName;
+
+    @ExcelProperty(index = 8, name = "姓名", type = 2)
+    @NotNull
+    private String studentName;
+
+    @ExcelProperty(index = 9, name = "考生编号", type = 2)
+    @NotNull
+    private String studentCode;
+
+    @ExcelProperty(index = 10, name = "考生编号后5位", type = 2)
+    private String studentCodeEnd;
+
+    @ExcelProperty(index = 11, name = "科目代码", type = 2)
+    @NotNull
+    private String courseCode;
+
+    @ExcelProperty(index = 12, name = "科目名称", type = 2)
+    @NotNull
+    private String courseName;
+
+    @ExcelProperty(index = 13, name = "考试时间", type = 2)
+    private String examTime;
+
+    @ExcelProperty(index = 14, name = "科目流水号", type = 2)
+    private String courseSerialNumber;
+
+    @ExcelProperty(index = 15, name = "考点流水号", type = 2)
+    private String examPlaceSerialNumber;
+
+    @ExcelProperty(index = 16, name = "准考证号", type = 2)
+    @NotNull
+    private String examNumber;
+
+    @ExcelProperty(index = 17, name = "准考证号1", type = 2)
+    private String examNumber1;
+
+    @ExcelProperty(index = 18, name = "准考证号2", type = 2)
+    private String examNumber2;
+
+    @ExcelProperty(index = 19, name = "准考证号3", type = 2)
+    private String examNumber3;
+
+    @ExcelProperty(index = 20, name = "准考证号4", type = 2)
+    private String examNumber4;
+
+    @ExcelProperty(index = 21, name = "页码流水", type = 2)
+    private String pageSerialNumber;
+
+    @ExcelProperty(index = 22, name = "条码样式码", type = 2)
+    private String barStyleCode;
+
+    @ExcelProperty(index = 23, name = "自定义1", type = 2)
+    private String custom1;
+
+    @ExcelProperty(index = 24, name = "自定义2", type = 2)
+    private String custom2;
+
+    @ExcelProperty(index = 25, name = "自定义3", type = 2)
+    private String custom3;
+
+    @ExcelProperty(index = 26, name = "自定义4", type = 2)
+    private String custom4;
+
+    @ExcelProperty(index = 27, name = "自定义5", type = 2)
+    private String custom5;
+
+    public String getSerialNumber() {
+        return serialNumber;
+    }
+
+    public void setSerialNumber(String serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
+    public String getExamUnitId() {
+        return examUnitId;
+    }
+
+    public void setExamUnitId(String examUnitId) {
+        this.examUnitId = examUnitId;
+    }
+
+    public String getExamUnit() {
+        return examUnit;
+    }
+
+    public void setExamUnit(String examUnit) {
+        this.examUnit = examUnit;
+    }
+
+    public String getExamPlaceCode() {
+        return examPlaceCode;
+    }
+
+    public void setExamPlaceCode(String examPlaceCode) {
+        this.examPlaceCode = examPlaceCode;
+    }
+
+    public String getExamPlaceName() {
+        return examPlaceName;
+    }
+
+    public void setExamPlaceName(String examPlaceName) {
+        this.examPlaceName = examPlaceName;
+    }
+
+    public String getExamAgencyCode() {
+        return examAgencyCode;
+    }
+
+    public void setExamAgencyCode(String examAgencyCode) {
+        this.examAgencyCode = examAgencyCode;
+    }
+
+    public String getExamAgencyName() {
+        return examAgencyName;
+    }
+
+    public void setExamAgencyName(String examAgencyName) {
+        this.examAgencyName = examAgencyName;
+    }
+
+    public String getStudentName() {
+        return studentName;
+    }
+
+    public void setStudentName(String studentName) {
+        this.studentName = studentName;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public String getStudentCodeEnd() {
+        return studentCodeEnd;
+    }
+
+    public void setStudentCodeEnd(String studentCodeEnd) {
+        this.studentCodeEnd = studentCodeEnd;
+    }
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getExamTime() {
+        return examTime;
+    }
+
+    public void setExamTime(String examTime) {
+        this.examTime = examTime;
+    }
+
+    public String getCourseSerialNumber() {
+        return courseSerialNumber;
+    }
+
+    public void setCourseSerialNumber(String courseSerialNumber) {
+        this.courseSerialNumber = courseSerialNumber;
+    }
+
+    public String getExamPlaceSerialNumber() {
+        return examPlaceSerialNumber;
+    }
+
+    public void setExamPlaceSerialNumber(String examPlaceSerialNumber) {
+        this.examPlaceSerialNumber = examPlaceSerialNumber;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getExamNumber1() {
+        return examNumber1;
+    }
+
+    public void setExamNumber1(String examNumber1) {
+        this.examNumber1 = examNumber1;
+    }
+
+    public String getExamNumber2() {
+        return examNumber2;
+    }
+
+    public void setExamNumber2(String examNumber2) {
+        this.examNumber2 = examNumber2;
+    }
+
+    public String getExamNumber3() {
+        return examNumber3;
+    }
+
+    public void setExamNumber3(String examNumber3) {
+        this.examNumber3 = examNumber3;
+    }
+
+    public String getExamNumber4() {
+        return examNumber4;
+    }
+
+    public void setExamNumber4(String examNumber4) {
+        this.examNumber4 = examNumber4;
+    }
+
+    public String getPageSerialNumber() {
+        return pageSerialNumber;
+    }
+
+    public void setPageSerialNumber(String pageSerialNumber) {
+        this.pageSerialNumber = pageSerialNumber;
+    }
+
+    public String getBarStyleCode() {
+        return barStyleCode;
+    }
+
+    public void setBarStyleCode(String barStyleCode) {
+        this.barStyleCode = barStyleCode;
+    }
+
+    public String getCustom1() {
+        return custom1;
+    }
+
+    public void setCustom1(String custom1) {
+        this.custom1 = custom1;
+    }
+
+    public String getCustom2() {
+        return custom2;
+    }
+
+    public void setCustom2(String custom2) {
+        this.custom2 = custom2;
+    }
+
+    public String getCustom3() {
+        return custom3;
+    }
+
+    public void setCustom3(String custom3) {
+        this.custom3 = custom3;
+    }
+
+    public String getCustom4() {
+        return custom4;
+    }
+
+    public void setCustom4(String custom4) {
+        this.custom4 = custom4;
+    }
+
+    public String getCustom5() {
+        return custom5;
+    }
+
+    public void setCustom5(String custom5) {
+        this.custom5 = custom5;
+    }
+}

+ 11 - 0
src/main/java/cn/com/qmth/print/manage/entity/ExamStudentEntity.java

@@ -3,6 +3,7 @@ package cn.com.qmth.print.manage.entity;
 import cn.com.qmth.print.manage.entity.base.AuditingWithoutIdEntity;
 
 import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
 
 @TableName("pm_exam_student")
 public class ExamStudentEntity extends AuditingWithoutIdEntity {
@@ -33,6 +34,9 @@ public class ExamStudentEntity extends AuditingWithoutIdEntity {
      */
     private String examRoom;
 
+    @ApiModelProperty("考试单元")
+    private String examUnit;
+
     public Long getOrgId() {
         return orgId;
     }
@@ -105,4 +109,11 @@ public class ExamStudentEntity extends AuditingWithoutIdEntity {
         this.sortNo = sortNo;
     }
 
+    public String getExamUnit() {
+        return examUnit;
+    }
+
+    public void setExamUnit(String examUnit) {
+        this.examUnit = examUnit;
+    }
 }

+ 5 - 0
src/main/java/cn/com/qmth/print/manage/service/ExamService.java

@@ -31,5 +31,10 @@ public interface ExamService extends IService<ExamEntity> {
      */
     Object importExams(UserEntity requestUser, Long printLeader, MultipartFile file) throws IOException;
 
+    /**
+     * 删除考试批次
+     * @param examId 考试id
+     */
+    void deleteExam(Long examId);
 
 }

+ 7 - 0
src/main/java/cn/com/qmth/print/manage/service/ExamStudentService.java

@@ -23,5 +23,12 @@ public interface ExamStudentService extends IService<ExamStudentEntity> {
 
     Object importStudents(Long examId, MultipartFile file) throws IOException;
 
+    /**
+     * 解析Zip并导入考生
+     * @param examId 考试id
+     * @return 信息
+     */
+    Object analyzeZipAndImportStudents(Long examId, MultipartFile file) throws IOException;
+
     void deleteByExamId(Long examId);
 }

+ 19 - 1
src/main/java/cn/com/qmth/print/manage/service/impl/ExamServiceImpl.java

@@ -231,6 +231,24 @@ public class ExamServiceImpl extends ServiceImpl<ExamDao, ExamEntity> implements
         return excelErrors;
     }
 
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void deleteExam(Long examId) {
+        if (checkRecordService.count(new QueryWrapper<CheckRecordEntity>().lambda()
+                .eq(CheckRecordEntity::getExamId, examId)
+                .ne(CheckRecordEntity::getStatus, RecordStatus.NONE)) > 0) {
+            throw new StatusException("已有校验数据,不可重复导入");
+        }
+        // 删除考试表id
+        this.removeById(examId);
+        // 删除考生表
+        examStudentService.deleteByExamId(examId);
+        // 删除校验记录
+        checkRecordService.deleteByExamId(examId);
+        // 删除中断记录
+        breakRecordService.deleteByExamId(examId);
+    }
+
     /**
      * 拼接导入异常信息
      *
@@ -250,4 +268,4 @@ public class ExamServiceImpl extends ServiceImpl<ExamDao, ExamEntity> implements
         }
         return sj.toString();
     }
-}
+}

+ 77 - 0
src/main/java/cn/com/qmth/print/manage/service/impl/ExamStudentServiceImpl.java

@@ -2,6 +2,7 @@ package cn.com.qmth.print.manage.service.impl;
 
 import cn.com.qmth.print.manage.dao.ExamDao;
 import cn.com.qmth.print.manage.dao.ExamStudentDao;
+import cn.com.qmth.print.manage.dto.ExamStudentImportDTO;
 import cn.com.qmth.print.manage.dto.StudentDTO;
 import cn.com.qmth.print.manage.entity.CheckRecordEntity;
 import cn.com.qmth.print.manage.entity.ExamEntity;
@@ -12,8 +13,10 @@ import cn.com.qmth.print.manage.service.BreakRecordService;
 import cn.com.qmth.print.manage.service.CheckRecordService;
 import cn.com.qmth.print.manage.service.ExamStudentService;
 import cn.com.qmth.print.manage.service.query.ExamStudentQuery;
+import cn.com.qmth.print.manage.utils.Zip4jUtil;
 import cn.com.qmth.print.manage.utils.excel.ExcelError;
 import cn.com.qmth.print.manage.utils.excel.ExcelReader;
+import cn.hutool.core.io.FileUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
@@ -29,6 +32,7 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
+import java.io.File;
 import java.io.IOException;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicLong;
@@ -157,6 +161,72 @@ public class ExamStudentServiceImpl extends ServiceImpl<ExamStudentDao, ExamStud
         return excelErrors;
     }
 
+    @Transactional
+    @Override
+    public Object analyzeZipAndImportStudents(Long examId ,MultipartFile file) throws IOException {
+        String zipPath = "E:\\file\\studentImport2.zip";
+        String dirPath = "E:\\file\\studentImport2";
+//        File zip = new File("E:\\file\\studentImport2.zip");
+//        File zipDir = new File("E:\\file\\studentImport2");
+        Zip4jUtil.unzipEncryptFile(zipPath,dirPath,"qmth!@#");
+//        File zip = new File("E:\\file\\studentImport2.zip");
+        File zipDir = new File("E:\\file\\studentImport2");
+        File[] firstDirArr = zipDir.listFiles();
+        if (Objects.isNull(firstDirArr) || firstDirArr.length != 1) {
+            throw new StatusException("文件解析失败:未找到一级目录");
+        }
+        List<File> studentFileList = Arrays.stream(Objects.requireNonNull(firstDirArr[0].listFiles()))
+                .filter(e -> e.getName().endsWith("xlsx"))
+                .collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(studentFileList)) {
+            throw new StatusException("文件解析失败:未找到导入的excel文件");
+        }
+        if (studentFileList.size() != 1) {
+            throw new StatusException("文件解析失败:存在多个excel文件");
+        }
+        File studentExcel = studentFileList.get(0);
+
+        ExamEntity examEntity = examDao.selectById(examId);
+        List<ExamStudentEntity> studentList = new ArrayList<>();
+        ExcelReader excelReader = new ExcelReader(ExamStudentImportDTO.class);
+        AtomicLong sort = new AtomicLong(1L);
+        List<ExcelError> excelErrors = excelReader.reader(FileUtil.getInputStream(studentExcel), obj -> {
+            try {
+                ExamStudentImportDTO dto = (ExamStudentImportDTO) obj;
+                ExamStudentEntity examStudentEntity = new ExamStudentEntity();
+                examStudentEntity.setExamId(examId);
+                examStudentEntity.setOrgId(examEntity.getOrgId());
+                examStudentEntity.setExamNumber(dto.getExamNumber());
+                examStudentEntity.setStudentCode(dto.getStudentCode());
+                examStudentEntity.setName(dto.getStudentName());
+                examStudentEntity.setCourseCode(dto.getCourseCode().concat("_").concat(dto.getCourseName()));
+                examStudentEntity.setExamSite(dto.getExamPlaceName());
+                examStudentEntity.setSortNo(sort.getAndIncrement());
+                examStudentEntity.setExamUnit(dto.getExamUnit());
+                examStudentEntity.setCreateTime(new Date());
+                examStudentEntity.setUpdateTime(new Date());
+                studentList.add(examStudentEntity);
+                return null;
+            } catch (RuntimeException e) {
+                // 手动回滚
+                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+                ExcelError excelError = new ExcelError();
+                excelError.setExcelErrorType(e.getMessage());
+                return excelError;
+            }
+        });
+
+        String errors = errorsString(excelErrors);
+        if (errors.length() > 0) {
+            throw new StatusException(errors);
+        }
+
+        if (!CollectionUtils.isEmpty(studentList)) {
+            insertData(examEntity, studentList);
+        }
+        return excelErrors;
+    }
+
     @Override
     public void deleteByExamId(Long examId) {
         UpdateWrapper<ExamStudentEntity> updateWrapper = new UpdateWrapper<>();
@@ -166,6 +236,13 @@ public class ExamStudentServiceImpl extends ServiceImpl<ExamStudentDao, ExamStud
 
     @Transactional
     public void insertData(ExamEntity examEntity, List<ExamStudentEntity> studentList) {
+        // 有校验数据不能删除
+        if (checkRecordService.count(new QueryWrapper<CheckRecordEntity>().lambda()
+                .eq(CheckRecordEntity::getExamId,examEntity.getId())
+                .ne(CheckRecordEntity::getStatus,RecordStatus.NONE)) > 0){
+            throw new StatusException("已有校验数据,不可重复导入");
+        }
+
         // 删除考生表
         this.deleteByExamId(examEntity.getId());
         // 删除校验记录

+ 64 - 0
src/main/java/cn/com/qmth/print/manage/utils/Zip4jUtil.java

@@ -0,0 +1,64 @@
+package cn.com.qmth.print.manage.utils;
+
+import com.qmth.boot.core.exception.StatusException;
+import net.lingala.zip4j.core.ZipFile;
+import net.lingala.zip4j.exception.ZipException;
+
+import java.io.File;
+import java.util.Objects;
+
+/**
+ * @Description:
+ * @Author: CaoZixuan
+ * @Date:
+ */
+public class Zip4jUtil {
+
+    /**
+     * 解压zip带密码
+     *
+     * @param scrPath  zip路径
+     * @param destPath 解压后路径
+     * @param password 解压密码
+     */
+    public static void unzipEncryptFile(String scrPath, String destPath, String password) {
+        if (scrPath == null || scrPath.length() == 0) {
+            throw new StatusException("原始路径不能为空");
+        }
+        if (destPath == null || destPath.length() == 0) {
+            throw new StatusException("解压路径不能为空");
+        }
+        if (password == null || password.length() == 0) {
+            throw new StatusException("解压密码不能为空");
+        }
+
+        commonUnZipFile(scrPath, destPath, password);
+    }
+
+    /**
+     * 解压zip包
+     *
+     * @param scrPath  zip路径
+     * @param destPath 解压后路径
+     * @param password 解压密码
+     */
+    private static void commonUnZipFile(String scrPath, String destPath, String password) {
+        try {
+            File file = new File(scrPath);
+            if (!file.exists()) {
+                file.getParentFile().mkdirs();
+            }
+            ZipFile zipFile = new ZipFile(scrPath);
+            if (Objects.nonNull(password) && zipFile.isEncrypted()) {
+                zipFile.setPassword(password);
+            }
+            File currentFile = new File(destPath);
+            if (!currentFile.exists()) {
+                currentFile.mkdirs();
+            }
+            zipFile.extractAll(destPath);
+        } catch (ZipException e) {
+            throw new StatusException(e.getMessage());
+        }
+    }
+}

+ 61 - 3
src/main/java/cn/com/qmth/print/manage/utils/excel/ExcelReader.java

@@ -1,13 +1,15 @@
 package cn.com.qmth.print.manage.utils.excel;
 
-import com.qmth.boot.core.exception.StatusException;
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.ss.usermodel.*;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.Objects;
 
@@ -62,10 +64,14 @@ public class ExcelReader extends ExcelUtils {
 					for (int j = 0; j < this.getColumnSettings().size(); j++) {
 						ColumnSetting columnSetting = this.getColumnSettings().get(j);
 						Cell cell = row.getCell(columnSetting.getIndex() - 1);
-						Object obj = convert(cell);
+						if (Objects.isNull(cell)){
+							// TODO: 2023/10/19 这个地方可以植入@NotNull判断必填报错 
+							continue;
+						}
+						String value = analyzeExcelCellValue(cell);
 						Field field = getDataClass().getDeclaredField(columnSetting.getFieldName());
 						field.setAccessible(true);
-						field.set(dto, obj);
+						field.set(dto, value);
 					}
 				} catch (NoSuchFieldException e) {
 					e.printStackTrace();
@@ -116,4 +122,56 @@ public class ExcelReader extends ExcelUtils {
 		
 		return null;
 	}
+
+	/**
+	 * 解析excel单元格类型
+	 *
+	 * @param cell 单元格
+	 * @return 转换成字符串后的值
+	 */
+	public static String analyzeExcelCellValue(Cell cell) {
+		String cellValue;
+		CellType cellType = cell.getCellTypeEnum();
+		switch (cellType) {
+			case NUMERIC:
+				if (HSSFDateUtil.isCellDateFormatted(cell)) {
+					SimpleDateFormat sdf;
+					// 验证short值
+					if (cell.getCellStyle().getDataFormat() == 14) {
+						sdf = new SimpleDateFormat("yyyy/MM/dd");
+					} else if (cell.getCellStyle().getDataFormat() == 21) {
+						sdf = new SimpleDateFormat("HH:mm:ss");
+					} else if (cell.getCellStyle().getDataFormat() == 22) {
+						sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+					} else {
+						throw new RuntimeException("日期格式错误!!!");
+					}
+					Date date = cell.getDateCellValue();
+					cellValue = sdf.format(date);
+				} else {//处理数值格式
+					cell.setCellType(CellType.STRING);
+					cellValue = String.valueOf(cell.getRichStringCellValue().getString());
+				}
+				break;
+			case STRING:
+				cellValue = String.valueOf(cell.getStringCellValue());
+				break;
+			case BOOLEAN:
+				cellValue = String.valueOf(cell.getBooleanCellValue());
+				break;
+			case FORMULA:
+				cellValue = String.valueOf(cell.getCellFormula());
+				break;
+			case BLANK:
+				cellValue = null;
+				break;
+			case ERROR:
+				cellValue = "非法字符";
+				break;
+			default:
+				cellValue = "未知类型";
+				break;
+		}
+		return cellValue;
+	}
 }