瀏覽代碼

增加eb_mark_group_student表和eb_subjective_score表;
eb_exam_student表增加subjective_status字段;
修改主观题统分为自动统分

luoshi 4 年之前
父節點
當前提交
2b844ebd8c
共有 35 個文件被更改,包括 816 次插入205 次删除
  1. 18 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamStudentDao.java
  2. 0 8
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamSubjectDao.java
  3. 3 3
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkGroupDao.java
  4. 45 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkGroupStudentDao.java
  5. 40 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/SubjectiveScoreDao.java
  6. 15 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamStudent.java
  7. 0 30
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamSubject.java
  8. 84 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroupStudent.java
  9. 65 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroupStudentPK.java
  10. 118 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/SubjectiveScore.java
  11. 82 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/SubjectiveScorePK.java
  12. 13 4
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/ExamStudentSearchQuery.java
  13. 10 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamStudentService.java
  14. 0 4
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamSubjectService.java
  15. 1 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamQuestionServiceImpl.java
  16. 20 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamStudentServiceImpl.java
  17. 0 18
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamSubjectServiceImpl.java
  18. 13 15
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkLibraryDao.java
  19. 187 54
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkServiceImpl.java
  20. 1 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkService.java
  21. 9 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/ScoreItem.java
  22. 4 3
      stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/LockType.java
  23. 25 0
      stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/SubjectiveStatus.java
  24. 2 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ArbitrateController.java
  25. 2 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/LibraryController.java
  26. 4 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkGroupController.java
  27. 28 47
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkerController.java
  28. 1 3
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/PaperController.java
  29. 2 2
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ScoreController.java
  30. 3 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/StudentController.java
  31. 2 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/DataSyncThread.java
  32. 3 5
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/ScoreCalculateThread.java
  33. 2 0
      stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/CoreController.java
  34. 12 0
      stmms-web/src/main/java/cn/com/qmth/stmms/common/controller/BaseController.java
  35. 2 0
      stmms-web/src/main/java/cn/com/qmth/stmms/mark/MarkController.java

+ 18 - 2
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamStudentDao.java

@@ -1,6 +1,7 @@
 package cn.com.qmth.stmms.biz.exam.dao;
 
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
@@ -26,6 +27,10 @@ public interface ExamStudentDao
 
     public List<ExamStudent> findByExamIdAndSecretNumber(int examId, String secretNumber);
 
+    @Query("select s.id from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.subjectiveStatus in (?3)")
+    public List<Integer> findIdByExamIdAndSubjectCodeAndSubjectiveStatus(Integer examId, String subjectCode,
+            SubjectiveStatus... status);
+
     @Query("select count(s) from ExamStudent s where s.examId=?1 and s.subjectCode=?2 "
             + "and s.upload=true and s.absent=false and s.breach=false")
     public long countUploaded(Integer examId, String subjectCode);
@@ -59,8 +64,19 @@ public interface ExamStudentDao
     public List<String> findDistinctPackageCode(int examId);
 
     @Modifying
-    @Query("update ExamStudent s set s.subjectiveScore=?2, s.subjectiveScoreList=?3 where s.id=?1")
-    public void updateSubjectiveScore(int id, double score, String scoreList);
+    @Query("update ExamStudent s set s.subjectiveStatus=?2, s.subjectiveScore=?3, s.subjectiveScoreList=?4 where s.id=?1")
+    public void updateSubjectiveStatusAndScore(Integer id, SubjectiveStatus status, double score, String scoreList);
+
+    @Modifying
+    @Query("update ExamStudent s set s.subjectiveStatus=?3, s.subjectiveScore=?4, s.subjectiveScoreList=?5 where s.examId=?1 and s.subjectCode=?2")
+    public void updateSubjectiveStatusAndScore(Integer examId, String subjetCode, SubjectiveStatus status, double score,
+            String scoreList);
+
+    @Modifying
+    @Query("update ExamStudent s set s.subjectiveStatus=?3 where s.examId=?1 and s.subjectCode=?2 and not exists "
+            + "(select g.pk.studentId from MarkGroupStudent g where g.pk.studentId=s.id and g.status!=?4)")
+    public void updateSubjectiveStatusFromGroupStatus(Integer examId, String subjetCode, SubjectiveStatus status,
+            SubjectiveStatus groupStatus);
 
     @Modifying
     @Query("update ExamStudent s set s.objectiveScore=?2, s.objectiveScoreList=?3 where s.id=?1")

+ 0 - 8
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamSubjectDao.java

@@ -34,14 +34,6 @@ public interface ExamSubjectDao
     @Query("select s from ExamSubject s where s.pk.examId=?1 and s.uploadCount>?2")
     public List<ExamSubject> findByExamIdAndUploadCountGt(int examId, int uploadCount);
 
-    @Modifying
-    @Query("update ExamSubject s set s.needCalculate=?3 where s.pk.examId=?1 and s.pk.code=?2")
-    public int updateNeedCalculate(int examId, String code, boolean needCalculate);
-
-    @Modifying
-    @Query("update ExamSubject s set s.calculateProgress=?3 where s.pk.examId=?1 and s.pk.code=?2")
-    public int updateCalculateProgress(Integer examId, String subjectCode, Double progress);
-
     @Modifying
     @Query("update ExamSubject s set s.totalScore=s.objectiveScore+s.subjectiveScore where s.pk.examId=?1")
     public void updateTotalScoreByExamId(int examId);

+ 3 - 3
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkGroupDao.java

@@ -31,9 +31,6 @@ public interface MarkGroupDao
     @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.status in (?2)")
     long countByExamIdAndStatus(Integer examId, MarkStatus... status);
 
-    @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2")
-    long countByExamIdAndSubjectCode(Integer examId, String subjectCode);
-
     @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 "
             + "and q.pk.number=?3 and q.status in (?4)")
     long countByExamIdAndSubjectCodeAndNumberAndStatus(Integer examId, String subjectCode, Integer groupNumber,
@@ -60,6 +57,9 @@ public interface MarkGroupDao
     @Query("select count(q) from MarkGroup q where q.pk.examId=?1")
     long countByExamId(Integer examId);
 
+    @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2")
+    long countByExamIdAndSubjectCode(Integer examId, String subjectCode);
+
     @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.pk.number=?3 "
             + "and q.status=?4 and q.trialCount>q.libraryCount")
     long countByStatusAndTrailCount(Integer examId, String subjectCode, Integer number, MarkStatus status);

+ 45 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkGroupStudentDao.java

@@ -0,0 +1,45 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import cn.com.qmth.stmms.biz.exam.model.MarkGroupStudent;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroupStudentPK;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import java.util.List;
+
+public interface MarkGroupStudentDao extends PagingAndSortingRepository<MarkGroupStudent, MarkGroupStudentPK> {
+
+    @Query("select s from MarkGroupStudent s where s.pk.studentId=?1 and s.pk.groupNumber=?2")
+    MarkGroupStudent findByStudentIdAndGroupNumber(Integer studentId, Integer groupNumber);
+
+    @Query("select s.pk.studentId from MarkGroupStudent s where "
+            + "s.examId=?1 and s.subjectCode=?2 and s.pk.groupNumber=?3 and s.status=?4")
+    List<Integer> findStudentIdByGroupNumberAndStatus(Integer examId, String subjectCode, Integer groupNumber,
+            SubjectiveStatus status);
+
+    @Query("select count(s) from MarkGroupStudent s where s.pk.studentId=?1 and s.status=?2")
+    long countByStudentIdAndStatus(Integer studentId, SubjectiveStatus status);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete MarkGroupStudent s where s.pk.studentId=?1")
+    void deleteByStudentId(Integer studentId);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete MarkGroupStudent s where s.examId=?1 and s.subjectCode=?2 and s.pk.groupNumber=?3")
+    void deleteByExamIdAndSubjectCodeAndGroupNumber(Integer examId, String subjectCode, Integer groupNumber);
+
+    @Modifying(clearAutomatically = true)
+    @Query("update MarkGroupStudent s set s.status=?4 where s.examId=?1 and s.subjectCode=?2 and s.pk.groupNumber=?3")
+    void updateStatusByExamIdAndSubjectCodeAndGroupNumber(Integer examId, String subjectCode, Integer groupNumber,
+            SubjectiveStatus status);
+
+    @Modifying(clearAutomatically = true)
+    @Query("update MarkGroupStudent s set s.status=?4 where s.examId=?1 and s.subjectCode=?2 and s.groupNumber=?3 and exists "
+            + "(select l.id from MarkLibrary l where l.studentId=s.pk.studentId and l.groupNumber=s.groupNumber and l.status in (?5))")
+    void updateStatusByMarkLibraryStatus(Integer examId, String subjectCode, Integer groupNumber,
+            SubjectiveStatus status, LibraryStatus... libraryStatus);
+
+}

