xiaofei 7 hónapja
szülő
commit
a352dcb9e6
30 módosított fájl, 707 hozzáadás és 164 törlés
  1. 0 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicExamStudentServiceImpl.java
  2. 1 1
      distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/OpenApiServiceImpl.java
  3. 24 0
      distributed-print/install/mysql/init/teachcloud_db.sql
  4. 22 0
      distributed-print/install/mysql/upgrade/3.4.2.sql
  5. 19 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/scananswer/AnswerQueryDomain.java
  6. 12 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/manage/MarkStepDTO.java
  7. 68 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/manage/MarkerScoreDTO.java
  8. 9 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/score/StudentScoreDetailDto.java
  9. 12 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkStudent.java
  10. 217 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/ScanAnswerCardQuestion.java
  11. 16 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/mapper/ScanAnswerCardQuestionMapper.java
  12. 0 2
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkPaperService.java
  13. 0 2
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkQuestionAnswerService.java
  14. 0 1
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkQuestionService.java
  15. 3 2
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkStudentService.java
  16. 23 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/ScanAnswerCardQuestionService.java
  17. 6 10
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkPaperServiceImpl.java
  18. 0 8
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkQuestionAnswerServiceImpl.java
  19. 0 8
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkQuestionServiceImpl.java
  20. 2 2
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkServiceImpl.java
  21. 57 74
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkStudentServiceImpl.java
  22. 4 4
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkUserGroupServiceImpl.java
  23. 54 0
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanAnswerCardQuestionServiceImpl.java
  24. 22 37
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanAnswerCardServiceImpl.java
  25. 5 5
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanOmrTaskServiceImpl.java
  26. 42 1
      teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/TaskServiceImpl.java
  27. 10 0
      teachcloud-mark/src/main/resources/mapper/MarkStudentMapper.xml
  28. 25 0
      teachcloud-mark/src/main/resources/mapper/ScanAnswerCardQuestionMapper.xml
  29. 4 1
      teachcloud-task/src/main/java/com/qmth/teachcloud/task/service/PrintFinishService.java
  30. 50 5
      teachcloud-task/src/main/java/com/qmth/teachcloud/task/service/impl/PrintFinishServiceImpl.java

+ 0 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicExamStudentServiceImpl.java

@@ -165,7 +165,6 @@ public class BasicExamStudentServiceImpl extends ServiceImpl<BasicExamStudentMap
                 }
             }
 