+ 40 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/SubjectiveScoreDao.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import cn.com.qmth.stmms.biz.exam.model.SubjectiveScore;
+import cn.com.qmth.stmms.biz.exam.model.SubjectiveScorePK;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import java.util.List;
+
+public interface SubjectiveScoreDao extends PagingAndSortingRepository<SubjectiveScore, SubjectiveScorePK> {
+
+    @Query("select s from SubjectiveScore s where s.pk.studentId=?1 order by s.pk.mainNumber, s.pk.subNumber")
+    List<SubjectiveScore> findByStudentId(Integer studentId);
+
+    @Query("select s from SubjectiveScore s where s.pk.studentId=?1 and s.groupNumber=?2 order by s.pk.mainNumber, s.pk.subNumber")
+    List<SubjectiveScore> findByStudentIdAndGroupNumber(Integer studentId, Integer groupNumber);
+
+    @Query("select s from SubjectiveScore s where s.pk.studentId=?1 and s.pk.mainNumber=?2 and s.pk.subNumber=?3")
+    SubjectiveScore findByStudentIdAndMainNumberAndSubNumber(Integer studentId, Integer mainNumber, Integer subNumber);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete SubjectiveScore s where s.pk.studentId=?1")
+    void deleteByStudentId(Integer studentId);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete SubjectiveScore s where s.pk.studentId=?1 and s.groupNumber=?2")
+    void deleteByStudentIdAndGroupNumber(Integer studentId, Integer groupNumber);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete SubjectiveScore s where s.examId=?1 and s.subjectCode=?2 and s.groupNumber=?3")
+    void deleteByExamIdAndSubjectCodeAndGroupNumber(Integer examId, String subjectCode, Integer groupNumber);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete SubjectiveScore s where s.examId=?1 and s.subjectCode=?2 and s.groupNumber=?3 and not exists "
+            + "(select g.studentId from MarkGroupStudent g where g.pk.studentId=s.pk.studentId and g.status=?4)")
+    void deleteByStudentGroupStatus(Integer examId, String subjectCode, Integer groupNumber, SubjectiveStatus status);
+
+}

+ 15 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamStudent.java

@@ -3,6 +3,7 @@ package cn.com.qmth.stmms.biz.exam.model;
 import cn.com.qmth.stmms.biz.mark.model.ProblemType;
 import cn.com.qmth.stmms.biz.utils.ScoreItem;
 import cn.com.qmth.stmms.common.annotation.ExcelField;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.math.RandomUtils;
 