-
             if (CollectionUtils.isNotEmpty(basicExamStudentIds)) {
                 examStudentService.deleteByBasicStudentId(basicExamStudentIds);
                 markStudentService.deleteByBasicStudentId(basicExamStudentIds);

+ 1 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/OpenApiServiceImpl.java

@@ -239,7 +239,7 @@ public class OpenApiServiceImpl implements OpenApiService {
             int status = 1;
             if (e.getAbsent() || e.getManualAbsent() || e.getOmrAbsent()) {
                 status = 2;
-            } else if (e.getBreach()) {
+            } else if (e.getBreach() || e.getManualBreach() || e.getOmrBreach()) {
                 status = 3;
             }
             examStudentScore.setStatus(status);

+ 24 - 0
distributed-print/install/mysql/init/teachcloud_db.sql

@@ -1797,6 +1797,7 @@ CREATE TABLE IF NOT EXISTS `mark_student` (
   `incomplete` bit(1) DEFAULT NULL,
   `breach_code` varchar(32) DEFAULT NULL,
   `omr_absent` bit(1) DEFAULT NULL COMMENT '识别缺考',
+  `is_manual_breach` TINYINT(1) NULL DEFAULT 0 COMMENT '人工指定缺考',
   `omr_absent_checked` bit(1) DEFAULT NULL COMMENT '识别缺考检查',
   `omr_breach` TINYINT(1) NULL DEFAULT 0 COMMENT '识别违纪',
   `paper_type_check_status` varchar(32) NOT NULL DEFAULT 'NORMAL' COMMENT '卷型检查状态',
@@ -2397,6 +2398,29 @@ CREATE TABLE IF NOT EXISTS `scan_answer_card` (
   UNIQUE KEY `idx_1` (`exam_id`,`number`) USING BTREE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='题卡卡格式表';
 
+-- ----------------------------
+-- Table structure for scan_answer_card_question
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `scan_answer_card_question`  (
+      `id` bigint NOT NULL COMMENT '主键',
+      `exam_id` bigint NOT NULL COMMENT '考试ID',
+      `paper_number` varchar(100) NOT NULL COMMENT '试卷类型',
+      `course_paper_id` varchar(32) NULL DEFAULT NULL COMMENT '试卷编号(交互)',
+      `serial_number` int NULL DEFAULT NULL COMMENT '备用卷',
+      `card_number` int NULL DEFAULT NULL COMMENT '卡格式序号',
+      `main_number` int NOT NULL COMMENT '大题号',
+      `sub_number` int NOT NULL COMMENT '小题号',
+      `option_count` int NOT NULL COMMENT '选项个数',
+      `question_type` varchar(2) NULL DEFAULT NULL COMMENT '题型',
+      `paper_index` int NULL DEFAULT NULL,
+      `page_index` int NULL DEFAULT NULL,
+      `create_id` bigint NULL DEFAULT NULL,
+      `create_time` bigint NULL DEFAULT NULL,
+      `update_id` bigint NULL DEFAULT NULL,
+      `update_time` bigint NULL DEFAULT NULL,
+      PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '卡格式题型';
+
 -- ----------------------------
 -- Table structure for scan_answer_card_subject
 -- ----------------------------

+ 22 - 0
distributed-print/install/mysql/upgrade/3.4.2.sql

@@ -149,3 +149,25 @@ update mark_paper set paper_file_path = concat('[',paper_file_path, ']') where p
 ALTER TABLE obe_course_outline MODIFY COLUMN course_type varchar(50) NOT NULL COMMENT '课程类别';
 
 ALTER TABLE `t_b_session` CHANGE COLUMN `type` `type` VARCHAR(200) NOT NULL COMMENT '用户类型' ;
+
+ALTER TABLE `mark_student` ADD COLUMN `is_manual_breach` TINYINT(1) NULL DEFAULT 0 COMMENT '人工指定缺考' AFTER `omr_breach`;
+
+CREATE TABLE `scan_answer_card_question`  (
+      `id` bigint NOT NULL COMMENT '主键',
+      `exam_id` bigint NOT NULL COMMENT '考试ID',
+      `paper_number` varchar(100) NOT NULL COMMENT '试卷类型',
+      `course_paper_id` varchar(32) NULL DEFAULT NULL COMMENT '试卷编号(交互)',
+      `serial_number` int NULL DEFAULT NULL COMMENT '备用卷',
+      `card_number` int NULL DEFAULT NULL COMMENT '卡格式序号',
+      `main_number` int NOT NULL COMMENT '大题号',
+      `sub_number` int NOT NULL COMMENT '小题号',
+      `option_count` int NOT NULL COMMENT '选项个数',
+      `question_type` varchar(2) NULL DEFAULT NULL COMMENT '题型',
+      `paper_index` int NULL DEFAULT NULL,
+      `page_index` int NULL DEFAULT NULL,
+      `create_id` bigint NULL DEFAULT NULL,
+      `create_time` bigint NULL DEFAULT NULL,
+      `update_id` bigint NULL DEFAULT NULL,
+      `update_time` bigint NULL DEFAULT NULL,
+      PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '卡格式题型';

+ 19 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/bean/scananswer/AnswerQueryDomain.java

@@ -41,6 +41,7 @@ public class AnswerQueryDomain extends PagerQuery {
 
     private Boolean omrAbsent;
     private Boolean omrAbsentChecked;
+    private Boolean manualAbsent;
 
     private Boolean assigned;
     private Boolean assignConfirmed;
@@ -61,6 +62,8 @@ public class AnswerQueryDomain extends PagerQuery {
 	private PaperTypeCheckStatus paperTypeCheckStatus;
 	@ApiModelProperty("识别违纪")
 	private Boolean omrBreach;
+	@ApiModelProperty("人工指定违纪")
+	private Boolean manualBreach;
 	public Long getExamId() {
 		return examId;
 	}
@@ -249,4 +252,20 @@ public class AnswerQueryDomain extends PagerQuery {
 	public void setOmrBreach(Boolean omrBreach) {
 		this.omrBreach = omrBreach;
 	}
+
+	public Boolean getManualAbsent() {
+		return manualAbsent;
+	}
+
+	public void setManualAbsent(Boolean manualAbsent) {
+		this.manualAbsent = manualAbsent;
+	}
+
+	public Boolean getManualBreach() {
+		return manualBreach;
+	}
+
+	public void setManualBreach(Boolean manualBreach) {
+		this.manualBreach = manualBreach;
+	}
 }

+ 12 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/manage/MarkStepDTO.java

@@ -31,6 +31,7 @@ public class MarkStepDTO implements Serializable {
     private List<TrackDTO> trackList = new ArrayList<>();
 
     private List<TrackDTO> headerTrack = new ArrayList<>();
+    private List<MarkerScoreDTO> markerList = new ArrayList<>();
 
     public int getMainNumber() {
         return mainNumber;
@@ -136,4 +137,15 @@ public class MarkStepDTO implements Serializable {
         this.headerTrack.add(trackDTO);
     }
 
+    public List<MarkerScoreDTO> getMarkerList() {
+        return markerList;
+    }
+
+    public void setMarkerList(List<MarkerScoreDTO> markerList) {
+        this.markerList = markerList;
+    }
+
+    public void addMarkerList(MarkerScoreDTO markerScoreDTO) {
+        this.markerList.add(markerScoreDTO);
+    }
 }

+ 68 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/manage/MarkerScoreDTO.java

@@ -0,0 +1,68 @@
+package com.qmth.teachcloud.mark.dto.mark.manage;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+
+import java.io.Serializable;
+
+/**
+ * 阅卷轨迹交换类
+ *
+ * @author luoshi
+ */
+public class MarkerScoreDTO implements Serializable {
+
+    private static final long serialVersionUID = 4336042741848228793L;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long userId;
+
+    private String loginName;
+
+    private String userName;
+
+    private double score;
+
+    // 是否为科组长
+    private boolean header;
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public String getLoginName() {
+        return loginName;
+    }
+
+    public void setLoginName(String loginName) {
+        this.loginName = loginName;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public double getScore() {
+        return score;
+    }
+
+    public void setScore(double score) {
+        this.score = score;
+    }
+
+    public boolean isHeader() {
+        return header;
+    }
+
+    public void setHeader(boolean header) {
+        this.header = header;
+    }
+}

+ 9 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/dto/mark/score/StudentScoreDetailDto.java

@@ -47,6 +47,7 @@ public class StudentScoreDetailDto {
     private SubjectiveStatus subjectiveStatus;
     private Boolean absent;
     private Boolean omrAbsent;
+    private Boolean manualAbsent;
     private String statusDisplay;
     private Boolean upload;
     // 主观题检查标记
@@ -307,6 +308,14 @@ public class StudentScoreDetailDto {
         this.omrAbsent = omrAbsent;
     }
 
+    public Boolean getManualAbsent() {
+        return manualAbsent;
+    }
+
+    public void setManualAbsent(Boolean manualAbsent) {
+        this.manualAbsent = manualAbsent;
+    }
+
     public String getStatusDisplay() {
         return statusDisplay;
     }

+ 12 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/MarkStudent.java

@@ -125,6 +125,10 @@ public class MarkStudent implements Serializable {
     @TableField(value = "is_breach")
     private Boolean breach;
 
+    @ApiModelProperty(value = "是否人工指定违纪")
+    @TableField(value = "is_manual_breach")
+    private Boolean manualBreach;
+
     @ApiModelProperty(value = "上传时间")
     @TableField(updateStrategy = FieldStrategy.IGNORED)
     private Long uploadTime;
@@ -403,6 +407,14 @@ public class MarkStudent implements Serializable {
         this.breach = breach;
     }
 
+    public Boolean getManualBreach() {
+        return manualBreach;
+    }
+
+    public void setManualBreach(Boolean manualBreach) {
+        this.manualBreach = manualBreach;
+    }
+
     public Long getUploadTime() {
         return uploadTime;
     }

+ 217 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/entity/ScanAnswerCardQuestion.java

@@ -0,0 +1,217 @@
+package com.qmth.teachcloud.mark.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 卡格式题型
+ * </p>
+ *
+ * @author xf
+ * @since 2024-11-13
+ */
+@TableName("scan_answer_card_question")
+@ApiModel(value = "ScanAnswerCardQuestion对象", description = "卡格式题型")
+public class ScanAnswerCardQuestion implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.INPUT)
+    private Long id;
+
+    @ApiModelProperty(value = "考试ID")
+    private Long examId;
+
+    @ApiModelProperty(value = "试卷类型")
+    private String paperNumber;
+
+    @ApiModelProperty(value = "试卷编号(交互)")
+    private String coursePaperId;
+
+    @ApiModelProperty(value = "备用卷")
+    private Integer serialNumber;
+
+    @ApiModelProperty(value = "卡格式序号")
+    private Integer cardNumber;
+
+    @ApiModelProperty(value = "大题号")
+    private Integer mainNumber;
+
+    @ApiModelProperty(value = "小题号")
+    private Integer subNumber;
+
+    @ApiModelProperty(value = "选项个数")
+    private Integer optionCount;
+
+    @ApiModelProperty(value = "题型")
+    private Integer questionType;
+
+    private Integer paperIndex;
+
+    private Integer pageIndex;
+
+    private Long createId;
+
+    private Long createTime;
+
+    private Long updateId;
+
+    private Long updateTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getPaperNumber() {
+        return paperNumber;
+    }
+
+    public void setPaperNumber(String paperNumber) {
+        this.paperNumber = paperNumber;
+    }
+
+    public String getCoursePaperId() {
+        return coursePaperId;
+    }
+
+    public void setCoursePaperId(String coursePaperId) {
+        this.coursePaperId = coursePaperId;
+    }
+
+    public Integer getSerialNumber() {
+        return serialNumber;
+    }
+
+    public void setSerialNumber(Integer serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
+    public Integer getCardNumber() {
+        return cardNumber;
+    }
+
+    public void setCardNumber(Integer cardNumber) {
+        this.cardNumber = cardNumber;
+    }
+
+    public Integer getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public Integer getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(Integer subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public Integer getOptionCount() {
+        return optionCount;
+    }
+
+    public void setOptionCount(Integer optionCount) {
+        this.optionCount = optionCount;
+    }
+
+    public Integer getQuestionType() {
+        return questionType;
+    }
+
+    public void setQuestionType(Integer questionType) {
+        this.questionType = questionType;
+    }
+
+    public Integer getPaperIndex() {
+        return paperIndex;
+    }
+
+    public void setPaperIndex(Integer paperIndex) {
+        this.paperIndex = paperIndex;
+    }
+
+    public Integer getPageIndex() {
+        return pageIndex;
+    }
+
+    public void setPageIndex(Integer pageIndex) {
+        this.pageIndex = pageIndex;
+    }
+
+    public Long getCreateId() {
+        return createId;
+    }
+
+    public void setCreateId(Long createId) {
+        this.createId = createId;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+
+    public Long getUpdateId() {
+        return updateId;
+    }
+
+    public void setUpdateId(Long updateId) {
+        this.updateId = updateId;
+    }
+
+    public Long getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Long updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @Override
+    public String toString() {
+        return "ScanAnswerCardQuestion{" +
+                "id=" + id +
+                ", examId=" + examId +
+                ", paperNumber=" + paperNumber +
+                ", coursePaperId=" + coursePaperId +
+                ", serialNumber=" + serialNumber +
+                ", cardNumber=" + cardNumber +
+                ", mainNumber=" + mainNumber +
+                ", subNumber=" + subNumber +
+                ", optionCount=" + optionCount +
+                ", questionType=" + questionType +
+                ", paperIndex=" + paperIndex +
+                ", pageIndex=" + pageIndex +
+                ", createId=" + createId +
+                ", createTime=" + createTime +
+                ", updateId=" + updateId +
+                ", updateTime=" + updateTime +
+                "}";
+    }
+}

+ 16 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/mapper/ScanAnswerCardQuestionMapper.java

@@ -0,0 +1,16 @@
+package com.qmth.teachcloud.mark.mapper;
+
+import com.qmth.teachcloud.mark.entity.ScanAnswerCardQuestion;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 卡格式题型 Mapper 接口
+ * </p>
+ *
+ * @author xf
+ * @since 2024-11-13
+ */
+public interface ScanAnswerCardQuestionMapper extends BaseMapper<ScanAnswerCardQuestion> {
+
+}

+ 0 - 2
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkPaperService.java

@@ -59,8 +59,6 @@ public interface MarkPaperService extends IService<MarkPaper> {
     IPage<CheckScoreListDto> listStudentScoreList(Long examId, Long openCollegeId, Long courseId, String paperNumber,
             Integer pageNumber, Integer pageSize);
 
-    void updateStatus(Long examId, String paperNumber, MarkPaperStatus newStatus, MarkPaperStatus currentStatus);
-
     void updateUploadCount(Long examId, String paperNumber, int countUploaded);
 
     IPage<MarkPaperPackageDto> listPackage(Long examId, String paperNumber, String packageCode, Integer pageNumber,

+ 0 - 2
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkQuestionAnswerService.java

@@ -21,6 +21,4 @@ public interface MarkQuestionAnswerService extends IService<MarkQuestionAnswer>
     List<MarkQuestionAnswer> listByExamIdAndPaperNumberAndPaperType(Long examId, String paperNumber, String paperType);
 
     int countByExamIdAndPaperNumber(Long examId, String paperNumber);
-
-    void deleteByExamIdAndPaperNumber(Long examId, String paperNumber);
 }

+ 0 - 1
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkQuestionService.java

@@ -99,5 +99,4 @@ public interface MarkQuestionService extends IService<MarkQuestion> {
 
     List<MarkQuestion> listByExamIdAndPaperNumber(Long examId, String paperNumber);
 
-    void deleteByExamIdAndPaperNumberAndObjective(Long examId, String paperNumber, boolean objective);
 }

+ 3 - 2
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/MarkStudentService.java

@@ -33,6 +33,7 @@ import com.qmth.teachcloud.mark.dto.mark.score.StudentScoreDetailDto;
 import com.qmth.teachcloud.mark.entity.MarkPaper;
 import com.qmth.teachcloud.mark.entity.MarkStudent;
 import com.qmth.teachcloud.mark.entity.ScanStudentPaper;
+import com.qmth.teachcloud.mark.enums.PaperTypeCheckStatus;
 import com.qmth.teachcloud.mark.params.MarkHeaderResult;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -100,6 +101,8 @@ public interface MarkStudentService extends IService<MarkStudent> {
 
     List<SheetUrlDto> buildSheetUrls(Long studentId);
 
+    int getPaperTypeCheckCount(Long examId, Long courseId, String coursePaperId, PaperTypeCheckStatus status, DataPermissionRule dpr);
+
     ScanExamCheckInfoVo checkInfo(BasicExam exam, Long courseId, String coursePaperId);
 
     /**
@@ -130,8 +133,6 @@ public interface MarkStudentService extends IService<MarkStudent> {
 
     List<MarkStudent> listUnMarkTaskStudent(Long examId, String paperNumber, Integer groupNumber, int pageSize);
 
-    boolean saveUploadStudent(MarkStudent student);
-
     void calculateObjectiveScore(MarkStudent student);
 
     void updateStudentAndPaper(SysUser user, Long studentId, List<ScanStudentPaper> studentPaperList, boolean clearMarkTask);

+ 23 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/ScanAnswerCardQuestionService.java

@@ -0,0 +1,23 @@
+package com.qmth.teachcloud.mark.service;
+
+import com.qmth.teachcloud.mark.entity.ScanAnswerCardQuestion;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 卡格式题型 服务类
+ * </p>
+ *
+ * @author xf
+ * @since 2024-11-13
+ */
+public interface ScanAnswerCardQuestionService extends IService<ScanAnswerCardQuestion> {
+
+    void deleteByExamIdAndPaperNumberAndCardNumber(Long examId, String paperNumber, Integer number);
+
+    List<ScanAnswerCardQuestion> listByExamIdAndPaperNumberAndCardNumberAndPaperIndexAndPageIndex(Long examId, String paperNumber, Integer cardNumber, Integer paperIndex, Integer pageIndex);
+
+    List<ScanAnswerCardQuestion> listByExamIdAndPaperNumberAndCardNumber(Long examId, String paperNumber, Integer number);
+}

+ 6 - 10
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkPaperServiceImpl.java

@@ -51,6 +51,7 @@ import com.qmth.teachcloud.mark.dto.mark.score.SettingDto;
 import com.qmth.teachcloud.mark.entity.*;
 import com.qmth.teachcloud.mark.enums.CardSource;
 import com.qmth.teachcloud.mark.enums.OmrTaskStatus;
+import com.qmth.teachcloud.mark.enums.PaperTypeCheckStatus;
 import com.qmth.teachcloud.mark.mapper.MarkPaperMapper;
 import com.qmth.teachcloud.mark.service.*;
 import com.qmth.teachcloud.mark.utils.Calculator;
@@ -263,6 +264,11 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
                         stringJoiner.add(courseInfo + "人工绑定记录未核对,请在扫描客户端进行确认操作后再结束阅卷");
                         continue;
                     }
+                    // 卷型检查未做完,不能结束
+                    if (markStudentService.getPaperTypeCheckCount(examId, markPaper.getCourseId(), markPaper.getCoursePaperId(), PaperTypeCheckStatus.WAITING, null) > 0) {
+                        stringJoiner.add(courseInfo + "卷型检查记录未核对,请在扫描客户端进行确认操作后再结束阅卷");
+                        continue;
+                    }
                     // 客观题检查未做完,不能结束
                     if (scanOmrTaskService.getFinishStudentCountByExamAndUserId(examId, markPaper.getCourseId(), markPaper.getCoursePaperId(), OmrTaskStatus.WAITING.name(), null) > 0) {
                         stringJoiner.add(courseInfo + "客观题存在识别嫌疑需要人工确认,请在扫描客户端进行确认操作后再结束阅卷");
@@ -362,16 +368,6 @@ public class MarkPaperServiceImpl extends ServiceImpl<MarkPaperMapper, MarkPaper
         return this.baseMapper.listStudentScoreList(page, examId, openCollegeId, courseId, paperNumber, dpr);
     }
 
-    @Override
-    public void updateStatus(Long examId, String paperNumber, MarkPaperStatus newStatus, MarkPaperStatus currentStatus) {
-        UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().set(MarkPaper::getStatus, newStatus)
-                .eq(MarkPaper::getExamId, examId)
-                .eq(MarkPaper::getPaperNumber, paperNumber)
-                .eq(MarkPaper::getStatus, currentStatus);
-        this.update(updateWrapper);
-    }
-
     @Override
     public void updateUploadCount(Long examId, String paperNumber, int countUploaded) {
         UpdateWrapper<MarkPaper> updateWrapper = new UpdateWrapper<>();

+ 0 - 8
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkQuestionAnswerServiceImpl.java

@@ -57,12 +57,4 @@ public class MarkQuestionAnswerServiceImpl extends ServiceImpl<MarkQuestionAnswe
                 .eq(MarkQuestionAnswer::getPaperNumber, paperNumber);
         return this.count(queryWrapper);
     }
-
-    @Override
-    public void deleteByExamIdAndPaperNumber(Long examId, String paperNumber) {
-        UpdateWrapper<MarkQuestionAnswer> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().eq(MarkQuestionAnswer::getExamId, examId)
-                .eq(MarkQuestionAnswer::getPaperNumber, paperNumber);
-        this.remove(updateWrapper);
-    }
 }

+ 0 - 8
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkQuestionServiceImpl.java

@@ -545,12 +545,4 @@ public class MarkQuestionServiceImpl extends ServiceImpl<MarkQuestionMapper, Mar
         return this.list(queryWrapper);
     }
 
-    @Override
-    public void deleteByExamIdAndPaperNumberAndObjective(Long examId, String paperNumber, boolean objective) {
-        UpdateWrapper<MarkQuestion> updateWrapper = new UpdateWrapper<>();
-        updateWrapper.lambda().eq(MarkQuestion::getExamId, examId)
-                .eq(MarkQuestion::getPaperNumber, paperNumber)
-                .eq(MarkQuestion::getObjective, objective);
-        this.remove(updateWrapper);
-    }
 }

+ 2 - 2
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkServiceImpl.java

@@ -1170,8 +1170,8 @@ public class MarkServiceImpl implements MarkService {
     }
 
     private void calculate(MarkStudent student) {
-        // 未上传、缺考、违纪的考生不统分
-        if (!student.getUpload() || student.getAbsent() || student.getBreach()) {
+        // 未上传、缺考的考生不统分
+        if (!student.getUpload() || student.getAbsent() || student.getOmrAbsent() || student.getManualAbsent()) {
             return;
         }
         try {

+ 57 - 74
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkStudentServiceImpl.java

@@ -64,11 +64,9 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.FillPatternType;
 import org.apache.poi.ss.usermodel.IndexedColors;
-import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.FileCopyUtils;
-import org.springframework.util.ReflectionUtils;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
@@ -281,7 +279,7 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
                             scoreDetailDto.getSubjectiveScoreList()));
             // 客观题检查标记
             scoreDetailDto.setObjectiveCheckFlag(
-                    !scoreDetailDto.getAbsent() && !scoreDetailDto.getOmrAbsent() && scoreDetailDto.getUpload() && ScanStatus.SCANNED.equals(scoreDetailDto.getScanStatus()) && StringUtils.isNotBlank(
+                    !scoreDetailDto.getAbsent() && !scoreDetailDto.getManualAbsent() && !scoreDetailDto.getOmrAbsent() && scoreDetailDto.getUpload() && ScanStatus.SCANNED.equals(scoreDetailDto.getScanStatus()) && StringUtils.isNotBlank(
                             scoreDetailDto.getObjectiveScore()) && StringUtils.isNotBlank(scoreDetailDto.getObjectiveScoreList()));
 
             // 格式化分数
@@ -452,6 +450,18 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         return baseMapper.selectCountByQuery(markStudent, dpr);
     }
 
+    private int getManualAbsentCount(Long examId, Long courseId, String coursePaperId,
+                                     MarkPaperStatus markPaperStatus, DataPermissionRule dpr) {
+        MarkStudent markStudent = new MarkStudent();
+        markStudent.setExamId(examId);
+        markStudent.setCourseId(courseId);
+        markStudent.setCoursePaperId(coursePaperId);
+        markStudent.setScanStatus(ScanStatus.UNEXIST);
+        markStudent.setManualAbsent(true);
+        markStudent.setMarkPaperStatus(markPaperStatus.name());
+        return baseMapper.selectCountByQuery(markStudent, dpr);
+    }
+
     private int getMissScanCount(Long examId, Long courseId, String coursePaperId,
                                  MarkPaperStatus markPaperStatus, DataPermissionRule dpr) {
         MarkStudent markStudent = new MarkStudent();
@@ -486,7 +496,8 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         return baseMapper.selectCountByQuery(markStudent, dpr);
     }
 
-    private int getPaperTypeCheckCount(Long examId, Long courseId, String coursePaperId, PaperTypeCheckStatus status, DataPermissionRule dpr) {
+    @Override
+    public int getPaperTypeCheckCount(Long examId, Long courseId, String coursePaperId, PaperTypeCheckStatus status, DataPermissionRule dpr) {
         MarkStudent markStudent = new MarkStudent();
         markStudent.setExamId(examId);
         markStudent.setCourseId(courseId);
@@ -506,8 +517,7 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         vo.setName(exam.getName());
         CheckTask ct = vo.getCheckTask();
         ct.setUnexistCount(getCount(examId, ScanStatus.UNEXIST, courseId, coursePaperId, MarkPaperStatus.FORMAL, dpr));
-        ct.setUnexistCheckedCount(
-                getCount(examId, ScanStatus.MANUAL_ABSENT, courseId, coursePaperId, MarkPaperStatus.FORMAL, dpr));
+        ct.setUnexistCheckedCount(getManualAbsentCount(examId, courseId, coursePaperId, MarkPaperStatus.FORMAL, dpr));
         ct.setMissScanCount(getMissScanCount(examId, courseId, coursePaperId, MarkPaperStatus.FORMAL, dpr));
         ct.setAssignedCount(getAssignedCount(examId, false, courseId, coursePaperId, MarkPaperStatus.FORMAL, dpr));
         ct.setAssignedCheckedCount(
@@ -541,11 +551,12 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
 
         // 重置状态
         student.setIncomplete(false);
-        student.setAssigned(false);
-        student.setAssignConfirmed(false);
+        if (!omrEdit) {
+            student.setAssigned(false);
+            student.setAssignConfirmed(false);
+        }
         student.setInvalid(false);
         student.setQuestionFilled(false);
-        // student.setOmrAbsent(false);
         int paperCount = 0;
         List<ScanStudentPaper> studentPaperList = studentPaperService.findByStudentId(studentId);
         List<String> objectiveAnswers = new ArrayList<>();
@@ -565,21 +576,19 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
                     student.setOmrAbsent(page.getAbsent() != null && page.getAbsent().getResult());
                     student.setOmrBreach(page.getBreach() != null && page.getBreach().getResult());
                     student.setOmrAbsentChecked(false);
-                    student.setAbsent(false);
                     student.setManualAbsent(false);
+                    student.setManualBreach(false);
                     if (student.getOmrAbsent()) {
                         student.setObjectiveScore(null);
                         student.setObjectiveScoreList(null);
                     }
                 } else {
-                    student.setScanStatus(page.getAbsent() != null && page.getAbsent().getResult() ? ScanStatus.MANUAL_ABSENT : student.getScanStatus());
-                    student.setManualAbsent(ScanStatus.MANUAL_ABSENT.equals(student.getScanStatus()));
-                    student.setBreach(page.getBreach() != null && page.getBreach().getResult());
+                    student.setManualAbsent(page.getAbsent() != null && page.getAbsent().getResult());
+                    student.setManualBreach(page.getBreach() != null && page.getBreach().getResult());
                 }
+                student.setAbsent(student.getOmrAbsent() || student.getManualAbsent());
+                student.setBreach(student.getOmrBreach() || student.getManualBreach());
 
-                // student.setDevice(batchService.findByPaperId(paper.getId()).getDevice());
-
-                PaperTypeCheckStatus paperTypeCheckStatus = PaperTypeCheckStatus.NORMAL;
                 // 根据卷型识别结果更新考生卷型,如果卷型识别结果异常则添加到卷型检查中
                 StringResult paperTypeResult = page.getPaperType();
 
@@ -599,15 +608,14 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
                     }
                     student.setPaperType(paperType);
                     if (!omrEdit) {
-                        if (paperType.length() > 1) {
-                            // 多卷型
-                            paperTypeCheckStatus = PaperTypeCheckStatus.WAITING;
-                        }
-                        if ("#".equals(paperType)) {
-                            // 没有识别到卷型
-                            paperTypeCheckStatus = PaperTypeCheckStatus.WAITING;
+                        if (paperType.length() > 1 || "#".equals(paperType)) {
+                            // 多卷型、没有识别到卷型
+                            student.setPaperTypeCheckStatus(PaperTypeCheckStatus.WAITING);
+                        } else {
+                            student.setPaperTypeCheckStatus(PaperTypeCheckStatus.NORMAL);
                         }
-                        student.setPaperTypeCheckStatus(paperTypeCheckStatus);
+                    } else {
+                        student.setPaperTypeCheckStatus(PaperTypeCheckStatus.PROCESSED);
                     }
                 }
 
@@ -731,7 +739,7 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
             studentObjectiveDetailDto.setSubjectiveScore(
                     markStudent.getSubjectiveScore() != null ? markStudent.getSubjectiveScore() : 0);
             studentObjectiveDetailDto.setUpload(markStudent.getUpload());
-            studentObjectiveDetailDto.setAbsent(markStudent.getAbsent());
+            studentObjectiveDetailDto.setAbsent(markStudent.getAbsent() || markStudent.getManualAbsent() || markStudent.getOmrAbsent());
             studentObjectiveDetailDto.setSheetUrls(this.buildSheetUrls(studentId));
 
             List<MarkQuestionAnswerVo> questions = markQuestionService.listQuestionAnswerByExamIdAndPaperNumberAndPaperType(
@@ -779,14 +787,18 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(student.getExamId(), student.getPaperNumber());
         // 评卷是否结束
         if (markPaper == null || MarkPaperStatus.FINISH.equals(markPaper.getStatus())) {
-            throw ExceptionResultEnum.ERROR.exception("科目已结束评卷,无法打分");
+            throw ExceptionResultEnum.ERROR.exception("科目已结束评卷");
         }
         answers = StringUtils.trimToEmpty(answers);
         if (student != null) {
             student.setAnswers(answers.toUpperCase());
             student.setCheckUserId(userId);
             student.setCheckTime(System.currentTimeMillis());
-            return saveUploadStudent(student);
+            boolean success = this.updateScanInfo(student);
+            if (success) {
+                calculateObjectiveScore(student);
+            }
+            return success;
         } else {
             return false;
         }
@@ -798,9 +810,7 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         queryWrapper.lambda().eq(MarkStudent::getExamId, examId).eq(MarkStudent::getPaperNumber, paperNumber)
                 .eq(MarkStudent::getUpload, true)
                 .eq(MarkStudent::getScanStatus, ScanStatus.SCANNED)
-                .eq(MarkStudent::getAbsent, false)
-                .eq(MarkStudent::getBreach, false)
-                .eq(MarkStudent::getOmrAbsent, false);
+                .eq(MarkStudent::getAbsent, false);
         return this.count(queryWrapper);
     }
 
@@ -808,9 +818,9 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
     public boolean updateScanInfo(MarkStudent student) {
         UpdateWrapper<MarkStudent> updateWrapper = new UpdateWrapper<>();
         updateWrapper.lambda().set(MarkStudent::getAnswers, student.getAnswers())
-                .set(MarkStudent::getBatchCode, student.getBatchCode()).set(MarkStudent::getAbsent, student.getAbsent())
-                .set(MarkStudent::getUploadTime, System.currentTimeMillis())
-                .set(MarkStudent::getCardNumber, student.getCardNumber()).eq(MarkStudent::getId, student.getId());
+                .set(MarkStudent::getCheckUserId, student.getCheckUserId())
+                .set(MarkStudent::getCheckTime, student.getCheckTime())
+                .eq(MarkStudent::getId, student.getId());
         return this.update(updateWrapper);
 
     }
@@ -821,7 +831,8 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
     }
 
     @Override
-    public List<MarkStudent> listUnMarkTaskStudent(Long examId, String paperNumber, Integer groupNumber, int pageSize) {
+    public List<MarkStudent> listUnMarkTaskStudent(Long examId, String paperNumber, Integer groupNumber,
+                                                   int pageSize) {
         Page<MarkStudent> page = new Page<>(1, pageSize);
         IPage<MarkStudent> markStudentIPage = this.baseMapper.listUnMarkTaskStudent(page, examId, paperNumber,
                 groupNumber);
@@ -830,44 +841,11 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
 
     /**
      * 客观题统分 统分场景: 1.后台-成绩检查-客观题检查 2.扫描端-考生图片上传 3.扫描端-客观题二次识别
-     *
-     * @param student
-     * @return
      */
-    @Override
-    public boolean saveUploadStudent(MarkStudent student) {
-        MarkStudent old = this.getById(student.getId());
-        if (!student.getAbsent()) {// 正考
-            MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(student.getExamId(),
-                    student.getPaperNumber());
-            if (markPaper.getStatus().equals(MarkPaperStatus.FINISH)) {
-                markPaperService.updateStatus(markPaper.getExamId(), markPaper.getPaperNumber(), MarkPaperStatus.FORMAL,
-                        MarkPaperStatus.FINISH);
-            }
-        }
-        calculateObjectiveScore(student);
-        if (student.getAbsent()) {// 转缺考
-            student.setObjectiveScore(null);
-            student.setObjectiveScoreList(null);
-        }
-        if (!old.getAbsent() && student.getAbsent()) {// 正考转缺考
-            student.setSubjectiveScore(null);
-            student.setSubjectiveScoreList(null);
-            student.setSubjectiveStatus(SubjectiveStatus.UNMARK);
-            this.updateById(student);
-        }
-        boolean success = this.updateScanInfo(student);
-        if (success) {
-            markPaperService.updateUploadCount(student.getExamId(), student.getPaperNumber(),
-                    this.countUploadedByExamIdAndPaperNumber(student.getExamId(), student.getPaperNumber()));
-        }
-        return success;
-    }
-
     @Override
     public void calculateObjectiveScore(MarkStudent student) {
         // 缺考状态不统分(人工指定缺考、识别缺考)
-        if (!ScanStatus.MANUAL_ABSENT.equals(student.getScanStatus()) && !student.getAbsent() && !student.getOmrAbsent()) {
+        if (!student.getManualAbsent() && !student.getAbsent() && !student.getOmrAbsent()) {
             ScoreCalculateUtil util = ScoreCalculateUtil.instance(student);
             ScoreInfo info = util.calculate(markQuestionService.listQuestionAnswerByExamIdAndPaperNumberAndPaperType(
                     student.getExamId(), student.getPaperNumber(), student.getPaperType(), true), null);
@@ -1101,7 +1079,7 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         LambdaUpdateWrapper<MarkStudent> lw = new LambdaUpdateWrapper<>();
         lw.set(MarkStudent::getScanStatus, status);
         lw.set(MarkStudent::getManualAbsent, ScanStatus.MANUAL_ABSENT.equals(status));
-        lw.set(MarkStudent::getAbsent, ScanStatus.MANUAL_ABSENT.equals(status));
+        lw.set(MarkStudent::getAbsent, student.getOmrAbsent() || ScanStatus.MANUAL_ABSENT.equals(status));
         lw.set(MarkStudent::getMissScan, false);
         lw.eq(MarkStudent::getId, student.getId());
         update(lw);
@@ -1434,7 +1412,7 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
             lambdaQueryWrapper.eq(MarkStudent::getSubjectiveStatus, status);
         }
         lambdaQueryWrapper.eq(MarkStudent::getUpload, true).eq(MarkStudent::getAbsent, false)
-                .eq(MarkStudent::getBreach, false).eq(MarkStudent::getOmrAbsent, false);
+                .eq(MarkStudent::getManualAbsent, false).eq(MarkStudent::getOmrAbsent, false);
         return this.count(queryWrapper);
     }
 
@@ -1456,7 +1434,8 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
     }
 
     @Override
-    public int countOmrAbsentStudent(Long examId, String paperNumber, boolean isOmrAbsentConfirm, String teachClassName) {
+    public int countOmrAbsentStudent(Long examId, String paperNumber, boolean isOmrAbsentConfirm, String
+            teachClassName) {
         return this.baseMapper.countOmrAbsentStudent(examId, paperNumber, isOmrAbsentConfirm, teachClassName);
     }
 
@@ -1558,7 +1537,8 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         return this.update(updateWrapper);
     }
 
-    private void fillObjective(ScoreReportVo ret, List<ArchiveStudentVo> studentList, Long examId, String paperNumber) {
+    private void fillObjective(ScoreReportVo ret, List<ArchiveStudentVo> studentList, Long examId, String
+            paperNumber) {
         List<MarkQuestion> qs = markQuestionService.listByExamIdAndPaperNumberAndObjective(examId, paperNumber, true);
         Map<String, List<ArchiveStudentVo>> collect = studentList.stream().filter(m -> StringUtils.isNotBlank(m.getPaperType())).collect(Collectors.groupingBy(ArchiveStudentVo::getPaperType));
 
@@ -1633,7 +1613,8 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
      * @param examId      考试id
      * @param paperNumber 试卷编号
      */
-    private void fillMainQuestionAnalysis(ScoreReportVo ret, List<ArchiveStudentVo> studentList, Long examId, String paperNumber) {
+    private void fillMainQuestionAnalysis(ScoreReportVo ret, List<ArchiveStudentVo> studentList, Long
+            examId, String paperNumber) {
         // 试卷结构数据
         Map<String, QuestionVo> mainQuestionMap = new HashMap<>();
 
@@ -1840,6 +1821,7 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
         markStudent.setExamId(examId);
         markStudent.setPaperNumber(paperNumber);
         markStudent.setScanStatus(ScanStatus.UNEXIST);
+        markStudent.setAbsent(false);
         markStudent.setMarkPaperStatus(MarkPaperStatus.FORMAL.name());
         return baseMapper.selectCountByQuery(markStudent, null);
     }
@@ -2025,7 +2007,8 @@ public class MarkStudentServiceImpl extends ServiceImpl<MarkStudentMapper, MarkS
     }
 
     @Override
-    public MarkStudent assembleByBasicExamStudent(BasicExamStudent basicExamStudent, MarkPaper markPaper, Set<String> secretNumberSet) {
+    public MarkStudent assembleByBasicExamStudent(BasicExamStudent basicExamStudent, MarkPaper
+            markPaper, Set<String> secretNumberSet) {
         MarkStudent markStudent = this.findByBasicStudentId(basicExamStudent.getId());
         if (markStudent == null) {
             if (MarkPaperStatus.FINISH.equals(markPaper.getStatus())) {

+ 4 - 4
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/MarkUserGroupServiceImpl.java

@@ -73,16 +73,16 @@ public class MarkUserGroupServiceImpl extends ServiceImpl<MarkUserGroupMapper, M
         for (MarkEntranceDto record : markEntranceDtoIPage.getRecords()) {
             int taskCount = record.getTaskCount();
             int markedCount = record.getMarkedCount();
-            MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, record.getPaperNumber());
+            MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(record.getExamId(), record.getPaperNumber());
             if (markPaper != null && markPaper.getOpenMarkClass() != null && markPaper.getOpenMarkClass()) {
-                List<MarkUserClass> markUserClassList = markUserClassService.listByExamIdAndPaperNumberAndUserId(examId, record.getPaperNumber(), sysUser.getId());
+                List<MarkUserClass> markUserClassList = markUserClassService.listByExamIdAndPaperNumberAndUserId(record.getExamId(), record.getPaperNumber(), sysUser.getId());
                 List<String> classNames = null;
                 if (CollectionUtils.isNotEmpty(markUserClassList)) {
                     classNames = markUserClassList.stream().map(MarkUserClass::getClassName).collect(Collectors.toList());
                 }
-                taskCount = markTaskService.countByExamIdAndPaperNumberAndGroupNumberAndUserIdAndAndClassNameStatusIn(examId, record.getPaperNumber(), record.getGroupNumber(), null, classNames);
+                taskCount = markTaskService.countByExamIdAndPaperNumberAndGroupNumberAndUserIdAndAndClassNameStatusIn(record.getExamId(), record.getPaperNumber(), record.getGroupNumber(), null, classNames);
                 record.setTaskCount(taskCount);
-                markedCount = markTaskService.countByExamIdAndPaperNumberAndGroupNumberAndUserIdAndAndClassNameStatusIn(examId, record.getPaperNumber(), record.getGroupNumber(), null, classNames, MarkTaskStatus.MARKED, MarkTaskStatus.ARBITRATED);
+                markedCount = markTaskService.countByExamIdAndPaperNumberAndGroupNumberAndUserIdAndAndClassNameStatusIn(record.getExamId(), record.getPaperNumber(), record.getGroupNumber(), null, classNames, MarkTaskStatus.MARKED, MarkTaskStatus.ARBITRATED);
                 record.setMarkedCount(markedCount);
             }
             record.setLeftCount(taskCount == 0 ? 0 : taskCount - markedCount);

+ 54 - 0
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanAnswerCardQuestionServiceImpl.java

@@ -0,0 +1,54 @@
+package com.qmth.teachcloud.mark.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.qmth.teachcloud.mark.entity.ScanAnswerCardQuestion;
+import com.qmth.teachcloud.mark.mapper.ScanAnswerCardQuestionMapper;
+import com.qmth.teachcloud.mark.service.ScanAnswerCardQuestionService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 卡格式题型 服务实现类
+ * </p>
+ *
+ * @author xf
+ * @since 2024-11-13
+ */
+@Service
+public class ScanAnswerCardQuestionServiceImpl extends ServiceImpl<ScanAnswerCardQuestionMapper, ScanAnswerCardQuestion> implements ScanAnswerCardQuestionService {
+
+    @Override
+    public void deleteByExamIdAndPaperNumberAndCardNumber(Long examId, String paperNumber, Integer number) {
+        UpdateWrapper<ScanAnswerCardQuestion> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.lambda().eq(ScanAnswerCardQuestion::getExamId, examId)
+                .eq(ScanAnswerCardQuestion::getPaperNumber, paperNumber)
+                .eq(ScanAnswerCardQuestion::getCardNumber, number);
+        this.remove(updateWrapper);
+    }
+
+    @Override
+    public List<ScanAnswerCardQuestion> listByExamIdAndPaperNumberAndCardNumberAndPaperIndexAndPageIndex(Long examId, String paperNumber, Integer cardNumber, Integer paperIndex, Integer pageIndex) {
+        QueryWrapper<ScanAnswerCardQuestion> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ScanAnswerCardQuestion::getExamId, examId)
+                .eq(ScanAnswerCardQuestion::getPaperNumber, paperNumber)
+                .eq(ScanAnswerCardQuestion::getCardNumber, cardNumber)
+                .eq(ScanAnswerCardQuestion::getPaperIndex, paperIndex)
+                .eq(ScanAnswerCardQuestion::getPageIndex, pageIndex)
+                .orderByAsc(ScanAnswerCardQuestion::getMainNumber, ScanAnswerCardQuestion::getSubNumber);
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public List<ScanAnswerCardQuestion> listByExamIdAndPaperNumberAndCardNumber(Long examId, String paperNumber, Integer number) {
+        QueryWrapper<ScanAnswerCardQuestion> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ScanAnswerCardQuestion::getExamId, examId)
+                .eq(ScanAnswerCardQuestion::getPaperNumber, paperNumber)
+                .eq(ScanAnswerCardQuestion::getCardNumber, number)
+                .orderByAsc(ScanAnswerCardQuestion::getMainNumber, ScanAnswerCardQuestion::getSubNumber);
+        return this.list(queryWrapper);
+    }
+}

+ 22 - 37
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanAnswerCardServiceImpl.java

@@ -13,7 +13,6 @@ import com.qmth.teachcloud.common.bean.marking.scanAnswerCard.AnswerCard;
 import com.qmth.teachcloud.common.bean.marking.scanAnswerCard.AnswerCardPage;
 import com.qmth.teachcloud.common.bean.vo.FilePathVo;
 import com.qmth.teachcloud.common.contant.SystemConstant;
-import com.qmth.teachcloud.common.entity.MarkQuestion;
 import com.qmth.teachcloud.common.entity.SysUser;
 import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
 import com.qmth.teachcloud.common.enums.scan.OmrField;
@@ -24,8 +23,8 @@ import com.qmth.teachcloud.common.util.ServletUtil;
 import com.qmth.teachcloud.mark.bean.UriVo;
 import com.qmth.teachcloud.mark.bean.answercard.*;
 import com.qmth.teachcloud.mark.entity.MarkPaper;
-import com.qmth.teachcloud.mark.entity.MarkQuestionAnswer;
 import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
+import com.qmth.teachcloud.mark.entity.ScanAnswerCardQuestion;
 import com.qmth.teachcloud.mark.enums.CardSource;
 import com.qmth.teachcloud.mark.mapper.ScanAnswerCardMapper;
 import com.qmth.teachcloud.mark.service.*;
@@ -64,9 +63,7 @@ public class ScanAnswerCardServiceImpl extends ServiceImpl<ScanAnswerCardMapper,
     @Resource
     private MarkStudentService markStudentService;
     @Resource
-    private MarkQuestionService markQuestionService;
-    @Resource
-    private MarkQuestionAnswerService markQuestionAnswerService;
+    private ScanAnswerCardQuestionService scanAnswerCardQuestionService;
     @Resource
     private BasicRoleDataPermissionService basicRoleDataPermissionService;
     @Resource
@@ -173,61 +170,49 @@ public class ScanAnswerCardServiceImpl extends ServiceImpl<ScanAnswerCardMapper,
         card.setAdapteUri(filePath);
         this.saveOrUpdate(card);
 
-        saveObjectiveStruct(domain.getExamId(), domain.getCoursePaperId(), domain.getFile());
+        saveScanAnswerCardQuestion(domain.getExamId(), domain.getCoursePaperId(), domain.getFile(), card.getNumber());
         return card;
     }
 
     /**
      * 根据卡格式中的结构,更新客观题试卷结构
      */
-    private void saveObjectiveStruct(Long examId, String coursePaperId, MultipartFile file) {
+    private void saveScanAnswerCardQuestion(Long examId, String coursePaperId, MultipartFile file, Integer number) {
         MarkPaper markPaper = markPaperService.getByExamIdAndCoursePaperId(examId, coursePaperId);
         CardFile cardFile;
         byte[] fileData;
-        String sliceConfig;
         try {
             fileData = file.getBytes();
             // 解析卡格式文件
             cardFile = parseCardFile(fileData);
-            List<MarkQuestion> markQuestions = new ArrayList<>();
-            List<MarkQuestionAnswer> markQuestionAnswers = new ArrayList<>();
+            List<ScanAnswerCardQuestion> scanAnswerCardQuestions = new ArrayList<>();
             int i = 1;
             for (CardPageWrapper page : cardFile.getPages()) {
                 for (FillArea fillArea : page.getExchange().getFillArea().stream().filter(m -> OmrField.QUESTION.equals(m.getField())).collect(Collectors.toList())) {
                     for (FillItem item : fillArea.getItems()) {
-                        MarkQuestion markQuestion = new MarkQuestion();
-                        markQuestion.setId(SystemConstant.getDbUuid());
-                        markQuestion.setExamId(examId);
-                        markQuestion.setPaperNumber(markPaper.getPaperNumber());
-                        markQuestion.setObjective(fillArea.isSingle());
-                        markQuestion.setMainNumber(item.getMainNumber());
-                        markQuestion.setSubNumber(item.getSubNumber());
-                        markQuestion.setMainTitle(fillArea.isSingle() ? item.getOptions().size() == 2 ? "判断题" : "单选题" : "多选题");
-                        markQuestion.setOptionCount(item.getOptions().size());
-                        markQuestion.setQuestionType(fillArea.isSingle() ? item.getOptions().size() == 2 ? 3 : 1 : 2);
-                        markQuestion.setPaperIndex(i / 2);
-                        markQuestion.setPageIndex(i % 2 == 1 ? 1 : 2);
-                        markQuestions.add(markQuestion);
-
-                        // 保存客观题数据
-                        for (String paperType : markPaper.getPaperTypeList()) {
-                            MarkQuestionAnswer markQuestionAnswer = new MarkQuestionAnswer(examId, markQuestion.getPaperNumber(), paperType, markQuestion.getMainNumber(), markQuestion.getSubNumber());
-                            markQuestionAnswers.add(markQuestionAnswer);
-                        }
+                        ScanAnswerCardQuestion scanAnswerCardQuestion = new ScanAnswerCardQuestion();
+                        scanAnswerCardQuestion.setId(SystemConstant.getDbUuid());
+                        scanAnswerCardQuestion.setExamId(examId);
+                        scanAnswerCardQuestion.setPaperNumber(markPaper.getPaperNumber());
+                        scanAnswerCardQuestion.setCoursePaperId(coursePaperId);
+                        scanAnswerCardQuestion.setCardNumber(number);
+                        scanAnswerCardQuestion.setMainNumber(item.getMainNumber());
+                        scanAnswerCardQuestion.setSubNumber(item.getSubNumber());
+                        scanAnswerCardQuestion.setOptionCount(item.getOptions().size());
+                        scanAnswerCardQuestion.setQuestionType(fillArea.isSingle() ? 1 : 2);
+                        scanAnswerCardQuestion.setPaperIndex(i / 2);
+                        scanAnswerCardQuestion.setPageIndex(i % 2 == 1 ? 1 : 2);
+                        scanAnswerCardQuestion.setCreateTime(System.currentTimeMillis());
+                        scanAnswerCardQuestions.add(scanAnswerCardQuestion);
                     }
                 }
                 i++;
             }
 
-            if (CollectionUtils.isNotEmpty(markQuestions)) {
+            if (CollectionUtils.isNotEmpty(scanAnswerCardQuestions)) {
                 // 删除
-                markQuestionService.deleteByExamIdAndPaperNumberAndObjective(examId, markPaper.getPaperNumber(), true);
-                markQuestionService.saveBatch(markQuestions);
-            }
-            if (CollectionUtils.isNotEmpty(markQuestionAnswers)) {
-                // 删除客观题标答
-                markQuestionAnswerService.deleteByExamIdAndPaperNumber(examId, markPaper.getPaperNumber());
-                markQuestionAnswerService.saveBatch(markQuestionAnswers);
+                scanAnswerCardQuestionService.deleteByExamIdAndPaperNumberAndCardNumber(examId, markPaper.getPaperNumber(), number);
+                scanAnswerCardQuestionService.saveBatch(scanAnswerCardQuestions);
             }
         } catch (IOException e) {
             throw new ParameterException("文件解析失败", e);

+ 5 - 5
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/ScanOmrTaskServiceImpl.java

@@ -70,7 +70,7 @@ public class ScanOmrTaskServiceImpl extends ServiceImpl<ScanOmrTaskMapper, ScanO
     private ConcurrentService concurrentService;
 
     @Autowired
-    private MarkQuestionService questionService;
+    private ScanAnswerCardQuestionService scanAnswerCardQuestionService;
 
     @Resource
     private MarkPaperService markPaperService;
@@ -240,9 +240,9 @@ public class ScanOmrTaskServiceImpl extends ServiceImpl<ScanOmrTaskMapper, ScanO
 //                    }
 //                }
                 if (ConditionType.QUESTION_SINGLE_EXCEED.equals(c) && ScanStatus.SCANNED.equals(student.getScanStatus())) {
-                    List<MarkQuestion> questiongList = questionService
-                            .listByExamIdAndPaperNumberAndPaperIndexAndPageIndex(student.getExamId(),
-                                    student.getPaperNumber(), spe.getPaperIndex(), pageEntity.getPageIndex(), true);
+                    List<ScanAnswerCardQuestion> questiongList = scanAnswerCardQuestionService
+                            .listByExamIdAndPaperNumberAndCardNumberAndPaperIndexAndPageIndex(student.getExamId(),
+                                    student.getPaperNumber(), student.getCardNumber(), spe.getPaperIndex(), pageEntity.getPageIndex());
                     if (pageEntity.getQuestion() == null || pageEntity.getQuestion().getResult() == null
                             || questiongList.isEmpty()) {
                         continue;
@@ -251,7 +251,7 @@ public class ScanOmrTaskServiceImpl extends ServiceImpl<ScanOmrTaskMapper, ScanO
                             : pageEntity.getQuestion().getResult().size();
                     for (int i = 0; i < size; i++) {
                         String result = pageEntity.getQuestion().getResult().get(i);
-                        MarkQuestion question = questiongList.get(i);
+                        ScanAnswerCardQuestion question = questiongList.get(i);
                         String newStr = result.replace(OMR_SUSPECT, "");
                         if ((question.getQuestionType().equals(QuestionType.SINGLE.getValue()) || question.getQuestionType().equals(QuestionType.TRUE_OR_FALSE.getValue()))
                                 && result != null

+ 42 - 1
teachcloud-mark/src/main/java/com/qmth/teachcloud/mark/service/impl/TaskServiceImpl.java

@@ -1,9 +1,11 @@
 package com.qmth.teachcloud.mark.service.impl;
 
 import java.util.*;
+import java.util.stream.Collectors;
 
 import javax.annotation.Resource;
 
+import com.qmth.teachcloud.common.contant.SystemConstant;
 import com.qmth.teachcloud.mark.dto.mark.MarkStudentVo;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -133,7 +135,6 @@ public class TaskServiceImpl implements TaskService {
             List<MarkTask> markTaskList = markTaskService.listByStudentIdAndGroupNumber(markStudent.getId(), question.getGroupNumber());
             // 仲裁轨迹
             List<MarkHeaderTrack> headerTracks = markHeaderTrackService.listByStudentIdAndQuestionNumber(markStudent.getId(), questionNumber);
-            List<String> questionList = new ArrayList<>();
             Map<Long, String> userNameMap = new HashMap<>();
             // 不管单评还是多评显示所有评卷员给分轨迹
             for (MarkTask markTask : markTaskList) {
@@ -150,7 +151,47 @@ public class TaskServiceImpl implements TaskService {
                     }
                     step.addTrack(replaceTrackFromHeaderTrack(track, headerTracks, userNameMap));
                 }
+
+                // 普通模式无轨迹数据。单独处理评卷员每题得分
+                if (CollectionUtils.isEmpty(tracks) && StringUtils.isNotBlank(markTask.getMarkerScoreList())) {
+                    List<String> questionNumberList = sList.stream().filter(m -> m.getGroupNumber() == markTask.getGroupNumber()).map(m -> m.getQuestionNumber()).collect(Collectors.toList());
+                    int index = questionNumberList.indexOf(questionNumber);
+
+                    // 评卷员
+                    String[] scoreLists = markTask.getMarkerScoreList().split(SystemConstant.COMMA);
+                    if (scoreLists.length >= index) {
+                        MarkerScoreDTO markerScoreDTO = new MarkerScoreDTO();
+                        markerScoreDTO.setUserId(markTask.getUserId());
+                        SysUser sysUser = sysUserService.getByUserId(markTask.getUserId());
+                        if (sysUser != null) {
+                            markerScoreDTO.setLoginName(sysUser.getLoginName());
+                            markerScoreDTO.setUserName(sysUser.getRealName());
+                        }
+                        markerScoreDTO.setScore(Double.parseDouble(scoreLists[index]));
+                        markerScoreDTO.setHeader(false);
+                        step.addMarkerList(markerScoreDTO);
+                    }
+                    // 科组长
+                    if(StringUtils.isNotBlank(markTask.getHeaderScoreList())) {
+                        String[] headerScoreLists = markTask.getHeaderScoreList().split(SystemConstant.COMMA);
+                        if (headerScoreLists.length >= index) {
+                            if(Double.parseDouble(scoreLists[index]) != Double.parseDouble(headerScoreLists[index])) {
+                                MarkerScoreDTO markerScoreDTO = new MarkerScoreDTO();
+                                markerScoreDTO.setUserId(markTask.getHeaderId());
+                                SysUser sysUser = sysUserService.getByUserId(markTask.getHeaderId());
+                                if (sysUser != null) {
+                                    markerScoreDTO.setLoginName(sysUser.getLoginName());
+                                    markerScoreDTO.setUserName(sysUser.getRealName());
+                                }
+                                markerScoreDTO.setScore(Double.parseDouble(headerScoreLists[index]));
+                                markerScoreDTO.setHeader(true);
+                                step.addMarkerList(markerScoreDTO);
+                            }
+                        }
+                    }
+                }
             }
+
             for (MarkHeaderTrack headerTrack : headerTracks) {
                 TrackDTO trackDTO = new TrackDTO(headerTrack);
                 SysUser sysUser = sysUserService.getByUserId(headerTrack.getUserId());

+ 10 - 0
teachcloud-mark/src/main/resources/mapper/MarkStudentMapper.xml

@@ -71,6 +71,7 @@
         ms.subjective_status subjectiveStatus,
         ms.is_absent absent,
         ms.omr_absent omrAbsent,
+        ms.is_manual_absent manualAbsent,
         ms.is_upload upload,
         bes.status studentStatus,
         ms.is_breach breach,
@@ -304,6 +305,9 @@
         <if test="query.omrAbsentChecked != null">
             and t.omr_absent_checked=#{query.omrAbsentChecked}
         </if>
+        <if test="query.manualAbsent != null">
+            and t.is_manual_absent=#{query.manualAbsent}
+        </if>
         <if test="query.assigned != null">
             and t.assigned=#{query.assigned}
         </if>
@@ -334,6 +338,9 @@
         <if test="query.omrBreach != null">
             and t.omr_breach = #{query.omrBreach}
         </if>
+        <if test="query.manualBreach != null">
+            and t.is_manual_absent = #{query.manualBreach}
+        </if>
         <if test="dpr != null and dpr.requestUserId != null">
             AND t.create_id = #{dpr.requestUserId}
         </if>
@@ -732,6 +739,9 @@
             <if test="markStudent.scanStatus != null">
                 and ms.scan_status = #{markStudent.scanStatus}
             </if>
+            <if test="markStudent.manualAbsent != null">
+                and ms.is_manual_absent = #{markStudent.manualAbsent}
+            </if>
             <if test="markStudent.omrAbsent != null">
                 and ms.omr_absent = #{markStudent.omrAbsent}
             </if>

+ 25 - 0
teachcloud-mark/src/main/resources/mapper/ScanAnswerCardQuestionMapper.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qmth.teachcloud.mark.mapper.ScanAnswerCardQuestionMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.qmth.teachcloud.mark.entity.ScanAnswerCardQuestion">
+        <id column="id" property="id" />
+        <result column="exam_id" property="examId" />
+        <result column="paper_number" property="paperNumber" />
+        <result column="course_paper_id" property="coursePaperId" />
+        <result column="serial_number" property="serialNumber" />
+        <result column="card_number" property="cardNumber" />
+        <result column="main_number" property="mainNumber" />
+        <result column="sub_number" property="subNumber" />
+        <result column="main_title" property="mainTitle" />
+        <result column="question_type" property="questionType" />
+        <result column="paper_index" property="paperIndex" />
+        <result column="page_index" property="pageIndex" />
+        <result column="create_id" property="createId" />
+        <result column="create_time" property="createTime" />
+        <result column="update_id" property="updateId" />
+        <result column="update_time" property="updateTime" />
+    </resultMap>
+
+</mapper>

+ 4 - 1
teachcloud-task/src/main/java/com/qmth/teachcloud/task/service/PrintFinishService.java

@@ -3,6 +3,7 @@ package com.qmth.teachcloud.task.service;
 import com.qmth.distributed.print.business.bean.dto.initMarkData.ExamDetailCourseInitMarkDto;
 import com.qmth.distributed.print.business.entity.BasicCardRule;
 import com.qmth.teachcloud.common.bean.vo.PaperInfoVo;
+import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
 
 import java.util.List;
 
@@ -17,7 +18,7 @@ public interface PrintFinishService {
 
     void insertScanAnswerCardAndMarkQuestion(ExamDetailCourseInitMarkDto dto);
 
-    void insertScanAnswerCard(ExamDetailCourseInitMarkDto dto, String cardId, String content);
+    ScanAnswerCard insertScanAnswerCard(ExamDetailCourseInitMarkDto dto, String cardId, String content);
 
     void insertMarkQuestion(Long examId, String paperNumber, String content);
 
@@ -26,4 +27,6 @@ public interface PrintFinishService {
     void insertMarkPaperPackageCode(ExamDetailCourseInitMarkDto dto);
 
     void updateMarkSheetConfig(ExamDetailCourseInitMarkDto dto, String content);
+
+    void insertScanAnswerCardQuestion(Long examId, String paperNumber, String content, Integer number);
 }

+ 50 - 5
teachcloud-task/src/main/java/com/qmth/teachcloud/task/service/impl/PrintFinishServiceImpl.java

@@ -77,6 +77,8 @@ public class PrintFinishServiceImpl implements PrintFinishService {
     private FileStoreUtils fileStoreUtils;
     @Resource
     private MarkFileService markFileService;
+    @Resource
+    private ScanAnswerCardQuestionService scanAnswerCardQuestionService;
 
     /**
      * 打印结束后,生成阅卷科目数据
@@ -161,24 +163,28 @@ public class PrintFinishServiceImpl implements PrintFinishService {
                 // 解析卡格式中试卷结构并保存
                 this.insertMarkQuestion(dto.getExamId(), dto.getPaperNumber(), examCard.getContent());
                 // 生成并保存卡格式文件(后缀为.json)
-                this.insertScanAnswerCard(dto, cardId, examCard.getContent());
+                ScanAnswerCard scanAnswerCard = this.insertScanAnswerCard(dto, cardId, examCard.getContent());
+                if (scanAnswerCard != null) {
+                    this.insertScanAnswerCardQuestion(dto.getExamId(), dto.getPaperNumber(), examCard.getContent(), scanAnswerCard.getNumber());
+                }
                 // 题库获取的试卷,同步标答文件
                 if (examCard.getPaperId() != null) {
                     this.insertPaperAnswerFile(dto.getExamId(), dto.getPaperNumber(), dto.getSerialNumber(), examCard.getPaperId());
                 }
                 // 自动保存题卡遮盖区
                 this.updateMarkSheetConfig(dto, examCard.getContent());
+
             }
         }
     }
 
     @Override
-    public void insertScanAnswerCard(ExamDetailCourseInitMarkDto dto, String cardId, String content) {
+    public ScanAnswerCard insertScanAnswerCard(ExamDetailCourseInitMarkDto dto, String cardId, String content) {
         ExamCard examCard = examCardService.getById(cardId);
         if (examCard != null) {
             ScanAnswerCard scanAnswerCard = scanAnswerCardService.getByExamIdAndCoursePaperIdAndSerialNumberAndCardId(dto.getExamId(), dto.getCoursePaperId(), dto.getSerialNumber(), Long.valueOf(cardId));
             if (scanAnswerCard != null) {
-                return;
+                return scanAnswerCard;
             }
 
             File tempFile = SystemConstant.getFileTempDirVar(System.currentTimeMillis() + File.separator + SystemConstant.getNanoId(), SystemConstant.TEMP_PREFIX);
@@ -233,9 +239,9 @@ public class PrintFinishServiceImpl implements PrintFinishService {
                     }
                 }
             }
-
-
+            return scanAnswerCard;
         }
+        return null;
     }
 
     @Transactional
@@ -333,4 +339,43 @@ public class PrintFinishServiceImpl implements PrintFinishService {
             markPaperService.update(updateWrapper);
         }
     }
+
+    @Override
+    public void insertScanAnswerCardQuestion(Long examId, String paperNumber, String content, Integer number) {
+        try {
+            List<Struct> structList = CardParseUtils.parseCardContent(content);
+            if (CollectionUtils.isEmpty(structList)) {
+                return;
+            }
+            List<ScanAnswerCardQuestion> scanAnswerCardQuestionList = scanAnswerCardQuestionService.listByExamIdAndPaperNumberAndCardNumber(examId, paperNumber, number);
+            // 第一次新增
+            if (CollectionUtils.isEmpty(scanAnswerCardQuestionList)) {
+                MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumber(examId, paperNumber);
+                List<ScanAnswerCardQuestion> scanAnswerCardQuestions = new ArrayList<>();
+                for (Struct struct : structList) {
+                    if (!struct.getObjective()) {
+                        continue;
+                    }
+                    ScanAnswerCardQuestion scanAnswerCardQuestion = new ScanAnswerCardQuestion();
+                    scanAnswerCardQuestion.setId(SystemConstant.getDbUuid());
+                    scanAnswerCardQuestion.setExamId(examId);
+                    scanAnswerCardQuestion.setPaperNumber(paperNumber);
+                    scanAnswerCardQuestion.setCoursePaperId(markPaper.getCoursePaperId());
+                    scanAnswerCardQuestion.setCardNumber(number);
+                    scanAnswerCardQuestion.setMainNumber(struct.getMainNumber());
+                    scanAnswerCardQuestion.setSubNumber(struct.getSubNumber());
+                    scanAnswerCardQuestion.setOptionCount(struct.getOptionCount());
+                    scanAnswerCardQuestion.setQuestionType(struct.getType());
+                    scanAnswerCardQuestion.setPaperIndex(struct.getPaperIndex());
+                    scanAnswerCardQuestion.setPageIndex(struct.getPageIndex());
+                    scanAnswerCardQuestion.setCreateTime(System.currentTimeMillis());
+                    scanAnswerCardQuestions.add(scanAnswerCardQuestion);
+                }
+                scanAnswerCardQuestionService.deleteByExamIdAndPaperNumberAndCardNumber(examId, paperNumber, number);
+                scanAnswerCardQuestionService.saveBatch(scanAnswerCardQuestions);
+            }
+        } catch (Exception e) {
+            log.info("同步卡格式结构失败");
+        }
+    }
 }