@@ -202,6 +203,12 @@ public class ExamStudent implements Serializable {
     @Column(name = "objective_score_list", nullable = true, columnDefinition = "text")
     private String objectiveScoreList;
 
+    /**
+     * 主观题状态
+     */
+    @Column(name = "subjective_status", length = 16, nullable = false)
+    private SubjectiveStatus subjectiveStatus;
+
     /**
      * 主观总分
      */
@@ -767,6 +774,14 @@ public class ExamStudent implements Serializable {
         this.problemType = problemType;
     }
 
+    public SubjectiveStatus getSubjectiveStatus() {
+        return subjectiveStatus;
+    }
+
+    public void setSubjectiveStatus(SubjectiveStatus subjectiveStatus) {
+        this.subjectiveStatus = subjectiveStatus;
+    }
+
     public String getSecretNumber() {
         return secretNumber;
     }

+ 0 - 30
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamSubject.java

@@ -4,11 +4,9 @@ import cn.com.qmth.stmms.biz.file.enums.FormatType;
 import cn.com.qmth.stmms.biz.file.service.FileService;
 import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
 import net.sf.json.JSONObject;
-
 import org.apache.commons.lang.StringUtils;
 
 import javax.persistence.*;
-
 import java.io.Serializable;
 import java.util.List;
 
@@ -48,18 +46,6 @@ public class ExamSubject implements Serializable {
     @Column(name = "remark")
     private String remark;
 
-    /**
-     * 是否需要统分
-     */
-    @Column(name = "need_calculate", nullable = false)
-    private boolean needCalculate;
-
-    /**
-     * 是否需要统分
-     */
-    @Column(name = "calculate_progress", nullable = true)
-    private Double calculateProgress;
-
     /**
      * 裁切图配置
      */
@@ -220,14 +206,6 @@ public class ExamSubject implements Serializable {
         this.groupCount = groupCount;
     }
 
-    public boolean isNeedCalculate() {
-        return needCalculate;
-    }
-
-    public void setNeedCalculate(boolean needCalculate) {
-        this.needCalculate = needCalculate;
-    }
-
     public String getSliceConfig() {
         return sliceConfig;
     }
@@ -252,14 +230,6 @@ public class ExamSubject implements Serializable {
         return PictureConfigItem.parse(sheetConfig);
     }
 
-    public Double getCalculateProgress() {
-        return calculateProgress;
-    }
-
-    public void setCalculateProgress(Double calculateProgress) {
-        this.calculateProgress = calculateProgress;
-    }
-
     public FormatType getCardType() {
         return cardType;
     }

+ 84 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroupStudent.java

@@ -0,0 +1,84 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * 每个考生每个评卷分组状态
+ */
+@Entity
+@Table(name = "eb_mark_group_student")
+public class MarkGroupStudent implements Serializable {
+
+    private static final long serialVersionUID = 2701810699367970775L;
+
+    @EmbeddedId
+    private MarkGroupStudentPK pk;
+
+    /**
+     * 考试ID
+     */
+    @Column(name = "exam_id", nullable = false)
+    private Integer examId;
+
+    /**
+     * 科目代码
+     */
+    @Column(name = "subject_code", length = 32, nullable = false)
+    private String subjectCode;
+
+    /**
+     * 状态
+     */
+    @Column(name = "status", length = 16, nullable = false)
+    private SubjectiveStatus status;
+
+    public MarkGroupStudent() {
+        this.pk = new MarkGroupStudentPK();
+    }
+
+    public Integer getStudentId() {
+        return pk.getStudentId();
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.pk.setStudentId(studentId);
+    }
+
+    public Integer getGroupNumber() {
+        return pk.getGroupNumber();
+    }
+
+    public void setGroupNumber(Integer groupNumber) {
+        this.pk.setGroupNumber(groupNumber);
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public SubjectiveStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(SubjectiveStatus status) {
+        this.status = status;
+    }
+}

+ 65 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroupStudentPK.java

@@ -0,0 +1,65 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import java.io.Serializable;
+
+@Embeddable
+public class MarkGroupStudentPK implements Serializable {
+
+    private static final long serialVersionUID = 5274946877418574003L;
+
+    @Column(name = "student_id", nullable = false)
+    private Integer studentId;
+
+    @Column(name = "group_number", nullable = false)
+    private Integer groupNumber;
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public Integer getGroupNumber() {
+        return groupNumber;
+    }
+
+    public void setGroupNumber(Integer groupNumber) {
+        this.groupNumber = groupNumber;
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((studentId == null) ? 0 : studentId.hashCode());
+        result = PRIME * result + ((groupNumber == null) ? 0 : groupNumber.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final MarkGroupStudentPK other = (MarkGroupStudentPK) obj;
+        if (studentId == null) {
+            if (other.studentId != null)
+                return false;
+        } else if (!studentId.equals(other.studentId))
+            return false;
+        if (groupNumber == null) {
+            if (other.groupNumber != null)
+                return false;
+        } else if (!groupNumber.equals(other.groupNumber))
+            return false;
+        return true;
+    }
+
+}

+ 118 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/SubjectiveScore.java

@@ -0,0 +1,118 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * 主观题得分详情状态
+ */
+@Entity
+@Table(name = "eb_subjective_score")
+public class SubjectiveScore implements Serializable {
+
+    private static final long serialVersionUID = 6637010422161820147L;
+
+    @EmbeddedId
+    private SubjectiveScorePK pk;
+
+    /**
+     * 考试ID
+     */
+    @Column(name = "exam_id", nullable = false)
+    private Integer examId;
+
+    /**
+     * 科目代码
+     */
+    @Column(name = "subject_code", length = 32, nullable = false)
+    private String subjectCode;
+
+    /**
+     * 分组序号
+     */
+    @Column(name = "group_number", nullable = false)
+    private Integer groupNumber;
+
+    /**
+     * 分组总分
+     */
+    @Column(name = "group_score", nullable = false)
+    private Double groupScore;
+
+    /**
+     * 小题得分
+     */
+    @Column(name = "score", nullable = false)
+    private Double score;
+
+    public SubjectiveScore() {
+        this.pk = new SubjectiveScorePK();
+    }
+
+    public Integer getStudentId() {
+        return pk.getStudentId();
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.pk.setStudentId(studentId);
+    }
+
+    public Integer getMainNumber() {
+        return pk.getMainNumber();
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        this.pk.setMainNumber(mainNumber);
+    }
+
+    public Integer getSubNumber() {
+        return pk.getSubNumber();
+    }
+
+    public void setSubNumber(Integer subNumber) {
+        this.pk.setSubNumber(subNumber);
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Integer getGroupNumber() {
+        return groupNumber;
+    }
+
+    public void setGroupNumber(Integer groupNumber) {
+        this.groupNumber = groupNumber;
+    }
+
+    public Double getGroupScore() {
+        return groupScore;
+    }
+
+    public void setGroupScore(Double groupScore) {
+        this.groupScore = groupScore;
+    }
+
+    public Double getScore() {
+        return score;
+    }
+
+    public void setScore(Double score) {
+        this.score = score;
+    }
+}

+ 82 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/SubjectiveScorePK.java

@@ -0,0 +1,82 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import java.io.Serializable;
+
+@Embeddable
+public class SubjectiveScorePK implements Serializable {
+
+    private static final long serialVersionUID = 7186961625210327765L;
+
+    @Column(name = "student_id", nullable = false)
+    private Integer studentId;
+
+    @Column(name = "main_number", nullable = false)
+    private Integer mainNumber;
+
+    @Column(name = "sub_number", nullable = false)
+    private Integer subNumber;
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    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;
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((studentId == null) ? 0 : studentId.hashCode());
+        result = PRIME * result + ((mainNumber == null) ? 0 : mainNumber.hashCode());
+        result = PRIME * result + ((subNumber == null) ? 0 : subNumber.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final SubjectiveScorePK other = (SubjectiveScorePK) obj;
+        if (studentId == null) {
+            if (other.studentId != null)
+                return false;
+        } else if (!studentId.equals(other.studentId))
+            return false;
+        if (mainNumber == null) {
+            if (other.mainNumber != null)
+                return false;
+        } else if (!mainNumber.equals(other.mainNumber))
+            return false;
+        if (subNumber == null) {
+            if (other.subNumber != null)
+                return false;
+        } else if (!subNumber.equals(other.subNumber))
+            return false;
+        return true;
+    }
+
+}

+ 13 - 4
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/ExamStudentSearchQuery.java

@@ -1,12 +1,12 @@
 package cn.com.qmth.stmms.biz.exam.query;
 
-import java.util.Date;
-
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import org.springframework.data.domain.Sort;
 import org.springframework.data.domain.Sort.Direction;
 
-import cn.com.qmth.stmms.biz.common.BaseQuery;
-import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import java.util.Date;
 
 public class ExamStudentSearchQuery extends BaseQuery<ExamStudent> {
 
@@ -38,6 +38,8 @@ public class ExamStudentSearchQuery extends BaseQuery<ExamStudent> {
 
     private Double objectiveScoreLt;
 
+    private SubjectiveStatus subjectiveStatus;
+
     private Double subjectiveScore;
 
     private Double subjectiveScoreGt;
@@ -374,4 +376,11 @@ public class ExamStudentSearchQuery extends BaseQuery<ExamStudent> {
         this.paperType = paperType;
     }
 
+    public SubjectiveStatus getSubjectiveStatus() {
+        return subjectiveStatus;
+    }
+
+    public void setSubjectiveStatus(SubjectiveStatus subjectiveStatus) {
+        this.subjectiveStatus = subjectiveStatus;
+    }
 }

+ 10 - 2
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamStudentService.java

@@ -6,6 +6,7 @@ import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
 import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
 import cn.com.qmth.stmms.biz.utils.OriginTag;
 import cn.com.qmth.stmms.biz.utils.PictureTag;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 
 import java.util.Date;
 import java.util.List;
@@ -62,7 +63,10 @@ public interface ExamStudentService {
 
     void updateSubjectInfo(ExamSubject subject);
 
-    void updateSubjectiveScore(int id, double score, String scoreList);
+    void updateSubjectiveStatusAndScore(Integer examId, String subjectCode, SubjectiveStatus status, double score,
+            String scoreList);
+
+    void updateSubjectiveStatusAndScore(Integer id, SubjectiveStatus status, double score, String scoreList);
 
     void updateObjectiveScore(int id, double score, String scoreList);
 
@@ -97,7 +101,8 @@ public interface ExamStudentService {
     public Long countByExamIdAndSubjectCodeAndCampus(Integer examId, String code, String campusName, boolean upload,
             boolean absent);
 
-    public long countByNoAbsentAndBreach(int examId, String subjectCode, boolean upload, boolean absent, boolean breach);
+    public long countByNoAbsentAndBreach(int examId, String subjectCode, boolean upload, boolean absent,
+            boolean breach);
 
     public long countByAbsentAndBreach(int examId, String subjectCode, Boolean absent, Boolean breach);
 
@@ -109,6 +114,9 @@ public interface ExamStudentService {
 
     List<ExamStudent> findByExamIdAndSubjectCode(int examId, String subjectCode, int pageNumber, int pageSize);
 
+    List<Integer> findIdByExamIdAndSubjectCodeAndSubjectiveStatus(Integer examId, String subjectCode,
+            SubjectiveStatus... status);
+
     List<PictureTag> buildSheetTags(ExamStudent student, int index);
 
     Map<Integer, List<PictureTag>> buildSheetTags(ExamStudent student);

+ 0 - 4
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamSubjectService.java

@@ -35,10 +35,6 @@ public interface ExamSubjectService {
 
     List<String> listCategory(int examId);
 
-    boolean updateNeedCalculate(int examId, String code, boolean needCalculate);
-
-    boolean updateCalculateProgress(int examId, String code, Double progress);
-
     void updateUploadCount(Integer examId, String subjectCode, int count);
 
     void updateTotalScore(int examId);

+ 1 - 2
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamQuestionServiceImpl.java

@@ -184,8 +184,7 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
         ExamQuestion question = questionDao.findOne(questionId);
         question.setObjectivePolicy(objectivePolicy);
         questionDao.save(question);
-        // 修改后需要重新统分
-        subjectService.updateNeedCalculate(question.getExamId(), question.getSubjectCode(), true);
+        // TODO - 修改后需要重新统分
         return question;
     }
 

+ 20 - 2
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamStudentServiceImpl.java

@@ -16,6 +16,7 @@ import cn.com.qmth.stmms.biz.utils.OriginTag;
 import cn.com.qmth.stmms.biz.utils.PictureConfigTransform;
 import cn.com.qmth.stmms.biz.utils.PictureTag;
 import cn.com.qmth.stmms.biz.utils.ScoreItem;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.math.RandomUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -416,8 +417,15 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
 
     @Override
     @Transactional
-    public void updateSubjectiveScore(int id, double score, String scoreList) {
-        studentDao.updateSubjectiveScore(id, score, scoreList);
+    public void updateSubjectiveStatusAndScore(Integer examId, String subjectCode, SubjectiveStatus status,
+            double score, String scoreList) {
+        studentDao.updateSubjectiveStatusAndScore(examId, subjectCode, status, score, scoreList);
+    }
+
+    @Override
+    @Transactional
+    public void updateSubjectiveStatusAndScore(Integer id, SubjectiveStatus status, double score, String scoreList) {
+        studentDao.updateSubjectiveStatusAndScore(id, status, score, scoreList);
     }
 
     @Override
@@ -515,6 +523,10 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
                     predicates
                             .add(cb.lessThan(root.get("objectiveScore").as(Double.class), query.getObjectiveScoreLt()));
                 }
+                if (query.getSubjectiveStatus() != null) {
+                    predicates.add(cb.equal(root.get("subjectiveStatus").as(SubjectiveStatus.class),
+                            query.getSubjectiveStatus()));
+                }
                 if (query.getSubjectiveScore() != null) {
                     predicates.add(cb.equal(root.get("subjectiveScore"), query.getSubjectiveScore()));
                 } else if (query.getSubjectiveScoreGt() != null) {
@@ -640,6 +652,12 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
         return studentDao.findByExamIdAndSubjectCodeAndUploadTimeNotNull(examId, code);
     }
 
+    @Override
+    public List<Integer> findIdByExamIdAndSubjectCodeAndSubjectiveStatus(Integer examId, String subjectCode,
+            SubjectiveStatus... status) {
+        return studentDao.findIdByExamIdAndSubjectCodeAndSubjectiveStatus(examId, subjectCode, status);
+    }
+
     @Override
     public ExamStudent findByExamIdAndSubjectCodeAndUploadTimeAfter(int examId, String code, Date date) {
         ExamStudentSearchQuery query = new ExamStudentSearchQuery();

+ 0 - 18
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamSubjectServiceImpl.java

@@ -103,24 +103,6 @@ public class ExamSubjectServiceImpl extends BaseQueryService<ExamSubject> implem
         subjectDao.deleteByExamId(examId);
     }
 
-    @Transactional
-    @Override
-    // @CacheEvict(value = "exam_subject_cache", key =
-    // "T(String).valueOf(#subject.examId)+'-'+#subject.code", condition =
-    // "#subject!=null && #subject.examId!=null && #subject.code!=null")
-    public boolean updateNeedCalculate(int examId, String code, boolean needCalculate) {
-        return subjectDao.updateNeedCalculate(examId, code, needCalculate) > 0;
-    }
-
-    @Transactional
-    @Override
-    // @CacheEvict(value = "exam_subject_cache", key =
-    // "T(String).valueOf(#subject.examId)+'-'+#subject.code", condition =
-    // "#subject!=null && #subject.examId!=null && #subject.code!=null")
-    public boolean updateCalculateProgress(int examId, String code, Double progress) {
-        return subjectDao.updateCalculateProgress(examId, code, progress) > 0;
-    }
-
     @Transactional
     @Override
     // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,

+ 13 - 15
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkLibraryDao.java

@@ -1,17 +1,16 @@
 package cn.com.qmth.stmms.biz.mark.dao;
 
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-
+import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 
-import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
-import cn.com.qmth.stmms.common.enums.LibraryStatus;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
 
 public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, JpaSpecificationExecutor<MarkLibrary> {
 
@@ -31,8 +30,8 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
     @Query("select l1 from MarkLibrary l1 where l1.examId=?1 and l1.subjectCode=?2 and l1.groupNumber=?3 and l1.status in (?6) "
             + "and not exists (select l2 from MarkLibrary l2 where l2.studentId=l1.studentId and l2.id!=l1.id and l2.markerId=?4) "
             + "and exists (select mc.id from MarkerClass mc, ExamStudent s where l1.studentId=s.id and mc.userId=?5 and s.className=mc.className)")
-    List<MarkLibrary> findUnMarkedFilterClass(Integer examId, String subjectCode, Integer groupNumber,
-            Integer markerId, Integer userId, Set<LibraryStatus> statusSet, Pageable page);
+    List<MarkLibrary> findUnMarkedFilterClass(Integer examId, String subjectCode, Integer groupNumber, Integer markerId,
+            Integer userId, Set<LibraryStatus> statusSet, Pageable page);
 
     List<MarkLibrary> findByMarkerId(Integer markerId);
 
@@ -51,8 +50,8 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
     long countByExamIdAndSubjectCodeAndGroupNumber(Integer examId, String subjectCode, Integer groupNumber);
 
     @Query("select count(f) from MarkLibrary f where f.examId=?1 and f.subjectCode=?2 and f.groupNumber=?3 and f.taskNumber=?4")
-    long countByExamIdAndSubjectCodeAndGroupNumberAndTaskNumber(Integer examId, String subjectCode,
-            Integer groupNumber, Integer taskNumber);
+    long countByExamIdAndSubjectCodeAndGroupNumberAndTaskNumber(Integer examId, String subjectCode, Integer groupNumber,
+            Integer taskNumber);
 
     @Query("select count(f) from MarkLibrary f where f.examId=?1 and f.subjectCode=?2 and f.groupNumber=?3 and f.status in (?4)")
     long countByExamIdAndSubjectCodeAndGroupNumberAndStatus(Integer examId, String subjectCode, Integer groupNumber,
@@ -75,9 +74,8 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
 
     @Modifying(clearAutomatically = true)
     @Query("update MarkLibrary m set m.status=?2, m.markerId=null, m.markerTime=null, m.markerScore=null, m.markerScoreList=null, m.markerSpent=null, "
-            + "m.headerId=null , m.headerTime=null , m.headerScore=null , m.headerScoreList=null  where m.markerId=?1 and m.status!=?3 and m.status not in (?4) ")
-    void resetByMarkerId(Integer markerId, LibraryStatus status, LibraryStatus libraryStatus1,
-            LibraryStatus... libraryStatus);
+            + "m.headerId=null , m.headerTime=null , m.headerScore=null , m.headerScoreList=null where m.markerId=?1 and m.status not in (?4) ")
+    void resetByMarkerId(Integer markerId, LibraryStatus status, LibraryStatus... notInStatus);
 
     @Modifying(clearAutomatically = true)
     @Query("update MarkLibrary m set m.status=?2, m.markerId=null, m.markerTime=null, m.markerScore=null, m.markerScoreList=null, m.markerSpent=null, "
@@ -107,8 +105,8 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
     @Modifying(clearAutomatically = true)
     @Query("update MarkLibrary m set m.headerId=?3, m.headerScore=?4, m.headerScoreList=?5, m.headerTime=?6, m.status=?7 "
             + " where m.studentId=?1 and m.groupNumber=?2")
-    void updateHeaderResult(Integer studentId, Integer groupNumber, Integer userId, Double totalScore,
-            String scoreList, Date updateTime, LibraryStatus arbitrated);
+    void updateHeaderResult(Integer studentId, Integer groupNumber, Integer userId, Double totalScore, String scoreList,
+            Date updateTime, LibraryStatus arbitrated);
 
     @Modifying(clearAutomatically = true)
     @Query("update MarkLibrary m set m.status=?3 where m.studentId=?1 and m.groupNumber=?2")

+ 187 - 54
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkServiceImpl.java

@@ -1,8 +1,6 @@
 package cn.com.qmth.stmms.biz.mark.service.Impl;
 
-import cn.com.qmth.stmms.biz.exam.dao.ExamQuestionDao;
-import cn.com.qmth.stmms.biz.exam.dao.MarkGroupDao;
-import cn.com.qmth.stmms.biz.exam.dao.MarkerDao;
+import cn.com.qmth.stmms.biz.exam.dao.*;
 import cn.com.qmth.stmms.biz.exam.model.*;
 import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
 import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
@@ -23,7 +21,10 @@ import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -45,6 +46,12 @@ public class MarkServiceImpl implements MarkService {
     @Autowired
     private MarkGroupDao groupDao;
 
+    @Autowired
+    private MarkGroupStudentDao groupStudentDao;
+
+    @Autowired
+    private SubjectiveScoreDao scoreDao;
+
     @Autowired
     private ExamQuestionDao questionDao;
 
@@ -202,14 +209,25 @@ public class MarkServiceImpl implements MarkService {
         // 小题数据
         questionDao.deleteByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                 false, group.getNumber());
-
+        // 考生分组状态与得分明细
+        groupStudentDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
+                group.getNumber());
+        scoreDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
+                group.getNumber());
+        // 删除分组
         releaseByGroup(group);
         groupDao.delete(group);
         // 科目总分
         subjectService.updateScore(group.getExamId(), group.getSubjectCode(), false,
                 sumTotalScore(group.getExamId(), group.getSubjectCode()));
-        // 需要重新统分
-        subjectService.updateNeedCalculate(group.getExamId(), group.getSubjectCode(), true);
+        // 考生整体状态与总分更新
+        long groupCount = groupDao.countByExamIdAndSubjectCode(group.getExamId(), group.getSubjectCode());
+        List<Integer> studentList = studentService
+                .findIdByExamIdAndSubjectCodeAndSubjectiveStatus(group.getExamId(), group.getSubjectCode(),
+                        SubjectiveStatus.MARKED, SubjectiveStatus.INSPECTED);
+        for (Integer studentId : studentList) {
+            checkStudentSubjective(studentId, groupCount);
+        }
     }
 
     /**
@@ -342,6 +360,13 @@ public class MarkServiceImpl implements MarkService {
                     LibraryStatus.PROBLEM);
             libraryDao.resetByMarkerId(marker.getId(), LibraryStatus.WAITING, LibraryStatus.ARBITRATED,
                     LibraryStatus.WAIT_ARBITRATE, LibraryStatus.PROBLEM);
+            // 只选取评卷完成状态的记录重新检查
+            List<Integer> studentIdList = groupStudentDao
+                    .findStudentIdByGroupNumberAndStatus(marker.getExamId(), marker.getSubjectCode(),
+                            marker.getGroupNumber(), SubjectiveStatus.MARKED);
+            for (Integer studentId : studentIdList) {
+                checkStudentGroup(studentId, group);
+            }
             markerDao.resetById(marker.getId());
         } else if (group.getStatus() == MarkStatus.TRIAL) {
             trialTagDao.deleteByMarkerId(marker.getId());
@@ -371,7 +396,9 @@ public class MarkServiceImpl implements MarkService {
         trialTagDao.deleteByStudentId(student.getId());
         trialHistoryDao.deleteByStudentId(student.getId());
         trialLibraryDao.deleteByStudentId(student.getId());
-
+        //主观状态与得分明细
+        groupStudentDao.deleteByStudentId(student.getId());
+        scoreDao.deleteByStudentId(student.getId());
         updateAllCount(student.getExamId(), student.getSubjectCode());
     }
 
@@ -503,9 +530,7 @@ public class MarkServiceImpl implements MarkService {
         // 保存阅卷轨迹
         if (result.getTrackList() != null) {
             trackDao.deleteByLibraryId(library.getId());
-            for (MarkTrack t : result.getTrackList(library, marker)) {
-                trackDao.saveAndFlush(t);
-            }
+            trackDao.save(result.getTrackList(library, marker));
         }
         // 保存特殊标记
         if (result.getTagList() != null) {
@@ -535,11 +560,11 @@ public class MarkServiceImpl implements MarkService {
                             // 两两比较,触发仲裁
                             List<MarkLibrary> libraries = libraryDao
                                     .findByStudentIdAndGroupNumber(library.getStudentId(), library.getGroupNumber());
-                            history = getArbitrate(libraries, group.getArbitrateThreshold(), now);
+                            history = buildArbitrateHistory(libraries, group.getArbitrateThreshold(), now);
                         }
                     } else {
                         // 未开启三评,触发仲裁
-                        history = getArbitrate(library, now);
+                        history = buildArbitrateHistory(library, now);
                         break;
                     }
                 }
@@ -551,11 +576,14 @@ public class MarkServiceImpl implements MarkService {
             // 触发仲裁后续状态更新
             libraryDao.updateByStudentIdAndGroupNumber(library.getStudentId(), library.getGroupNumber(),
                     LibraryStatus.WAIT_ARBITRATE);
+        } else {
+            // 判断当前分组是否已完成评卷
+            checkStudentGroup(library.getStudentId(), group);
         }
         return true;
     }
 
-    private ArbitrateHistory getArbitrate(List<MarkLibrary> list, Double arbitrateThreshold, Date now) {
+    private ArbitrateHistory buildArbitrateHistory(List<MarkLibrary> list, Double arbitrateThreshold, Date now) {
         for (MarkLibrary library : list) {
             if (library.getStatus() != LibraryStatus.MARKED && library.getStatus() != LibraryStatus.INSPECTED
                     && library.getStatus() != LibraryStatus.ARBITRATED) {
@@ -573,12 +601,12 @@ public class MarkServiceImpl implements MarkService {
             }
         }
         if (count == list.size()) {
-            return getArbitrate(list.get(0), now);
+            return buildArbitrateHistory(list.get(0), now);
         }
         return null;
     }
 
-    private ArbitrateHistory getArbitrate(MarkLibrary library, Date now) {
+    private ArbitrateHistory buildArbitrateHistory(MarkLibrary library, Date now) {
         ArbitrateHistory history = new ArbitrateHistory();
         history.setExamId(library.getExamId());
         history.setSubjectCode(library.getSubjectCode());
@@ -622,6 +650,8 @@ public class MarkServiceImpl implements MarkService {
                 LibraryStatus.PROBLEM) > 0) {
             trackDao.deleteByLibraryId(library.getId());
             specialTagDao.deleteByLibraryId(library.getId());
+            resetStudentGroup(library.getStudentId(), library.getExamId(), library.getSubjectCode(),
+                    library.getGroupNumber());
             updateMarkedCount(library.getExamId(), library.getSubjectCode(), library.getGroupNumber());
             problemHistoryService.resetByLibraryId(library.getId(), userId);
             return true;
@@ -661,43 +691,57 @@ public class MarkServiceImpl implements MarkService {
             libraryDao.updateHeaderResult(history.getStudentId(), history.getGroupNumber(), history.getUserId(),
                     history.getTotalScore(), history.getScoreList(), history.getUpdateTime(), LibraryStatus.ARBITRATED);
             updateMarkedCount(history.getExamId(), history.getSubjectCode(), history.getGroupNumber());
-            scoreCalculate(studentService.findById(history.getStudentId()),
-                    groupDao.findByExamIdAndSubjectCode(history.getExamId(), history.getSubjectCode()));
+            checkStudentGroup(history.getStudentId(),
+                    groupDao.findOne(history.getExamId(), history.getSubjectCode(), history.getGroupNumber()));
         }
     }
 
-    /**
-     * 对某个考生某个科目进行主观题统分
-     *
-     * @param student - 考生
-     * @param groups  - 所有评卷分组
-     */
-    @Override
-    @Transactional
-    public void scoreCalculate(ExamStudent student, List<MarkGroup> groups) {
-        if (student == null || groups == null || groups.isEmpty()) {
-            return;
-        }
+    //    /**
+    //     * 对某个考生某个科目进行主观题统分
+    //     *
+    //     * @param student - 考生
+    //     * @param groups  - 所有评卷分组
+    //     */
+    //    @Override
+    //    @Transactional
+    //    public void scoreCalculate(ExamStudent student, List<MarkGroup> groups) {
+    //        if (student == null || groups == null || groups.isEmpty()) {
+    //            return;
+    //        }
+    //        List<ScoreItem> scoreList = new ArrayList<>();
+    //        double totalScore = 0.0;
+    //        // 循环所有评卷分组
+    //        for (MarkGroup group : groups) {
+    //            if (group.getStatus().equals(MarkStatus.TRIAL)) {
+    //                return;
+    //            }
+    //            if (calculateGroup(group, student.getId())) {
+    //                totalScore += group.getMarkScore();
+    //                scoreList.addAll(group.getMarkScoreDetail());
+    //            } else {
+    //                // 未评完直接返回
+    //                return;
+    //            }
+    //        }
+    //        // 全部评完,更新考生主观题得分
+    //        student.setSubjectiveScore(totalScore);
+    //        student.setScoreList(scoreList, false);
+    //        studentService
+    //                .updateSubjectiveScore(student.getId(), student.getSubjectiveScore(), student.getSubjectiveScoreList());
+    //    }
+
+    private void scoreCalculate(Integer studentId) {
         List<ScoreItem> scoreList = new ArrayList<>();
         double totalScore = 0.0;
-        // 循环所有评卷分组
-        for (MarkGroup group : groups) {
-            if (group.getStatus().equals(MarkStatus.TRIAL)) {
-                return;
-            }
-            if (calculateGroup(group, student.getId())) {
-                totalScore += group.getMarkScore();
-                scoreList.addAll(group.getMarkScoreDetail());
-            } else {
-                // 未评完直接返回
-                return;
-            }
+        // 循环所有主观得分明细
+        List<SubjectiveScore> list = scoreDao.findByStudentId(studentId);
+        for (SubjectiveScore ss : list) {
+            totalScore += ss.getScore();
+            scoreList.add(new ScoreItem(ss));
         }
         // 全部评完,更新考生主观题得分
-        student.setSubjectiveScore(totalScore);
-        student.setScoreList(scoreList, false);
-        studentService
-                .updateSubjectiveScore(student.getId(), student.getSubjectiveScore(), student.getSubjectiveScoreList());
+        studentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.MARKED, totalScore,
+                ExamStudent.buildScoreList(scoreList));
     }
 
     private boolean calculateGroup(MarkGroup group, Integer studentId) {
@@ -722,15 +766,11 @@ public class MarkServiceImpl implements MarkService {
             // Collections.sort(list,
             // Comparator.comparing(MarkLibrary::getMarkerScore));
             // 从小到大排序
-            list.sort(new Comparator<MarkLibrary>() {
-
-                @Override
-                public int compare(MarkLibrary o1, MarkLibrary o2) {
-                    if (o1.getMarkerScore() - o2.getMarkerScore() > 0) {
-                        return 1;
-                    }
-                    return -1;
+            list.sort((o1, o2) -> {
+                if (o1.getMarkerScore() - o2.getMarkerScore() > 0) {
+                    return 1;
                 }
+                return -1;
             });
             Double score1 =
                     list.get(0).getHeaderScore() != null ? list.get(0).getHeaderScore() : list.get(0).getMarkerScore();
@@ -987,6 +1027,7 @@ public class MarkServiceImpl implements MarkService {
                             group.getNumber(), 3);
             markerDao.resetByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                     group.getNumber());
+            resetStudentGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
         } else if (group.getStatus() == MarkStatus.TRIAL) {
             trialTrackDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                     group.getNumber());
@@ -1066,4 +1107,96 @@ public class MarkServiceImpl implements MarkService {
         return false;
     }
 
+    /**
+     * 考生判断是否主观题全部评卷完成
+     *
+     * @param studentId
+     */
+    private void checkStudentSubjective(Integer studentId, long groupCount) {
+        if (groupStudentDao.countByStudentIdAndStatus(studentId, SubjectiveStatus.MARKED) == groupCount) {
+            scoreCalculate(studentId);
+        } else {
+            studentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK, 0, null);
+        }
+    }
+
+    /**
+     * 考生分组判断是否评卷完成,以及后续的统一处理动作
+     *
+     * @param studentId
+     * @param group
+     */
+    private void checkStudentGroup(Integer studentId, MarkGroup group) {
+        if (calculateGroup(group, studentId)) {
+            updateStudentGroupStatus(studentId, group.getExamId(), group.getSubjectCode(), group.getNumber(),
+                    SubjectiveStatus.MARKED);
+            updateStudentGroupScore(studentId, group.getExamId(), group.getSubjectCode(), group.getNumber(),
+                    group.getMarkScore(), group.getMarkScoreDetail());
+            checkStudentSubjective(studentId,
+                    groupDao.countByExamIdAndSubjectCode(group.getExamId(), group.getSubjectCode()));
+        } else {
+            updateStudentGroupStatus(studentId, group.getExamId(), group.getSubjectCode(), group.getNumber(),
+                    SubjectiveStatus.UNMARK);
+            studentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK, 0, null);
+        }
+    }
+
+    /**
+     * 重置考生某个分组的评卷状态,以及整体的主观题状态
+     *
+     * @param studentId
+     * @param examId
+     * @param subjectCode
+     * @param groupNumber
+     */
+    private void resetStudentGroup(Integer studentId, Integer examId, String subjectCode, Integer groupNumber) {
+        updateStudentGroupStatus(studentId, examId, subjectCode, groupNumber, SubjectiveStatus.UNMARK);
+        scoreDao.deleteByStudentIdAndGroupNumber(studentId, groupNumber);
+        studentService.updateSubjectiveStatusAndScore(studentId, SubjectiveStatus.UNMARK, 0, null);
+    }
+
+    /**
+     * 重置某个分组所有考生的评卷状态,以及这些考生的主观题状态
+     *
+     * @param examId
+     * @param subjectCode
+     * @param groupNumber
+     */
+    private void resetStudentGroup(Integer examId, String subjectCode, Integer groupNumber) {
+        groupStudentDao.updateStatusByExamIdAndSubjectCodeAndGroupNumber(examId, subjectCode, groupNumber,
+                SubjectiveStatus.UNMARK);
+        scoreDao.deleteByExamIdAndSubjectCodeAndGroupNumber(examId, subjectCode, groupNumber);
+        studentService.updateSubjectiveStatusAndScore(examId, subjectCode, SubjectiveStatus.UNMARK, 0, null);
+    }
+
+    private void updateStudentGroupStatus(Integer studentId, Integer examId, String subjectCode, Integer groupNumber,
+            SubjectiveStatus status) {
+        MarkGroupStudent gs = new MarkGroupStudent();
+        gs.setStudentId(studentId);
+        gs.setExamId(examId);
+        gs.setSubjectCode(subjectCode);
+        gs.setGroupNumber(groupNumber);
+        gs.setStatus(status);
+        groupStudentDao.save(gs);
+    }
+
+    private void updateStudentGroupScore(Integer studentId, Integer examId, String subjectCode, Integer groupNumber,
+            double score, List<ScoreItem> scoreList) {
+        //scoreDao.deleteByStudentIdAndGroupNumber(studentId, groupNumber);
+        List<SubjectiveScore> list = new ArrayList<>();
+        for (ScoreItem item : scoreList) {
+            SubjectiveScore ss = new SubjectiveScore();
+            ss.setStudentId(studentId);
+            ss.setExamId(examId);
+            ss.setSubjectCode(subjectCode);
+            ss.setGroupNumber(groupNumber);
+            ss.setGroupScore(score);
+            ss.setMainNumber(item.getMainNumber());
+            ss.setSubNumber(item.getSubNumber());
+            ss.setScore(item.getScore());
+            list.add(ss);
+        }
+        scoreDao.save(list);
+    }
+
 }

+ 1 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkService.java

@@ -119,7 +119,7 @@ public interface MarkService {
      * @param student
      * @param groups
      */
-    void scoreCalculate(ExamStudent student, List<MarkGroup> groups);
+    // void scoreCalculate(ExamStudent student, List<MarkGroup> groups);
 
     /**
      * 管理员/组长处理仲裁卷

+ 9 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/ScoreItem.java

@@ -1,5 +1,7 @@
 package cn.com.qmth.stmms.biz.utils;
 
+import cn.com.qmth.stmms.biz.exam.model.SubjectiveScore;
+
 import java.text.DecimalFormat;
 
 public class ScoreItem {
@@ -20,6 +22,13 @@ public class ScoreItem {
 
     private boolean objective;
 
+    public ScoreItem(SubjectiveScore ss) {
+        this.objective = false;
+        this.mainNumber = ss.getMainNumber();
+        this.subNumber = ss.getSubNumber();
+        this.score = ss.getScore();
+    }
+
     public ScoreItem(boolean objective) {
         this.objective = objective;
     }

+ 4 - 3
stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/LockType.java

@@ -1,9 +1,10 @@
 package cn.com.qmth.stmms.common.enums;
 
 public enum LockType {
-    GROUP("group"), STUDENT("student"), MARKER("marker"), USER("user"), FORMAL_LIBRARY("formal_library"), TRIAL_LIBRARY(
-            "trial_library"), ARBITRATE("arbitrate"), BATCH_QUALITY("batch_quality"), SAVE_SHEET("save_sheet"), SCORE_CALCULATE(
-            "score_calculate"), GROUP_LIBRARY("group_library"), DATA_SYNC("data_sync");
+    EXAM_SUBJECT("exam_subject"), GROUP("group"), STUDENT("student"), MARKER("marker"), USER("user"), FORMAL_LIBRARY(
+            "formal_library"), TRIAL_LIBRARY("trial_library"), ARBITRATE("arbitrate"), BATCH_QUALITY(
+            "batch_quality"), SCORE_CALCULATE("score_calculate"), GROUP_LIBRARY("group_library"), DATA_SYNC(
+            "data_sync");
 
     private String name;
 

+ 25 - 0
stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/SubjectiveStatus.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.stmms.common.enums;
+
+public enum SubjectiveStatus {
+
+    UNMARK("未评完"), MARKED("已评完"), INSPECTED("已复核");
+
+    private String name;
+
+    private SubjectiveStatus(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public static SubjectiveStatus findByText(String text) {
+        for (SubjectiveStatus status : SubjectiveStatus.values()) {
+            if (status.name.equalsIgnoreCase(text)) {
+                return status;
+            }
+        }
+        return null;
+    }
+}

+ 2 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ArbitrateController.java

@@ -311,6 +311,7 @@ public class ArbitrateController extends BaseExamController {
         if (history != null && subjectCheck(history.getSubjectCode(), wu) && task.getTotalScore() >= 0
                 && task.getScoreList() != null) {
             try {
+                lockService.watch(LockType.EXAM_SUBJECT, history.getExamId(), history.getSubjectCode());
                 lockService
                         .watch(LockType.GROUP, history.getExamId(), history.getSubjectCode(), history.getGroupNumber());
 
@@ -329,6 +330,7 @@ public class ArbitrateController extends BaseExamController {
             } finally {
                 lockService.unwatch(LockType.GROUP, history.getExamId(), history.getSubjectCode(),
                         history.getGroupNumber());
+                lockService.unwatch(LockType.EXAM_SUBJECT, history.getExamId(), history.getSubjectCode());
             }
         } else {
             result.accumulate("success", false);

+ 2 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/LibraryController.java

@@ -130,6 +130,7 @@ public class LibraryController extends BaseExamController {
         if (library != null) {
             if (subjectCheck(library.getSubjectCode(), RequestUtils.getWebUser(request))) {
                 try {
+                    lockService.watch(LockType.EXAM_SUBJECT, library.getExamId(), library.getSubjectCode());
                     lockService.watch(LockType.GROUP, library.getExamId(), library.getSubjectCode(),
                             library.getGroupNumber());
                     if ((library.getStatus().equals(LibraryStatus.MARKED) || library.getStatus()
@@ -146,6 +147,7 @@ public class LibraryController extends BaseExamController {
                 } finally {
                     lockService.unwatch(LockType.GROUP, library.getExamId(), library.getSubjectCode(),
                             library.getGroupNumber());
+                    lockService.unwatch(LockType.EXAM_SUBJECT, library.getExamId(), library.getSubjectCode());
                 }
             } else {
                 obj.accumulate("success", false);

+ 4 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkGroupController.java

@@ -171,6 +171,7 @@ public class MarkGroupController extends BaseExamController {
             return "redirect:/admin/exam/mark";
         }
         try {
+            lockService.waitlock(LockType.EXAM_SUBJECT, group.getExamId(), group.getSubjectCode());
             lockService.waitlock(LockType.GROUP, group.getExamId(), group.getSubjectCode(), group.getNumber());
             markService.resetByGroup(group);
         } catch (Exception e) {
@@ -178,6 +179,7 @@ public class MarkGroupController extends BaseExamController {
             throw new RuntimeException("重置大题失败", e);
         } finally {
             lockService.unlock(LockType.GROUP, group.getExamId(), group.getSubjectCode(), group.getNumber());
+            lockService.unlock(LockType.EXAM_SUBJECT, group.getExamId(), group.getSubjectCode());
         }
 
         redirectAttributes.addAttribute("subjectCode", subjectCode);
@@ -330,6 +332,7 @@ public class MarkGroupController extends BaseExamController {
             return "redirect:/admin/exam/group";
         }
         try {
+            lockService.waitlock(LockType.EXAM_SUBJECT, group.getExamId(), group.getSubjectCode());
             lockService.waitlock(LockType.GROUP, group.getExamId(), group.getSubjectCode(), group.getNumber());
             markService.deleteGroup(group);
             RequestUtils.setLog(request, "删除成功,subjectCode:" + subjectCode + " number:" + number);
@@ -338,6 +341,7 @@ public class MarkGroupController extends BaseExamController {
             throw new RuntimeException("删除大题失败", e);
         } finally {
             lockService.unlock(LockType.GROUP, group.getExamId(), group.getSubjectCode(), group.getNumber());
+            lockService.unlock(LockType.EXAM_SUBJECT, group.getExamId(), group.getSubjectCode());
         }
 
         redirectAttributes.addAttribute("subjectCode", subjectCode);

+ 28 - 47
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkerController.java

@@ -1,44 +1,11 @@
 package cn.com.qmth.stmms.admin.exam;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import net.sf.json.JSONArray;
-import net.sf.json.JSONObject;
-
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.servlet.mvc.support.RedirectAttributes;
-
 import cn.com.qmth.stmms.biz.exam.model.Exam;
 import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
 import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
 import cn.com.qmth.stmms.biz.exam.model.Marker;
 import cn.com.qmth.stmms.biz.exam.query.MarkerSearchQuery;
-import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
-import cn.com.qmth.stmms.biz.exam.service.ExamService;
-import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
-import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
-import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
-import cn.com.qmth.stmms.biz.exam.service.MarkerClassService;
-import cn.com.qmth.stmms.biz.exam.service.MarkerService;
+import cn.com.qmth.stmms.biz.exam.service.*;
 import cn.com.qmth.stmms.biz.lock.LockService;
 import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
 import cn.com.qmth.stmms.biz.mark.service.MarkService;
@@ -48,17 +15,27 @@ import cn.com.qmth.stmms.biz.user.service.query.UserSearchQuery;
 import cn.com.qmth.stmms.common.annotation.Logging;
 import cn.com.qmth.stmms.common.annotation.RoleRequire;
 import cn.com.qmth.stmms.common.domain.WebUser;
-import cn.com.qmth.stmms.common.enums.LockType;
-import cn.com.qmth.stmms.common.enums.LogType;
-import cn.com.qmth.stmms.common.enums.MarkerExcelError;
-import cn.com.qmth.stmms.common.enums.Role;
-import cn.com.qmth.stmms.common.enums.UserSource;
+import cn.com.qmth.stmms.common.enums.*;
 import cn.com.qmth.stmms.common.utils.ExportExcel;
 import cn.com.qmth.stmms.common.utils.ImportExcel;
 import cn.com.qmth.stmms.common.utils.Md5EncryptUtils;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
-
 import com.google.common.collect.Lists;
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.*;
 
 @Controller("examMarkerController")
 @RequestMapping("/admin/exam/marker")
@@ -110,14 +87,16 @@ public class MarkerController extends BaseExamController {
         query.orderById();
         if (StringUtils.isNotBlank(query.getLoginName())) {
             User user = userService.findByLoginName(query.getLoginName());
-            query.setUserId(user != null && user.getSchoolId().equals(wu.getUser().getSchoolId()) ? user.getId() : null);
+            query.setUserId(
+                    user != null && user.getSchoolId().equals(wu.getUser().getSchoolId()) ? user.getId() : null);
         }
         query = markerService.findByQuery(query);
         for (Marker marker : query.getResult()) {
             marker.setSubject(subjectService.find(marker.getExamId(), marker.getSubjectCode()));
             MarkGroup group = groupService.findOne(examId, marker.getSubjectCode(), marker.getGroupNumber());
-            group.setQuestionList(questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId,
-                    marker.getSubjectCode(), false, group.getNumber()));
+            group.setQuestionList(questionService
+                    .findByExamAndSubjectAndObjectiveAndGroupNumber(examId, marker.getSubjectCode(), false,
+                            group.getNumber()));
             marker.setGroup(group);
             marker.setMarkedCount(markService.markedCount(marker));
             marker.setCurrentCount(markService.applyCount(marker));
@@ -220,8 +199,9 @@ public class MarkerController extends BaseExamController {
         JSONObject obj = new JSONObject();
         if (marker != null) {
             try {
-                lockService.waitlock(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(),
-                        marker.getGroupNumber());
+                lockService.waitlock(LockType.EXAM_SUBJECT, marker.getExamId(), marker.getSubjectCode());
+                lockService
+                        .waitlock(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
                 lockService.waitlock(LockType.MARKER, marker.getId());
 
                 markService.resetMarker(marker);
@@ -234,6 +214,7 @@ public class MarkerController extends BaseExamController {
                 lockService.unlock(LockType.MARKER, marker.getId());
                 lockService
                         .unlock(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
+                lockService.unlock(LockType.EXAM_SUBJECT, marker.getExamId(), marker.getSubjectCode());
             }
         } else {
             obj.accumulate("success", false);
@@ -537,8 +518,8 @@ public class MarkerController extends BaseExamController {
         if (marker != null) {
             classService.save(marker, classes);
             addMessage(redirectAttributes, "保存成功");
-            return "redirect:" + "/admin/exam/marker?subjectCode=" + marker.getSubjectCode() + "&groupNumber="
-                    + marker.getGroupNumber();
+            return "redirect:" + "/admin/exam/marker?subjectCode=" + marker.getSubjectCode() + "&groupNumber=" + marker
+                    .getGroupNumber();
         }
         addMessage(redirectAttributes, "评卷员不存在");
         return "redirect:/admin/exam/marker";

+ 1 - 3
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/PaperController.java

@@ -197,9 +197,7 @@ public class PaperController extends BaseExamController {
             for (SubjectQuestionDTO dto : map.values()) {
                 ExamSubject subject = subjectService.find(examId, dto.getSubjectCode());
                 if (subject != null) {
-                    // 每次导入都需要重新统分
-                    subjectService.updateNeedCalculate(examId, subject.getCode(), true);
-                    subjectService.updateCalculateProgress(examId, subject.getCode(), null);
+                    // TODO - 每次导入都需要重新统分
                     if (dto.validate(error)) {
                         if (objective) {
                             questionService.deleteByExamAndSubjectAndObjective(examId, dto.getSubjectCode(), objective);

+ 2 - 2
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ScoreController.java

@@ -361,8 +361,8 @@ public class ScoreController extends BaseExamController {
 
     private String enableExport(int examId, String subjectCode) {
         ExamSubject subject = subjectService.find(examId, subjectCode);
-        if (subject == null || subject.isNeedCalculate()) {
-            return "该科目需要统分";
+        if (subject == null) {
+            return "该科目不存在";
         }
 
         List<MarkGroup> groups = groupService

+ 3 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/StudentController.java

@@ -18,6 +18,7 @@ import cn.com.qmth.stmms.common.annotation.RoleRequire;
 import cn.com.qmth.stmms.common.domain.WebUser;
 import cn.com.qmth.stmms.common.enums.LogType;
 import cn.com.qmth.stmms.common.enums.Role;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import cn.com.qmth.stmms.common.utils.ExportExcel;
 import cn.com.qmth.stmms.common.utils.ImportExcel;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
@@ -185,6 +186,7 @@ public class StudentController extends BaseExamController {
                 student.setSheetCount(0);
                 student.setObjectiveScore(0d);
                 student.setSubjectiveScore(0d);
+                student.setSubjectiveStatus(SubjectiveStatus.UNMARK);
                 ExamStudent old = checkExamNumber(student, new HashMap<String, ExamStudent>(),
                         new HashMap<String, ExamStudent>());
                 if (old != null) {
@@ -273,6 +275,7 @@ public class StudentController extends BaseExamController {
                 student.setSheetCount(0);
                 student.setObjectiveScore(0d);
                 student.setSubjectiveScore(0d);
+                student.setSubjectiveStatus(SubjectiveStatus.UNMARK);
                 ExamStudent previous = checkExamNumber(student, current, saveMap);
                 if (previous != null) {
                     student = updatePrevious(student, previous);

+ 2 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/DataSyncThread.java

@@ -13,6 +13,7 @@ import cn.com.qmth.stmms.biz.file.enums.FormatType;
 import cn.com.qmth.stmms.biz.file.service.FileService;
 import cn.com.qmth.stmms.biz.lock.LockService;
 import cn.com.qmth.stmms.common.enums.LockType;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import com.aliyun.oss.common.utils.BinaryUtil;
 import net.sf.json.JSONArray;
 import net.sf.json.JSONObject;
@@ -178,6 +179,7 @@ public class DataSyncThread implements Runnable {
                         examStudent.setSheetCount(0);
                         examStudent.setObjectiveScore(0d);
                         examStudent.setSubjectiveScore(0d);
+                        examStudent.setSubjectiveStatus(SubjectiveStatus.UNMARK);
                         examStudent.setAnswers(null);
                         examStudent.setBatchCode(null);
                         examStudent.setUploadTime(now);

+ 3 - 5
stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/ScoreCalculateThread.java

@@ -112,15 +112,13 @@ public class ScoreCalculateThread implements Runnable {
                     } else if (progress == 0 && count > 0) {
                         progress = 1;
                     }
-                    // 更新进度百分比
-                    subjectService.updateCalculateProgress(examId, subjectCode, progress);
+                    // TODO - 更新进度百分比
                     pageNumber++;
                     list = studentService.findByExamId(examId, pageNumber, pageSize);
                 }
                 // 结束统计
                 context.save();
-                // 统分结束修改标记
-                subjectService.updateNeedCalculate(examId, subjectCode, false);
+                // TODO - 统分结束修改标记
             } catch (Exception e) {
                 log.error("calculate exception for examId=" + examId + ", subjectCode=" + subjectCode, e);
             } finally {
@@ -146,7 +144,7 @@ public class ScoreCalculateThread implements Runnable {
             studentService.updateObjectiveScore(student.getId(), student.getObjectiveScore(),
                     student.getObjectiveScoreList());
             // 增加主观题总分统计
-            markService.scoreCalculate(student, findMarkGroup(student.getSubjectCode()));
+            // markService.scoreCalculate(student, findMarkGroup(student.getSubjectCode()));
         } catch (Exception e) {
             log.error("calculate error for studentId=" + student.getId(), e);
         }

+ 2 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/CoreController.java

@@ -7,6 +7,7 @@ import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
 import cn.com.qmth.stmms.biz.exam.service.ExamService;
 import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
 import cn.com.qmth.stmms.common.domain.ApiUser;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import cn.com.qmth.stmms.common.utils.DateUtils;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
 import net.sf.json.JSONArray;
@@ -94,6 +95,7 @@ public class CoreController extends BaseApiController {
             student.setSheetCount(0);
             student.setObjectiveScore(0d);
             student.setSubjectiveScore(0d);
+            student.setSubjectiveStatus(SubjectiveStatus.UNMARK);
         }
         student.setStudentCode(studentCode);
         student.setName(name);

+ 12 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/common/controller/BaseController.java

@@ -247,6 +247,18 @@ public class BaseController {
                 }
             }
         });
+        // SubjectiveStatus 类型转换
+        binder.registerCustomEditor(SubjectiveStatus.class, new PropertyEditorSupport() {
+
+            @Override
+            public void setAsText(String text) {
+                try {
+                    setValue(SubjectiveStatus.findByText(text));
+                } catch (Exception e) {
+                    setValue(null);
+                }
+            }
+        });
         binder.registerCustomEditor(Boolean.class, new CustomBooleanEditor(true));
     }
 

+ 2 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/mark/MarkController.java

@@ -404,6 +404,7 @@ public class MarkController extends BaseController {
         Marker marker = RequestUtils.getWebUser(request).getMarker();
         boolean success = false;
         try {
+            lockService.watch(LockType.EXAM_SUBJECT, marker.getExamId(), marker.getSubjectCode());
             lockService.watch(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
             lockService.watch(LockType.STUDENT, markResult.getStudentId());
             lockService.watch(LockType.MARKER, marker.getId());
@@ -419,6 +420,7 @@ public class MarkController extends BaseController {
             lockService.unwatch(LockType.MARKER, marker.getId());
             lockService.unwatch(LockType.STUDENT, markResult.getStudentId());
             lockService.unwatch(LockType.GROUP, marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
+            lockService.unwatch(LockType.EXAM_SUBJECT, marker.getExamId(), marker.getSubjectCode());
         }
         result.accumulate("success", success);
         result.accumulate("status", status(request));