Răsfoiți Sursa

仲裁新增轨迹功能

ting.yin 1 an în urmă
părinte
comite
a69f7e5404
22 a modificat fișierele cu 1111 adăugiri și 301 ștergeri
  1. 29 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/HeaderTagDao.java
  2. 41 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/HeaderTrackDao.java
  3. 6 6
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkSpecialTagDao.java
  4. 5 5
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkTrackDao.java
  5. 15 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/ArbitrateHistory.java
  6. 136 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/HeaderTag.java
  7. 196 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/HeaderTrack.java
  8. 85 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/HeaderTrackPK.java
  9. 20 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkResult.java
  10. 23 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/SpecialTagDTO.java
  11. 34 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/TrackDTO.java
  12. 286 180
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkServiceImpl.java
  13. 20 18
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkSpecialTagServiceImpl.java
  14. 9 10
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkTrackServiceImpl.java
  15. 27 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/TaskServiceImpl.java
  16. 3 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkService.java
  17. 2 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkSpecialTagService.java
  18. 2 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkTrackService.java
  19. 1 1
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/AnswerCheckController.java
  20. 1 7
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ArbitrateController.java
  21. 87 36
      stmms-web/src/main/webapp/sql/stmms_ft.sql
  22. 83 30
      stmms-web/src/main/webapp/sql/upgrade/1.3.14.sql

+ 29 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/HeaderTagDao.java

@@ -0,0 +1,29 @@
+package cn.com.qmth.stmms.biz.mark.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.mark.model.HeaderTag;
+
+public interface HeaderTagDao extends PagingAndSortingRepository<HeaderTag, Integer>,
+        JpaSpecificationExecutor<HeaderTag> {
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete from HeaderTag s where s.studentId = ?1 and s.groupNumber=?2 ")
+    public void deleteByStudentIdAndGroupNumber(Integer studentId, Integer groupNumber);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete from HeaderTag s where s.studentId = ?1")
+    public void deleteByStudentId(Integer studentId);
+
+    public List<HeaderTag> findByStudentIdAndGroupNumberOrderByIdAsc(Integer studentId, Integer groupNumber);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete from HeaderTag s where s.groupNumber=?3 and s.studentId in (select m.id from ExamStudent m where m.examId=?1 and m.subjectCode=?2) ")
+    public void deleteByExamAndSubjectAndGroup(Integer examId, String subjectCode, Integer groupNumber);
+
+}

+ 41 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/HeaderTrackDao.java

@@ -0,0 +1,41 @@
+package cn.com.qmth.stmms.biz.mark.dao;
+
+import java.util.List;
+
+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.HeaderTrack;
+import cn.com.qmth.stmms.biz.mark.model.HeaderTrackPK;
+
+public interface HeaderTrackDao extends JpaRepository<HeaderTrack, HeaderTrackPK>,
+        JpaSpecificationExecutor<HeaderTrack> {
+
+    List<HeaderTrack> findByPkStudentIdAndGroupNumber(Integer studentId, Integer groupNumber);
+
+    List<HeaderTrack> findByPkStudentIdAndPkQuestionNumberOrderByPkNumberAsc(Integer studentId, String questionNumber);
+
+    List<HeaderTrack> findByPkStudentId(Integer studentId);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete from HeaderTrack t where t.pk.studentId=?1")
+    void deleteByPkStudentId(Integer studentId);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete from HeaderTrack t where t.pk.studentId=?1 and t.groupNumber=?2 ")
+    void deleteByPkStudentIdAndGroupNumber(Integer studentId, Integer groupNumber);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete from HeaderTrack t where t.examId=?1 and t.subjectCode=?2 and t.groupNumber=?3")
+    void deleteByExamIdAndSubjectCodeAndGroupNumber(Integer examId, String subjectCode, Integer groupNumber);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete from HeaderTrack t where t.pk.studentId=?1 and t.pk.questionNumber=?2")
+    void deleteByPkStudentIdAndQuestionNumber(Integer studentId, String questionNumber);
+
+    @Query("select count(t) from HeaderTrack t where t.pk.studentId=?1 and t.pk.questionNumber=?2 and t.unanswered =?3")
+    int countByStudentIdAndQuestionNumberAndUnanswered(Integer studentId, String questionNumber, boolean unanswered);
+
+}

+ 6 - 6
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkSpecialTagDao.java

@@ -1,7 +1,6 @@
 package cn.com.qmth.stmms.biz.mark.dao;
 
 import cn.com.qmth.stmms.biz.mark.model.MarkSpecialTag;
-import cn.com.qmth.stmms.common.enums.LibraryStatus;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
@@ -9,8 +8,8 @@ import org.springframework.data.repository.PagingAndSortingRepository;
 
 import java.util.List;
 
-public interface MarkSpecialTagDao
-        extends PagingAndSortingRepository<MarkSpecialTag, Integer>, JpaSpecificationExecutor<MarkSpecialTag> {
+public interface MarkSpecialTagDao extends PagingAndSortingRepository<MarkSpecialTag, Integer>,
+        JpaSpecificationExecutor<MarkSpecialTag> {
 
     @Modifying(clearAutomatically = true)
     @Query("delete from MarkSpecialTag s where s.libraryId = ?1")
@@ -23,9 +22,10 @@ public interface MarkSpecialTagDao
 
     public List<MarkSpecialTag> findByLibraryIdOrderByIdAsc(Integer libraryId);
 
-    @Modifying(clearAutomatically = true)
-    @Query("delete from MarkSpecialTag s where s.libraryId in (select m.id from MarkLibrary m where m.markerId=?1  and m.status!=?2 and m.status not in (?3) ) ")
-    public void deleteByMarkerId(Integer markerId, LibraryStatus arbitrated, LibraryStatus... waitArbitrate);
+    // @Modifying(clearAutomatically = true)
+    // @Query("delete from MarkSpecialTag s where s.libraryId in (select m.id from MarkLibrary m where m.markerId=?1  and m.status!=?2 and m.status not in (?3) ) ")
+    // public void deleteByMarkerId(Integer markerId, LibraryStatus arbitrated,
+    // LibraryStatus... waitArbitrate);
 
     @Modifying(clearAutomatically = true)
     @Query("delete from MarkSpecialTag s where s.libraryId in (select m.id from MarkLibrary m where m.examId=?1 and m.subjectCode=?2 and m.groupNumber=?3)")

+ 5 - 5
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkTrackDao.java

@@ -9,7 +9,6 @@ import org.springframework.data.jpa.repository.Query;
 
 import cn.com.qmth.stmms.biz.mark.model.MarkTrack;
 import cn.com.qmth.stmms.biz.mark.model.MarkTrackPK;
-import cn.com.qmth.stmms.common.enums.LibraryStatus;
 
 public interface MarkTrackDao extends JpaRepository<MarkTrack, MarkTrackPK>, JpaSpecificationExecutor<MarkTrack> {
 
@@ -17,7 +16,7 @@ public interface MarkTrackDao extends JpaRepository<MarkTrack, MarkTrackPK>, Jpa
 
     List<MarkTrack> findByPkLibraryIdAndPkQuestionNumberOrderByPkNumberAsc(Integer libraryId, String questionNumber);
 
-    List<MarkTrack> findByStudentId(Integer studentId);
+    // List<MarkTrack> findByStudentId(Integer studentId);
 
     @Modifying(clearAutomatically = true)
     @Query("delete from MarkTrack t where t.pk.libraryId=?1")
@@ -27,9 +26,10 @@ public interface MarkTrackDao extends JpaRepository<MarkTrack, MarkTrackPK>, Jpa
     @Query("delete from MarkTrack t where t.studentId=?1")
     void deleteByStudentId(Integer studentId);
 
-    @Modifying(clearAutomatically = true)
-    @Query("delete from MarkTrack t where t.pk.libraryId in (select m.id from MarkLibrary m where m.markerId=?1  and m.status!=?2 and m.status not in (?3) )")
-    void deleteByMarkerId(Integer markerId, LibraryStatus arbitrated, LibraryStatus... waitArbitrate);
+    // @Modifying(clearAutomatically = true)
+    // @Query("delete from MarkTrack t where t.pk.libraryId in (select m.id from MarkLibrary m where m.markerId=?1  and m.status!=?2 and m.status not in (?3) )")
+    // void deleteByMarkerId(Integer markerId, LibraryStatus arbitrated,
+    // LibraryStatus... waitArbitrate);
 
     @Modifying(clearAutomatically = true)
     @Query("delete from MarkTrack t where t.examId=?1 and t.subjectCode=?2 and t.groupNumber=?3")

+ 15 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/ArbitrateHistory.java

@@ -96,6 +96,12 @@ public class ArbitrateHistory implements Serializable {
     @Enumerated(EnumType.STRING)
     private HistoryStatus status;
 
+    /**
+     * 未作答的步骤数量
+     */
+    @Column(name = "unanswered_count", nullable = true)
+    private Integer unansweredCount;
+
     /**
      * 处理时间
      */
@@ -246,4 +252,13 @@ public class ArbitrateHistory implements Serializable {
         }
         return list;
     }
+
+    public Integer getUnansweredCount() {
+        return unansweredCount;
+    }
+
+    public void setUnansweredCount(Integer unansweredCount) {
+        this.unansweredCount = unansweredCount;
+    }
+
 }

+ 136 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/HeaderTag.java

@@ -0,0 +1,136 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import java.io.Serializable;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "m_header_tag")
+public class HeaderTag implements Serializable {
+
+    private static final long serialVersionUID = 7719002807054384554L;
+
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    @Column(name = "student_id", nullable = false)
+    private Integer studentId;
+
+    @Column(name = "group_number", nullable = false)
+    private Integer groupNumber;
+
+    @Column(name = "user_id", nullable = false)
+    private Integer userId;
+
+    @Column(name = "tag_name", nullable = false)
+    private String tagName;
+
+    @Column(name = "position_x", nullable = false)
+    private Double positionX;
+
+    @Column(name = "position_y", nullable = false)
+    private Double positionY;
+
+    /**
+     * 所在裁切图序号
+     */
+    @Column(name = "offset_index", nullable = false)
+    private Integer offsetIndex;
+
+    /**
+     * 相对裁切图X轴坐标
+     */
+    @Column(name = "offset_x", nullable = false)
+    private Integer offsetX;
+
+    /**
+     * 相对裁切图Y轴坐标
+     */
+    @Column(name = "offset_y", nullable = false)
+    private Integer offsetY;
+
+    public HeaderTag() {
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getTagName() {
+        return tagName;
+    }
+
+    public void setTagName(String tagName) {
+        this.tagName = tagName;
+    }
+
+    public Double getPositionX() {
+        return positionX;
+    }
+
+    public void setPositionX(Double positionX) {
+        this.positionX = positionX;
+    }
+
+    public Double getPositionY() {
+        return positionY;
+    }
+
+    public void setPositionY(Double positionY) {
+        this.positionY = positionY;
+    }
+
+    public Integer getOffsetIndex() {
+        return offsetIndex;
+    }
+
+    public void setOffsetIndex(Integer offsetIndex) {
+        this.offsetIndex = offsetIndex;
+    }
+
+    public Integer getOffsetX() {
+        return offsetX;
+    }
+
+    public void setOffsetX(Integer offsetX) {
+        this.offsetX = offsetX;
+    }
+
+    public Integer getOffsetY() {
+        return offsetY;
+    }
+
+    public void setOffsetY(Integer offsetY) {
+        this.offsetY = offsetY;
+    }
+
+    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;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+}

+ 196 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/HeaderTrack.java

@@ -0,0 +1,196 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * 阅卷轨迹
+ *
+ */
+@Entity
+@Table(name = "m_header_track")
+public class HeaderTrack implements Serializable {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 6917238036373630524L;
+
+    @EmbeddedId
+    private HeaderTrackPK pk;
+
+    @Column(name = "exam_id", nullable = false)
+    private Integer examId;
+
+    @Column(name = "subject_code", nullable = false)
+    private String subjectCode;
+
+    @Column(name = "group_number", nullable = false)
+    private Integer groupNumber;
+
+    @Column(name = "user_id", nullable = false)
+    private Integer userId;
+
+    /**
+     * 轨迹分数
+     */
+    @Column(name = "score", nullable = false)
+    private Double score;
+
+    /**
+     * X轴相对位置,0~1
+     */
+    @Column(name = "position_x", nullable = false)
+    private Double positionX;
+
+    /**
+     * Y轴相对位置,0~1
+     */
+    @Column(name = "position_y", nullable = false)
+    private Double positionY;
+
+    /**
+     * 所在裁切图序号
+     */
+    @Column(name = "offset_index", nullable = false)
+    private Integer offsetIndex;
+
+    /**
+     * 相对裁切图X轴坐标
+     */
+    @Column(name = "offset_x", nullable = false)
+    private Integer offsetX;
+
+    /**
+     * 相对裁切图Y轴坐标
+     */
+    @Column(name = "offset_y", nullable = false)
+    private Integer offsetY;
+
+    /**
+     * 是否未作答
+     */
+    @Column(name = "unanswered", nullable = false)
+    private boolean unanswered;
+
+    public HeaderTrack() {
+        this.pk = new HeaderTrackPK();
+    }
+
+    public Integer getStudentId() {
+        return pk.getStudentId();
+    }
+
+    public void setStudentId(Integer studentId) {
+        pk.setStudentId(studentId);
+    }
+
+    public String getQuestionNumber() {
+        return pk.getQuestionNumber();
+    }
+
+    public void setQuestionNumber(String questionNumber) {
+        pk.setQuestionNumber(questionNumber);
+    }
+
+    public Integer getNumber() {
+        return pk.getNumber();
+    }
+
+    public void setNumber(Integer number) {
+        pk.setNumber(number);
+    }
+
+    public Double getScore() {
+        return score;
+    }
+
+    public void setScore(Double score) {
+        this.score = score;
+    }
+
+    public Double getPositionX() {
+        return positionX;
+    }
+
+    public void setPositionX(Double positionX) {
+        this.positionX = positionX;
+    }
+
+    public Double getPositionY() {
+        return positionY;
+    }
+
+    public void setPositionY(Double positionY) {
+        this.positionY = positionY;
+    }
+
+    public Integer getGroupNumber() {
+        return groupNumber;
+    }
+
+    public void setGroupNumber(Integer groupNumber) {
+        this.groupNumber = 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 Integer getOffsetIndex() {
+        return offsetIndex;
+    }
+
+    public void setOffsetIndex(Integer offsetIndex) {
+        this.offsetIndex = offsetIndex;
+    }
+
+    public Integer getOffsetX() {
+        return offsetX;
+    }
+
+    public void setOffsetX(Integer offsetX) {
+        this.offsetX = offsetX;
+    }
+
+    public Integer getOffsetY() {
+        return offsetY;
+    }
+
+    public void setOffsetY(Integer offsetY) {
+        this.offsetY = offsetY;
+    }
+
+    public boolean isUnanswered() {
+        return unanswered;
+    }
+
+    public void setUnanswered(boolean unanswered) {
+        this.unanswered = unanswered;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+}

+ 85 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/HeaderTrackPK.java

@@ -0,0 +1,85 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class HeaderTrackPK implements Serializable {
+
+    private static final long serialVersionUID = 9096523417236451724L;
+
+    @Column(name = "student_id", nullable = false)
+    private Integer studentId;
+
+    @Column(name = "question_number", nullable = false)
+    private String questionNumber;
+
+    @Column(name = "number", nullable = false)
+    private Integer number;
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public String getQuestionNumber() {
+        return questionNumber;
+    }
+
+    public void setQuestionNumber(String questionNumber) {
+        this.questionNumber = questionNumber;
+    }
+
+    public Integer getNumber() {
+        return number;
+    }
+
+    public void setNumber(Integer number) {
+        this.number = number;
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((studentId == null) ? 0 : studentId.hashCode());
+        result = PRIME * result + ((questionNumber == null) ? 0 : questionNumber.hashCode());
+        result = PRIME * result + ((number == null) ? 0 : number.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 HeaderTrackPK other = (HeaderTrackPK) obj;
+        if (studentId == null) {
+            if (other.studentId != null)
+                return false;
+        } else if (!studentId.equals(other.studentId))
+            return false;
+        if (questionNumber == null) {
+            if (other.questionNumber != null)
+                return false;
+        } else if (!questionNumber.equals(other.questionNumber))
+            return false;
+
+        if (number == null) {
+            if (other.number != null)
+                return false;
+        } else if (!number.equals(other.number))
+            return false;
+
+        return true;
+    }
+
+}

+ 20 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkResult.java

@@ -177,6 +177,16 @@ public class MarkResult {
         return map;
     }
 
+    public List<HeaderTrack> getTrackList(ArbitrateHistory library) {
+        List<HeaderTrack> list = new LinkedList<>();
+        if (trackList != null) {
+            for (TrackDTO dto : trackList) {
+                list.add(dto.transform(library));
+            }
+        }
+        return list;
+    }
+
     public List<MarkTrack> getTrackList(MarkLibrary library, Marker marker) {
         List<MarkTrack> list = new LinkedList<>();
         if (trackList != null) {
@@ -202,6 +212,16 @@ public class MarkResult {
         return list;
     }
 
+    public List<HeaderTag> getHeaderTagList(ArbitrateHistory library) {
+        List<HeaderTag> list = new LinkedList<>();
+        if (specialTagList != null) {
+            for (SpecialTagDTO dto : specialTagList) {
+                list.add(dto.transform(library));
+            }
+        }
+        return list;
+    }
+
     public List<MarkSpecialTag> getSpecialTagList(MarkLibrary library, Marker marker) {
         List<MarkSpecialTag> list = new LinkedList<>();
         if (specialTagList != null) {

+ 23 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/SpecialTagDTO.java

@@ -40,6 +40,15 @@ public class SpecialTagDTO implements Serializable {
         this.offsetY = tag.getOffsetY();
     }
 
+    public SpecialTagDTO(HeaderTag tag) {
+        this.tagName = tag.getTagName();
+        this.positionX = tag.getPositionX();
+        this.positionY = tag.getPositionY();
+        this.offsetIndex = tag.getOffsetIndex();
+        this.offsetX = tag.getOffsetX();
+        this.offsetY = tag.getOffsetY();
+    }
+
     public MarkSpecialTag transform(MarkLibrary library) {
         MarkSpecialTag markSpecialTag = new MarkSpecialTag();
         markSpecialTag.setLibraryId(library.getId());
@@ -65,6 +74,20 @@ public class SpecialTagDTO implements Serializable {
         return tag;
     }
 
+    public HeaderTag transform(ArbitrateHistory library) {
+        HeaderTag markSpecialTag = new HeaderTag();
+        markSpecialTag.setStudentId(library.getStudentId());
+        markSpecialTag.setGroupNumber(library.getGroupNumber());
+        markSpecialTag.setUserId(library.getUserId());
+        markSpecialTag.setTagName(tagName);
+        markSpecialTag.setPositionX(positionX);
+        markSpecialTag.setPositionY(positionY);
+        markSpecialTag.setOffsetIndex(offsetIndex);
+        markSpecialTag.setOffsetX(offsetX);
+        markSpecialTag.setOffsetY(offsetY);
+        return markSpecialTag;
+    }
+
     public String getTagName() {
         return tagName;
     }

+ 34 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/TrackDTO.java

@@ -66,6 +66,21 @@ public class TrackDTO implements Serializable {
         setUnanswered(track.isUnanswered());
     }
 
+    public TrackDTO(HeaderTrack track) {
+        String questionNumber = track.getQuestionNumber();
+        String str[] = questionNumber.split("\\.");
+        setMainNumber(Integer.parseInt(str[0]));
+        setSubNumber(str[1]);
+        setNumber(track.getNumber());
+        setScore(track.getScore());
+        setPositionX(track.getPositionX());
+        setPositionY(track.getPositionY());
+        setOffsetIndex(track.getOffsetIndex());
+        setOffsetX(track.getOffsetX());
+        setOffsetY(track.getOffsetY());
+        setUnanswered(track.isUnanswered());
+    }
+
     public MarkTrack transform(MarkLibrary library, Marker marker) {
         MarkTrack track = new MarkTrack();
         track.setLibraryId(library.getId());
@@ -106,6 +121,25 @@ public class TrackDTO implements Serializable {
         return track;
     }
 
+    public HeaderTrack transform(ArbitrateHistory library) {
+        HeaderTrack track = new HeaderTrack();
+        track.setQuestionNumber(getMainNumber() + "." + getSubNumber());
+        track.setNumber(getNumber());
+        track.setStudentId(library.getStudentId());
+        track.setExamId(library.getExamId());
+        track.setSubjectCode(library.getSubjectCode());
+        track.setGroupNumber(library.getGroupNumber());
+        track.setUserId(library.getUserId());
+        track.setScore(getScore());
+        track.setPositionX(getPositionX());
+        track.setPositionY(getPositionY());
+        track.setOffsetIndex(getOffsetIndex());
+        track.setOffsetX(getOffsetX());
+        track.setOffsetY(getOffsetY());
+        track.setUnanswered(isUnanswered());
+        return track;
+    }
+
     public Integer getMainNumber() {
         return mainNumber;
     }

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

@@ -1,18 +1,17 @@
 package cn.com.qmth.stmms.biz.mark.service.Impl;
 
-import cn.com.qmth.stmms.biz.exam.dao.*;
-import cn.com.qmth.stmms.biz.exam.model.*;
-import cn.com.qmth.stmms.biz.exam.service.*;
-import cn.com.qmth.stmms.biz.lock.LockService;
-import cn.com.qmth.stmms.biz.mark.dao.*;
-import cn.com.qmth.stmms.biz.mark.model.*;
-import cn.com.qmth.stmms.biz.mark.query.MarkLibrarySearchQuery;
-import cn.com.qmth.stmms.biz.mark.service.MarkService;
-import cn.com.qmth.stmms.biz.utils.ScoreItem;
-import cn.com.qmth.stmms.biz.utils.TaskLock;
-import cn.com.qmth.stmms.biz.utils.TaskLockUtil;
-import cn.com.qmth.stmms.common.enums.*;
-import cn.com.qmth.stmms.common.utils.BigDecimalUtils;
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -21,11 +20,64 @@ import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.math.BigDecimal;
-import java.text.DecimalFormat;
-import java.util.*;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
+import cn.com.qmth.stmms.biz.exam.dao.MarkGroupDao;
+import cn.com.qmth.stmms.biz.exam.dao.MarkGroupStudentDao;
+import cn.com.qmth.stmms.biz.exam.dao.MarkerDao;
+import cn.com.qmth.stmms.biz.exam.dao.SelectiveStudentDao;
+import cn.com.qmth.stmms.biz.exam.dao.SubjectiveScoreDao;
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+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.MarkGroupStudent;
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.biz.exam.model.SelectiveGroup;
+import cn.com.qmth.stmms.biz.exam.model.SelectiveStudent;
+import cn.com.qmth.stmms.biz.exam.model.SubjectiveScore;
+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.InspectHistoryService;
+import cn.com.qmth.stmms.biz.exam.service.MarkerService;
+import cn.com.qmth.stmms.biz.exam.service.SelectiveGroupService;
+import cn.com.qmth.stmms.biz.exam.service.SubjectiveScoreService;
+import cn.com.qmth.stmms.biz.lock.LockService;
+import cn.com.qmth.stmms.biz.mark.dao.ArbitrateHistoryDao;
+import cn.com.qmth.stmms.biz.mark.dao.HeaderTagDao;
+import cn.com.qmth.stmms.biz.mark.dao.HeaderTrackDao;
+import cn.com.qmth.stmms.biz.mark.dao.MarkLibraryDao;
+import cn.com.qmth.stmms.biz.mark.dao.MarkSpecialTagDao;
+import cn.com.qmth.stmms.biz.mark.dao.MarkTrackDao;
+import cn.com.qmth.stmms.biz.mark.dao.ProblemHistoryDao;
+import cn.com.qmth.stmms.biz.mark.dao.RejectHistoryDao;
+import cn.com.qmth.stmms.biz.mark.dao.TrialLibraryDao;
+import cn.com.qmth.stmms.biz.mark.dao.TrialTagDao;
+import cn.com.qmth.stmms.biz.mark.dao.TrialTrackDao;
+import cn.com.qmth.stmms.biz.mark.model.ArbitrateHistory;
+import cn.com.qmth.stmms.biz.mark.model.HeaderTrack;
+import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
+import cn.com.qmth.stmms.biz.mark.model.MarkResult;
+import cn.com.qmth.stmms.biz.mark.model.MarkStepDTO;
+import cn.com.qmth.stmms.biz.mark.model.MarkTrack;
+import cn.com.qmth.stmms.biz.mark.model.ProblemHistory;
+import cn.com.qmth.stmms.biz.mark.model.RejectHistory;
+import cn.com.qmth.stmms.biz.mark.model.SubmitResult;
+import cn.com.qmth.stmms.biz.mark.model.TrialLibrary;
+import cn.com.qmth.stmms.biz.mark.query.MarkLibrarySearchQuery;
+import cn.com.qmth.stmms.biz.mark.service.MarkService;
+import cn.com.qmth.stmms.biz.utils.ScoreItem;
+import cn.com.qmth.stmms.biz.utils.TaskLock;
+import cn.com.qmth.stmms.biz.utils.TaskLockUtil;
+import cn.com.qmth.stmms.common.enums.HistoryStatus;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+import cn.com.qmth.stmms.common.enums.LockType;
+import cn.com.qmth.stmms.common.enums.MarkStatus;
+import cn.com.qmth.stmms.common.enums.ObjectiveStatus;
+import cn.com.qmth.stmms.common.enums.ScorePolicy;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
+import cn.com.qmth.stmms.common.enums.ThirdPolicy;
+import cn.com.qmth.stmms.common.utils.BigDecimalUtils;
 
 /**
  * 与评卷相关的所有修改操作(非传播性的新增操作除外),全部汇总到这里进行集中控制
@@ -81,6 +133,12 @@ public class MarkServiceImpl implements MarkService {
     @Autowired
     private TrialTagDao trialTagDao;
 
+    @Autowired
+    private HeaderTagDao headerTagDao;
+
+    @Autowired
+    private HeaderTrackDao headerTrackDao;
+
     @Autowired
     private ProblemHistoryDao problemHistoryDao;
 
@@ -113,7 +171,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 某个评卷分组已申请的评卷任务数量
      *
-     * @param group - 评卷分组
+     * @param group
+     *            - 评卷分组
      * @return int
      */
     @Override
@@ -129,7 +188,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 某个评卷员已申请的评卷任务数量
      *
-     * @param marker - 评卷员
+     * @param marker
+     *            - 评卷员
      * @return int
      */
     @Override
@@ -159,7 +219,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 某个评卷员已完成的评卷任务数量
      *
-     * @param marker - 评卷员
+     * @param marker
+     *            - 评卷员
      * @return long
      */
     @Override
@@ -172,8 +233,8 @@ public class MarkServiceImpl implements MarkService {
             if (group.getStatus() == MarkStatus.TRIAL) {
                 return trialLibraryDao.countByMarkerId(marker.getId());
             } else {
-                return libraryDao.countByMarkerAndStatus(marker.getId(), LibraryStatus.MARKED, LibraryStatus.ARBITRATED,
-                        LibraryStatus.INSPECTED);
+                return libraryDao.countByMarkerAndStatus(marker.getId(), LibraryStatus.MARKED,
+                        LibraryStatus.ARBITRATED, LibraryStatus.INSPECTED);
             }
         }
         return 0;
@@ -182,7 +243,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 释放某个评卷分组的锁定任务
      *
-     * @param group - 评卷分组
+     * @param group
+     *            - 评卷分组
      */
     @Override
     public void releaseByGroup(MarkGroup group) {
@@ -193,7 +255,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 重置某个评卷分组的所有评卷任务
      *
-     * @param group - 评卷分组
+     * @param group
+     *            - 评卷分组
      */
     @Override
     @Transactional
@@ -204,7 +267,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 删除某个评卷分组
      *
-     * @param group - 评卷分组
+     * @param group
+     *            - 评卷分组
      */
     @Override
     @Transactional
@@ -219,6 +283,9 @@ public class MarkServiceImpl implements MarkService {
         trackDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                 group.getNumber());
         specialTagDao.deleteByExamAndSubjectAndGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
+        headerTrackDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
+                group.getNumber());
+        headerTagDao.deleteByExamAndSubjectAndGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
         arbitrateDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                 group.getNumber());
         problemHistoryDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
@@ -231,9 +298,8 @@ public class MarkServiceImpl implements MarkService {
         markerDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                 group.getNumber());
         // 小题数据
-        questionService
-                .resetByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(group.getExamId(), group.getSubjectCode(), false,
-                        group.getNumber());
+        questionService.resetByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(group.getExamId(),
+                group.getSubjectCode(), false, group.getNumber());
         // 考生分组状态与得分明细
         groupStudentDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                 group.getNumber());
@@ -244,9 +310,8 @@ public class MarkServiceImpl implements MarkService {
         releaseByGroup(group);
         groupDao.delete(group);
         // 未分组的题目
-        long unGroupQuestionCount = questionService
-                .countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(group.getExamId(), group.getSubjectCode(),
-                        false);
+        long unGroupQuestionCount = questionService.countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(
+                group.getExamId(), group.getSubjectCode(), false);
         // 考生整体状态与总分更新
         long groupCount = groupDao.countByExamIdAndSubjectCode(group.getExamId(), group.getSubjectCode());
         if (groupCount == 0 || unGroupQuestionCount > 0) {
@@ -256,9 +321,8 @@ public class MarkServiceImpl implements MarkService {
             // group.getSubjectCode());
             inspectHistoryService.deleteByExamIdAndSubjectCode(group.getExamId(), group.getSubjectCode());
         } else {
-            List<Integer> studentList = studentService
-                    .findIdByExamIdAndSubjectCodeAndSubjectiveStatus(group.getExamId(), group.getSubjectCode(),
-                            SubjectiveStatus.UNMARK, SubjectiveStatus.MARKED);
+            List<Integer> studentList = studentService.findIdByExamIdAndSubjectCodeAndSubjectiveStatus(
+                    group.getExamId(), group.getSubjectCode(), SubjectiveStatus.UNMARK, SubjectiveStatus.MARKED);
             for (Integer studentId : studentList) {
                 checkStudentSubjective(studentId, groupCount, unGroupQuestionCount);
             }
@@ -268,15 +332,15 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 修改某个评卷分组给分步骤,并重置评卷任务
      *
-     * @param group - 评卷分组
+     * @param group
+     *            - 评卷分组
      */
     @Override
     @Transactional
     public void updateGroup(MarkGroup group, List<ExamQuestion> questionList, ScorePolicy policy, ThirdPolicy third,
             boolean selective) {
-        List<ExamQuestion> old = questionService
-                .findByExamAndSubjectAndObjectiveAndGroupNumber(group.getExamId(), group.getSubjectCode(), false,
-                        group.getNumber());
+        List<ExamQuestion> old = questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(group.getExamId(),
+                group.getSubjectCode(), false, group.getNumber());
         for (ExamQuestion question : old) {
             question.setGroupNumber(null);
             questionService.saveAndFlush(question);
@@ -309,8 +373,10 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 评卷员申请领取某个正式评卷任务
      *
-     * @param library - 正评任务
-     * @param marker  - 评卷员
+     * @param library
+     *            - 正评任务
+     * @param marker
+     *            - 评卷员
      */
     @Override
     public boolean applyLibrary(MarkLibrary library, Marker marker) {
@@ -333,8 +399,10 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 评卷员申请领取某个试评评卷任务
      *
-     * @param library - 试评任务
-     * @param marker  - 评卷员
+     * @param library
+     *            - 试评任务
+     * @param marker
+     *            - 评卷员
      * @return boolean
      */
     @Override
@@ -346,8 +414,10 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 评卷员是否已领取了某个正式评卷任务
      *
-     * @param library - 正评任务
-     * @param marker  - 评卷员
+     * @param library
+     *            - 正评任务
+     * @param marker
+     *            - 评卷员
      * @return boolean
      */
     @Override
@@ -359,8 +429,10 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 评卷员是否已领取了某个试评评卷任务
      *
-     * @param library - 试评任务
-     * @param marker  - 评卷员
+     * @param library
+     *            - 试评任务
+     * @param marker
+     *            - 评卷员
      * @return boolean
      */
     @Override
@@ -372,8 +444,10 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 释放某个评卷员已完成的评卷任务
      *
-     * @param result - 评卷结果
-     * @param marker - 评卷员
+     * @param result
+     *            - 评卷结果
+     * @param marker
+     *            - 评卷员
      */
     @Override
     public void releaseTask(SubmitResult result, Marker marker) {
@@ -391,7 +465,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 释放某个评卷员的所有锁定任务
      *
-     * @param marker - 评卷员
+     * @param marker
+     *            - 评卷员
      */
     @Override
     public void releaseByMarker(Marker marker) {
@@ -404,7 +479,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 重置某个评卷员
      *
-     * @param marker - 评卷员
+     * @param marker
+     *            - 评卷员
      */
     @Override
     @Transactional
@@ -448,8 +524,8 @@ public class MarkServiceImpl implements MarkService {
             for (MarkLibrary library : list) {
                 trackDao.deleteByLibraryId(library.getId());
                 specialTagDao.deleteByLibraryId(library.getId());
-                libraryDao
-                        .resetById(library.getId(), null, null, null, null, LibraryStatus.WAITING, library.getStatus());
+                libraryDao.resetById(library.getId(), null, null, null, null, LibraryStatus.WAITING,
+                        library.getStatus());
                 lockService.waitlock(LockType.STUDENT, library.getStudentId());
                 updateStudentGroupStatus(library.getStudentId(), library.getExamId(), library.getSubjectCode(),
                         library.getGroupNumber(), SubjectiveStatus.UNMARK);
@@ -469,7 +545,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 根据考生删除评卷任务
      *
-     * @param student - 考生
+     * @param student
+     *            - 考生
      */
     @Override
     @Transactional
@@ -477,6 +554,8 @@ public class MarkServiceImpl implements MarkService {
         // 正评相关数据
         trackDao.deleteByStudentId(student.getId());
         specialTagDao.deleteByStudentId(student.getId());
+        headerTagDao.deleteByStudentId(student.getId());
+        headerTrackDao.deleteByPkStudentId(student.getId());
         arbitrateDao.deleteByStudentId(student.getId());
         problemHistoryDao.deleteByStudentId(student.getId());
         libraryDao.deleteByStudentId(student.getId());
@@ -498,8 +577,10 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 评卷员提交评卷任务
      *
-     * @param result - 评卷结果
-     * @param marker - 评卷员
+     * @param result
+     *            - 评卷结果
+     * @param marker
+     *            - 评卷员
      * @return boolean
      */
     @Override
@@ -507,8 +588,8 @@ public class MarkServiceImpl implements MarkService {
     public SubmitResult submitTask(MarkResult result, Marker marker) {
         // 判断评卷分组是否存在/评卷是否结束
         MarkGroup group = groupDao.findOne(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
-        if (group == null || group.getStatus() == MarkStatus.FINISH || !group.getStatus().toString()
-                .equals(result.getStatusValue())) {
+        if (group == null || group.getStatus() == MarkStatus.FINISH
+                || !group.getStatus().toString().equals(result.getStatusValue())) {
             return SubmitResult.faile();
         }
 
@@ -516,8 +597,9 @@ public class MarkServiceImpl implements MarkService {
         // 根据评卷状态选择读取不同的评卷任务
         if (group.getStatus() == MarkStatus.FORMAL) {
             MarkLibrary library = libraryDao.findOne(result.getLibraryId());
-            if (library != null && library.getExamId().equals(group.getExamId()) && library.getSubjectCode()
-                    .equals(group.getSubjectCode()) && library.getGroupNumber().equals(group.getNumber())) {
+            if (library != null && library.getExamId().equals(group.getExamId())
+                    && library.getSubjectCode().equals(group.getSubjectCode())
+                    && library.getGroupNumber().equals(group.getNumber())) {
                 // 问题卷
                 if (result.isProblem()) {
                     // 状态更新
@@ -543,11 +625,12 @@ public class MarkServiceImpl implements MarkService {
             }
         } else if (group.getStatus() == MarkStatus.TRIAL) {
             TrialLibrary library = trialLibraryDao.findOne(result.getLibraryId());
-            if (library != null && library.getExamId().equals(group.getExamId()) && library.getSubjectCode()
-                    .equals(group.getSubjectCode()) && library.getGroupNumber().equals(group.getNumber())
+            if (library != null && library.getExamId().equals(group.getExamId())
+                    && library.getSubjectCode().equals(group.getSubjectCode())
+                    && library.getGroupNumber().equals(group.getNumber())
                     && result.getMarkerScore() <= group.getTotalScore()) {
-                if ((library.getMarkerId() == null && !hasApplied(library, marker)) || (library.getMarkerId() != null
-                        && !library.getMarkerId().equals(marker.getId()))) {
+                if ((library.getMarkerId() == null && !hasApplied(library, marker))
+                        || (library.getMarkerId() != null && !library.getMarkerId().equals(marker.getId()))) {
                     return SubmitResult.faile();
                 }
                 library.setMarkerId(marker.getId());
@@ -600,10 +683,14 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 评卷员提交某个正评任务
      *
-     * @param library - 正评任务
-     * @param marker  - 评卷员
-     * @param group   - 评卷分组
-     * @param result  - 评卷结果
+     * @param library
+     *            - 正评任务
+     * @param marker
+     *            - 评卷员
+     * @param group
+     *            - 评卷分组
+     * @param result
+     *            - 评卷结果
      */
     private boolean submitLibrary(MarkLibrary library, Marker marker, MarkGroup group, MarkResult result) {
         // 非本人领取的待评任务
@@ -612,13 +699,13 @@ public class MarkServiceImpl implements MarkService {
             return false;
         }
         // 非本人的回评任务
-        if ((library.getStatus() == LibraryStatus.MARKED || library.getStatus() == LibraryStatus.INSPECTED) && !library
-                .getMarkerId().equals(marker.getId())) {
+        if ((library.getStatus() == LibraryStatus.MARKED || library.getStatus() == LibraryStatus.INSPECTED)
+                && !library.getMarkerId().equals(marker.getId())) {
             return false;
         }
         // 是否多评情况下已处理过该考生评卷任务
-        if (libraryDao.countByStudentIdAndMarkerIdAndIdNotEqual(library.getStudentId(), marker.getId(), library.getId())
-                > 0) {
+        if (libraryDao
+                .countByStudentIdAndMarkerIdAndIdNotEqual(library.getStudentId(), marker.getId(), library.getId()) > 0) {
             return false;
         }
         // 未选做
@@ -630,10 +717,9 @@ public class MarkServiceImpl implements MarkService {
         }
         // 尝试提交评卷结果
         Date now = new Date();
-        if (libraryDao
-                .updateMarkerResult(library.getId(), LibraryStatus.MARKED, marker.getId(), result.getMarkerScore(),
-                        result.getScoreList(), now, result.getSpent(), null, null, null, LibraryStatus.WAITING,
-                        LibraryStatus.MARKED, LibraryStatus.INSPECTED, LibraryStatus.REJECTED) == 0) {
+        if (libraryDao.updateMarkerResult(library.getId(), LibraryStatus.MARKED, marker.getId(),
+                result.getMarkerScore(), result.getScoreList(), now, result.getSpent(), null, null, null,
+                LibraryStatus.WAITING, LibraryStatus.MARKED, LibraryStatus.INSPECTED, LibraryStatus.REJECTED) == 0) {
             // 条件不符更新失败,直接返回
             return false;
         }
@@ -659,9 +745,8 @@ public class MarkServiceImpl implements MarkService {
         ArbitrateHistory history = null;
         if (group.getArbitrateThreshold() != null && group.getArbitrateThreshold() > 0) {
             // 多评模式
-            List<MarkLibrary> list = libraryDao
-                    .findByStudentIdAndGroupNumberAndStatus(library.getStudentId(), library.getGroupNumber(),
-                            LibraryStatus.MARKED, LibraryStatus.INSPECTED);
+            List<MarkLibrary> list = libraryDao.findByStudentIdAndGroupNumberAndStatus(library.getStudentId(),
+                    library.getGroupNumber(), LibraryStatus.MARKED, LibraryStatus.INSPECTED);
             for (MarkLibrary other : list) {
                 // 本评卷任务或组长已打分,则跳过该任务
                 if (other.getId().equals(library.getId()) || other.getHeaderScore() != null) {
@@ -672,9 +757,8 @@ public class MarkServiceImpl implements MarkService {
                     continue;
                 }
                 // 其中一个有分另一个未选做 直接进入仲裁
-                if ((other.getMarkerScore() != UN_SELECTIVE_SCORE && result.getMarkerScore() == UN_SELECTIVE_SCORE) || (
-                        other.getMarkerScore() == UN_SELECTIVE_SCORE
-                                && result.getMarkerScore() != UN_SELECTIVE_SCORE)) {
+                if ((other.getMarkerScore() != UN_SELECTIVE_SCORE && result.getMarkerScore() == UN_SELECTIVE_SCORE)
+                        || (other.getMarkerScore() == UN_SELECTIVE_SCORE && result.getMarkerScore() != UN_SELECTIVE_SCORE)) {
                     history = buildArbitrateHistory(library, now);
                     break;
                 }
@@ -682,13 +766,12 @@ public class MarkServiceImpl implements MarkService {
                 if (Math.abs(other.getMarkerScore() - result.getMarkerScore()) > group.getArbitrateThreshold()) {
                     // 开启三评
                     if (group.getThirdPolicy().equals(ThirdPolicy.LOW_DIFF_HIGH_AVG)) {
-                        if (libraryDao.countByStudentIdAndGroupNumber(library.getStudentId(), library.getGroupNumber())
-                                == 2) {
+                        if (libraryDao.countByStudentIdAndGroupNumber(library.getStudentId(), library.getGroupNumber()) == 2) {
                             buildThirdLibrary(library, group);
                         } else {
                             // 两两比较,触发仲裁
-                            List<MarkLibrary> libraries = libraryDao
-                                    .findByStudentIdAndGroupNumber(library.getStudentId(), library.getGroupNumber());
+                            List<MarkLibrary> libraries = libraryDao.findByStudentIdAndGroupNumber(
+                                    library.getStudentId(), library.getGroupNumber());
                             history = buildArbitrateHistory(libraries, group.getArbitrateThreshold(), now);
                         }
                     } else {
@@ -769,7 +852,8 @@ public class MarkServiceImpl implements MarkService {
      * 管理员/组长打回某个评卷任务<br>
      * isRest为true时重置该评卷任务
      *
-     * @param library - 正评任务
+     * @param library
+     *            - 正评任务
      */
     @Override
     @Transactional
@@ -782,9 +866,8 @@ public class MarkServiceImpl implements MarkService {
         history.setUserId(userId);
         history.setReason(reason);
         Date now = new Date();
-        if (libraryDao.resetById(library.getId(), null, reason, userId, now,
-                isRest ? LibraryStatus.WAITING : LibraryStatus.REJECTED, LibraryStatus.MARKED, LibraryStatus.PROBLEM,
-                LibraryStatus.INSPECTED) > 0) {
+        if (libraryDao.resetById(library.getId(), null, reason, userId, now, isRest ? LibraryStatus.WAITING
+                : LibraryStatus.REJECTED, LibraryStatus.MARKED, LibraryStatus.PROBLEM, LibraryStatus.INSPECTED) > 0) {
             if (!isRest) {
                 markerService.updateRejectCountById(library.getMarkerId());
                 rejectHistoryDao.save(history);
@@ -798,9 +881,8 @@ public class MarkServiceImpl implements MarkService {
             // 开启三评时,打回1,2任务则删除第3条任务
             long count = libraryDao.countByStudentIdAndGroupNumber(library.getStudentId(), library.getGroupNumber());
             if (library.getTaskNumber() != 3 && count == 3) {
-                MarkLibrary third = libraryDao
-                        .findByStudentIdAndGroupNumberAndTaskNumber(library.getStudentId(), library.getGroupNumber(),
-                                3);
+                MarkLibrary third = libraryDao.findByStudentIdAndGroupNumberAndTaskNumber(library.getStudentId(),
+                        library.getGroupNumber(), 3);
                 trackDao.deleteByLibraryId(third.getId());
                 specialTagDao.deleteByLibraryId(third.getId());
                 problemHistoryDao.deleteByLibraryId(third.getId());
@@ -817,7 +899,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 管理员/组长重置某个试评任务
      *
-     * @param library - 试评任务
+     * @param library
+     *            - 试评任务
      */
     @Override
     @Transactional
@@ -835,12 +918,37 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 管理员/组长处理仲裁卷
      *
-     * @param history - 仲裁卷
+     * @param history
+     *            - 仲裁卷
      */
     @Override
     @Transactional
-    public void processArbitrate(ArbitrateHistory history) {
+    public void processArbitrate(MarkResult result, Integer userId) {
+        ArbitrateHistory history = arbitrateDao.findOne(result.getLibraryId());
+        history.setUserId(userId);
+        history.setTotalScore(result.isUnselective() ? UN_SELECTIVE_SCORE : result.getMarkerScore());
+        history.setScoreList(result.isUnselective() ? null : result.getScoreList());
+        history.setStatus(HistoryStatus.MARKED);
+        history.setUpdateTime(new Date());
         if (arbitrateDao.exists(history.getId())) {
+            // 保存阅卷轨迹
+            int unansweredCount = 0;
+            if (result.getTrackList() != null && !result.isUnselective()) {
+                headerTrackDao.deleteByPkStudentIdAndGroupNumber(history.getStudentId(), history.getGroupNumber());
+                List<HeaderTrack> tracks = result.getTrackList(history);
+                for (HeaderTrack t : tracks) {
+                    headerTrackDao.saveAndFlush(t);
+                    if (t.isUnanswered()) {
+                        unansweredCount++;
+                    }
+                }
+                history.setUnansweredCount(unansweredCount);
+            }
+            // 保存特殊标记
+            if (result.getSpecialTagList() != null && !result.isUnselective()) {
+                headerTagDao.deleteByStudentIdAndGroupNumber(history.getStudentId(), history.getGroupNumber());
+                headerTagDao.save(result.getHeaderTagList(history));
+            }
             arbitrateDao.saveAndFlush(history);
             libraryDao.updateHeaderResult(history.getStudentId(), history.getGroupNumber(), history.getUserId(),
                     history.getTotalScore(), history.getScoreList(), history.getUpdateTime(), LibraryStatus.ARBITRATED);
@@ -927,8 +1035,8 @@ public class MarkServiceImpl implements MarkService {
         boolean lessSelective = false;
         boolean mutiSelective = false;
         ExamStudent student = studentService.findById(studentId);
-        Map<Integer, List<SelectiveGroup>> indexMap = selectiveGroupService
-                .findGroupByExamIdAndSubjectCode(student.getExamId(), student.getSubjectCode());
+        Map<Integer, List<SelectiveGroup>> indexMap = selectiveGroupService.findGroupByExamIdAndSubjectCode(
+                student.getExamId(), student.getSubjectCode());
         for (Integer index : indexMap.keySet()) {
             // 循环选做题组
             List<SelectiveGroup> indexGroup = indexMap.get(index);
@@ -1056,9 +1164,8 @@ public class MarkServiceImpl implements MarkService {
                 // 有非完成状态的评卷任务,直接返回
                 return false;
             }
-            double markerScore = library.getStatus() == LibraryStatus.ARBITRATED ?
-                    library.getHeaderScore() :
-                    library.getMarkerScore();
+            double markerScore = library.getStatus() == LibraryStatus.ARBITRATED ? library.getHeaderScore() : library
+                    .getMarkerScore();
             if (markerScore == UN_SELECTIVE_SCORE) {
                 selectiveAll = true;
             }
@@ -1078,12 +1185,12 @@ public class MarkServiceImpl implements MarkService {
                 }
                 return -1;
             });
-            Double score1 =
-                    list.get(0).getHeaderScore() != null ? list.get(0).getHeaderScore() : list.get(0).getMarkerScore();
-            Double score2 =
-                    list.get(1).getHeaderScore() != null ? list.get(1).getHeaderScore() : list.get(1).getMarkerScore();
-            Double score3 =
-                    list.get(2).getHeaderScore() != null ? list.get(2).getHeaderScore() : list.get(2).getMarkerScore();
+            Double score1 = list.get(0).getHeaderScore() != null ? list.get(0).getHeaderScore() : list.get(0)
+                    .getMarkerScore();
+            Double score2 = list.get(1).getHeaderScore() != null ? list.get(1).getHeaderScore() : list.get(1)
+                    .getMarkerScore();
+            Double score3 = list.get(2).getHeaderScore() != null ? list.get(2).getHeaderScore() : list.get(2)
+                    .getMarkerScore();
             if ((score3 - score2) <= (score2 - score1)) {
                 list.remove(0);
             } else {
@@ -1155,7 +1262,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 更新某个评卷分组已评任务数量
      *
-     * @param group - 评卷分组
+     * @param group
+     *            - 评卷分组
      */
     @Override
     @Transactional
@@ -1163,8 +1271,7 @@ public class MarkServiceImpl implements MarkService {
         if (group.getStatus() == MarkStatus.FORMAL || group.getStatus() == MarkStatus.FINISH) {
             groupDao.updateMarkedCount(group.getExamId(), group.getSubjectCode(), group.getNumber(), (int) libraryDao
                     .countByExamIdAndSubjectCodeAndGroupNumberAndStatus(group.getExamId(), group.getSubjectCode(),
-                            group.getNumber(), LibraryStatus.MARKED, LibraryStatus.ARBITRATED,
-                            LibraryStatus.INSPECTED));
+                            group.getNumber(), LibraryStatus.MARKED, LibraryStatus.ARBITRATED, LibraryStatus.INSPECTED));
         } else if (group.getStatus() == MarkStatus.TRIAL) {
             groupDao.updateMarkedCount(group.getExamId(), group.getSubjectCode(), group.getNumber(),
                     (int) trialLibraryDao.countMarked(group.getExamId(), group.getSubjectCode(), group.getNumber()));
@@ -1174,21 +1281,20 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 更新某个评卷分组评卷任务总量
      *
-     * @param group - 评卷分组
+     * @param group
+     *            - 评卷分组
      */
     @Override
     @Transactional
     public void updateLibraryCount(MarkGroup group) {
         if (group.getStatus() == MarkStatus.FORMAL || group.getStatus() == MarkStatus.FINISH) {
-            group.setLibraryCount((int) libraryDao
-                    .countByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
-                            group.getNumber()));
+            group.setLibraryCount((int) libraryDao.countByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(),
+                    group.getSubjectCode(), group.getNumber()));
             groupDao.updateLibraryCount(group.getExamId(), group.getSubjectCode(), group.getNumber(),
                     group.getLibraryCount());
         } else if (group.getStatus() == MarkStatus.TRIAL) {
-            group.setLibraryCount((int) trialLibraryDao
-                    .countByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
-                            group.getNumber()));
+            group.setLibraryCount((int) trialLibraryDao.countByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(),
+                    group.getSubjectCode(), group.getNumber()));
             groupDao.updateLibraryCount(group.getExamId(), group.getSubjectCode(), group.getNumber(),
                     group.getLibraryCount());
         }
@@ -1197,8 +1303,10 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 更新某个科目所有评卷分组评卷任务数量
      *
-     * @param examId      - 考试ID
-     * @param subjectCode - 科目代码
+     * @param examId
+     *            - 考试ID
+     * @param subjectCode
+     *            - 科目代码
      */
     @Transactional
     @Override
@@ -1213,8 +1321,10 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 根据考生、学习中心、评卷分组构造试评评卷任务
      *
-     * @param student - 考生
-     * @param group   - 评卷分组
+     * @param student
+     *            - 考生
+     * @param group
+     *            - 评卷分组
      */
     @Override
     @Transactional
@@ -1243,22 +1353,25 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 重置评卷分组的连带操作
      *
-     * @param group - 评卷分组
+     * @param group
+     *            - 评卷分组
      */
     private void resetGroup(MarkGroup group) {
         if (group.getStatus() == MarkStatus.FORMAL) {
             trackDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                     group.getNumber());
             specialTagDao.deleteByExamAndSubjectAndGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
+            headerTagDao.deleteByExamAndSubjectAndGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
+            headerTrackDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
+                    group.getNumber());
             arbitrateDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                     group.getNumber());
             problemHistoryDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                     group.getNumber());
             libraryDao.resetByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                     group.getNumber(), LibraryStatus.WAITING);
-            libraryDao
-                    .deleteByExamIdAndSubjectCodeAndGroupNumberAndTaskNumber(group.getExamId(), group.getSubjectCode(),
-                            group.getNumber(), 3);
+            libraryDao.deleteByExamIdAndSubjectCodeAndGroupNumberAndTaskNumber(group.getExamId(),
+                    group.getSubjectCode(), group.getNumber(), 3);
             markerDao.resetByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
                     group.getNumber());
             resetStudentGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
@@ -1275,7 +1388,8 @@ public class MarkServiceImpl implements MarkService {
     /**
      * 计算并更新指定评卷员的评卷质量指标
      *
-     * @param marker - 评卷员
+     * @param marker
+     *            - 评卷员
      */
     @Override
     @Transactional
@@ -1294,9 +1408,8 @@ public class MarkServiceImpl implements MarkService {
             if (library.getStatus() == LibraryStatus.MARKED || library.getStatus() == LibraryStatus.INSPECTED) {
                 validCount++;
             }
-            double score = library.getMarkerScore() != null && library.getMarkerScore() != UN_SELECTIVE_SCORE ?
-                    library.getMarkerScore() :
-                    0;
+            double score = library.getMarkerScore() != null && library.getMarkerScore() != UN_SELECTIVE_SCORE ? library
+                    .getMarkerScore() : 0;
             int spent = library.getMarkerSpent() != null ? library.getMarkerSpent() : 0;
 
             sumScore += score;
@@ -1363,9 +1476,8 @@ public class MarkServiceImpl implements MarkService {
         updateStudentGroupScore(library.getStudentId(), group.getExamId(), group.getSubjectCode(), group,
                 library.getMarkerScore(), library.getScoreList());
         // 未分组的题目
-        long unGroupQuestionCount = questionService
-                .countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(group.getExamId(), group.getSubjectCode(),
-                        false);
+        long unGroupQuestionCount = questionService.countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(
+                group.getExamId(), group.getSubjectCode(), false);
         long groupCount = groupDao.countByExamIdAndSubjectCode(group.getExamId(), group.getSubjectCode());
         checkStudentSubjective(library.getStudentId(), groupCount, unGroupQuestionCount);
     }
@@ -1383,9 +1495,8 @@ public class MarkServiceImpl implements MarkService {
             updateStudentGroupScore(studentId, group.getExamId(), group.getSubjectCode(), group, group.getMarkScore(),
                     group.getMarkScoreDetail());
             // 未分组的题目
-            long unGroupQuestionCount = questionService
-                    .countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(group.getExamId(), group.getSubjectCode(),
-                            false);
+            long unGroupQuestionCount = questionService.countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(
+                    group.getExamId(), group.getSubjectCode(), false);
             long groupCount = groupDao.countByExamIdAndSubjectCode(group.getExamId(), group.getSubjectCode());
             checkStudentSubjective(studentId, groupCount, unGroupQuestionCount);
         } else {
@@ -1422,9 +1533,8 @@ public class MarkServiceImpl implements MarkService {
         scoreDao.deleteByExamIdAndSubjectCodeAndGroupNumber(examId, subjectCode, groupNumber);
         rejectHistoryDao.deleteByExamIdAndSubjectCodeAndGroupNumber(examId, subjectCode, groupNumber);
         selectiveStudentDao.deleteByExamIdAndSubjectCode(examId, subjectCode);
-        studentService
-                .updateSubjectiveStatusAndScoreAndInspectorId(examId, subjectCode, SubjectiveStatus.UNMARK, 0, null,
-                        null, null);
+        studentService.updateSubjectiveStatusAndScoreAndInspectorId(examId, subjectCode, SubjectiveStatus.UNMARK, 0,
+                null, null, null);
         inspectHistoryService.deleteByExamIdAndSubjectCode(examId, subjectCode);
     }
 
@@ -1442,10 +1552,10 @@ public class MarkServiceImpl implements MarkService {
     private void updateStudentGroupScore(Integer studentId, Integer examId, String subjectCode, MarkGroup group,
             double score, List<ScoreItem> scoreList) {
         // scoreDao.deleteByStudentIdAndGroupNumber(studentId, groupNumber);
-        List<ExamQuestion> questions = questionService
-                .findByExamAndSubjectAndObjectiveAndGroupNumber(examId, subjectCode, false, group.getNumber());
-        List<SubjectiveScore> subjectiveScores = scoreService
-                .findByStudentIdAndGroupNumber(studentId, group.getNumber());
+        List<ExamQuestion> questions = questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId,
+                subjectCode, false, group.getNumber());
+        List<SubjectiveScore> subjectiveScores = scoreService.findByStudentIdAndGroupNumber(studentId,
+                group.getNumber());
         for (int i = 0; i < questions.size(); i++) {
             ExamQuestion question = questions.get(i);
             SubjectiveScore ss;
@@ -1473,12 +1583,12 @@ public class MarkServiceImpl implements MarkService {
                 ss.setUncalculate(true);
             }
             if (group.getArbitrateThreshold() != null && group.getArbitrateThreshold() > 0) {
-                ss.setUnansweredCount(0);
+                ss.setUnansweredCount(headerTrackDao.countByStudentIdAndQuestionNumberAndUnanswered(studentId,
+                        question.getQuestionNumber(), true));
             } else {
                 if (MarkStatus.TRIAL.equals(group.getStatus())) {
-                    ss.setUnansweredCount(trialTrackDao
-                            .countByStudentIdAndQuestionNumberAndUnanswered(studentId, question.getQuestionNumber(),
-                                    true));
+                    ss.setUnansweredCount(trialTrackDao.countByStudentIdAndQuestionNumberAndUnanswered(studentId,
+                            question.getQuestionNumber(), true));
                 } else {
                     ss.setUnansweredCount(trackDao.countByStudentIdAndQuestionNumberAndUnanswered(studentId,
                             question.getQuestionNumber(), true));
@@ -1552,9 +1662,8 @@ public class MarkServiceImpl implements MarkService {
         Date now = new Date();
         for (Integer groupNumber : map.keySet()) {
             List<MarkLibrary> list = libraryDao.findByStudentIdAndGroupNumber(student.getId(), groupNumber);
-            List<ExamQuestion> questions = questionService
-                    .findByExamAndSubjectAndObjectiveAndGroupNumber(student.getExamId(), student.getSubjectCode(),
-                            false, groupNumber);
+            List<ExamQuestion> questions = questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(
+                    student.getExamId(), student.getSubjectCode(), false, groupNumber);
             List<MarkStepDTO> qList = map.get(groupNumber);
             MarkGroup group = groupDao.findOne(student.getExamId(), student.getSubjectCode(), groupNumber);
             int count = 0;
@@ -1580,22 +1689,24 @@ public class MarkServiceImpl implements MarkService {
                     rejectHistoryDao.save(history);
                     trackDao.deleteByLibraryId(library.getId());
                     specialTagDao.deleteByLibraryId(library.getId());
+                    headerTagDao.deleteByStudentIdAndGroupNumber(library.getStudentId(), groupNumber);
+                    headerTrackDao.deleteByPkStudentIdAndGroupNumber(library.getStudentId(), groupNumber);
                     arbitrateDao.deleteByStudentIdAndGroupNumber(student.getId(), groupNumber);
                     count++;
                     continue;
                 }
-                if (library.getStatus().equals(LibraryStatus.MARKED) || library.getStatus()
-                        .equals(LibraryStatus.INSPECTED)) {
+                if (library.getStatus().equals(LibraryStatus.MARKED)
+                        || library.getStatus().equals(LibraryStatus.INSPECTED)) {
                     List<ScoreItem> sList = library.getScoreList();
                     for (MarkStepDTO markStepDTO : qList) {
-                        trackDao.deleteByLibraryIdAndQuestionNumber(library.getId(),
-                                markStepDTO.getMainNumber() + "." + markStepDTO.getSubNumber());
+                        trackDao.deleteByLibraryIdAndQuestionNumber(library.getId(), markStepDTO.getMainNumber() + "."
+                                + markStepDTO.getSubNumber());
                         scoreDao.updateRejected(library.getStudentId(), markStepDTO.getMainNumber(),
                                 markStepDTO.getSubNumber(), true);
                         for (int i = 0; i < questions.size(); i++) {
                             ExamQuestion question = questions.get(i);
-                            if (markStepDTO.getMainNumber() == question.getMainNumber() && markStepDTO.getSubNumber()
-                                    .equals(question.getSubNumber())) {
+                            if (markStepDTO.getMainNumber() == question.getMainNumber()
+                                    && markStepDTO.getSubNumber().equals(question.getSubNumber())) {
                                 sList.remove(i);
                                 sList.add(i, new ScoreItem(false));
                             }
@@ -1613,10 +1724,9 @@ public class MarkServiceImpl implements MarkService {
                         // markerScoreList.append(",");
                         // }
                     }
-                    if (libraryDao
-                            .updateMarkerResult(library.getId(), LibraryStatus.REJECTED, library.getMarkerId(), null,
-                                    StringUtils.join(markerScoreList, ","), null, null, reason, userId, now,
-                                    LibraryStatus.MARKED, LibraryStatus.INSPECTED) == 1) {
+                    if (libraryDao.updateMarkerResult(library.getId(), LibraryStatus.REJECTED, library.getMarkerId(),
+                            null, StringUtils.join(markerScoreList, ","), null, null, reason, userId, now,
+                            LibraryStatus.MARKED, LibraryStatus.INSPECTED) == 1) {
                         markerService.updateRejectCountById(library.getMarkerId());
                         history.setRejectScoreList(StringUtils.join(markerScoreList, ","));
                         rejectHistoryDao.save(history);
@@ -1627,9 +1737,8 @@ public class MarkServiceImpl implements MarkService {
             if (count > 0) {
                 updateMarkedCount(group);
                 resetStudentGroup(student.getId(), student.getExamId(), student.getSubjectCode(), groupNumber);
-                studentService
-                        .updateSubjectiveStatusAndTimeAndInspectorId(student.getId(), SubjectiveStatus.UNMARK, null,
-                                null);
+                studentService.updateSubjectiveStatusAndTimeAndInspectorId(student.getId(), SubjectiveStatus.UNMARK,
+                        null, null);
             }
         }
         return true;
@@ -1642,8 +1751,8 @@ public class MarkServiceImpl implements MarkService {
             return false;
         }
         for (ExamQuestion question : list) {
-            SelectiveGroup selectiveGroup = selectiveGroupService
-                    .findOne(question.getExamId(), question.getSubjectCode(), question.getMainNumber());
+            SelectiveGroup selectiveGroup = selectiveGroupService.findOne(question.getExamId(),
+                    question.getSubjectCode(), question.getMainNumber());
             if (selectiveGroup != null) {
                 continue;
             }
@@ -1654,9 +1763,9 @@ public class MarkServiceImpl implements MarkService {
                 String subjectCode = question.getSubjectCode();
                 boolean objective = question.isObjective();
                 ExamSubject subject = subjectService.find(examId, subjectCode);
-                double totalScore = objective ?
-                        BigDecimalUtils.sub(subject.getObjectiveScore(), question.getTotalScore()) :
-                        BigDecimalUtils.sub(subject.getSubjectiveScore(), question.getTotalScore());
+                double totalScore = objective ? BigDecimalUtils.sub(subject.getObjectiveScore(),
+                        question.getTotalScore()) : BigDecimalUtils.sub(subject.getSubjectiveScore(),
+                        question.getTotalScore());
                 questionService.deleteById(question.getId());
                 if (objective) {
                     examService.updateObjectiveStatus(examId, ObjectiveStatus.WAITING);
@@ -1673,9 +1782,8 @@ public class MarkServiceImpl implements MarkService {
                         // subjectCode);
                         inspectHistoryService.deleteByExamIdAndSubjectCode(examId, subjectCode);
                     } else {
-                        List<Integer> studentList = studentService
-                                .findIdByExamIdAndSubjectCodeAndSubjectiveStatus(examId, subjectCode,
-                                        SubjectiveStatus.UNMARK, SubjectiveStatus.MARKED);
+                        List<Integer> studentList = studentService.findIdByExamIdAndSubjectCodeAndSubjectiveStatus(
+                                examId, subjectCode, SubjectiveStatus.UNMARK, SubjectiveStatus.MARKED);
                         for (Integer studentId : studentList) {
                             checkStudentSubjective(studentId, groupCount, unGroupQuestionCount);
                         }
@@ -1690,9 +1798,8 @@ public class MarkServiceImpl implements MarkService {
     @Override
     @Transactional
     public boolean rejectLibrary(MarkLibrary library, MarkStepDTO[] questionList, Integer userId, String reason) {
-        List<ExamQuestion> questions = questionService
-                .findByExamAndSubjectAndObjectiveAndGroupNumber(library.getExamId(), library.getSubjectCode(), false,
-                        library.getGroupNumber());
+        List<ExamQuestion> questions = questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(
+                library.getExamId(), library.getSubjectCode(), false, library.getGroupNumber());
         if (questionList.length == questions.size()) {
             return rejectLibrary(library, userId, reason, false);
         }
@@ -1707,14 +1814,14 @@ public class MarkServiceImpl implements MarkService {
         Date now = new Date();
         List<ScoreItem> sList = library.getScoreList();
         for (MarkStepDTO markStepDTO : questionList) {
-            trackDao.deleteByLibraryIdAndQuestionNumber(library.getId(),
-                    markStepDTO.getMainNumber() + "." + markStepDTO.getSubNumber());
+            trackDao.deleteByLibraryIdAndQuestionNumber(library.getId(), markStepDTO.getMainNumber() + "."
+                    + markStepDTO.getSubNumber());
             scoreDao.updateRejected(library.getStudentId(), markStepDTO.getMainNumber(), markStepDTO.getSubNumber(),
                     true);
             for (int i = 0; i < questions.size(); i++) {
                 ExamQuestion question = questions.get(i);
-                if (markStepDTO.getMainNumber() == question.getMainNumber() && markStepDTO.getSubNumber()
-                        .equals(question.getSubNumber())) {
+                if (markStepDTO.getMainNumber() == question.getMainNumber()
+                        && markStepDTO.getSubNumber().equals(question.getSubNumber())) {
                     sList.remove(i);
                     sList.add(i, new ScoreItem(false));
                 }
@@ -1744,9 +1851,8 @@ public class MarkServiceImpl implements MarkService {
             // 开启三评时,打回1,2任务则删除第3条任务
             long count = libraryDao.countByStudentIdAndGroupNumber(library.getStudentId(), library.getGroupNumber());
             if (library.getTaskNumber() != 3 && count == 3) {
-                MarkLibrary third = libraryDao
-                        .findByStudentIdAndGroupNumberAndTaskNumber(library.getStudentId(), library.getGroupNumber(),
-                                3);
+                MarkLibrary third = libraryDao.findByStudentIdAndGroupNumberAndTaskNumber(library.getStudentId(),
+                        library.getGroupNumber(), 3);
                 trackDao.deleteByLibraryId(third.getId());
                 specialTagDao.deleteByLibraryId(third.getId());
                 problemHistoryDao.deleteByLibraryId(third.getId());

+ 20 - 18
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkSpecialTagServiceImpl.java

@@ -4,7 +4,6 @@ import cn.com.qmth.stmms.biz.common.BaseQueryService;
 import cn.com.qmth.stmms.biz.mark.dao.MarkSpecialTagDao;
 import cn.com.qmth.stmms.biz.mark.model.MarkSpecialTag;
 import cn.com.qmth.stmms.biz.mark.service.MarkSpecialTagService;
-import cn.com.qmth.stmms.common.enums.LibraryStatus;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -14,31 +13,34 @@ import java.util.List;
 
 @Service
 public class MarkSpecialTagServiceImpl extends BaseQueryService<MarkSpecialTag> implements MarkSpecialTagService {
+
     @Autowired
     MarkSpecialTagDao markSpecialTagDao;
 
+    // @Transactional
+    // @Override
+    // public MarkSpecialTag save(MarkSpecialTag tag) {
+    // return markSpecialTagDao.save(tag);
+    // }
+
     @Transactional
     @Override
-    public MarkSpecialTag save(MarkSpecialTag tag){
-      return  markSpecialTagDao.save(tag);
-    }
-    @Transactional
-    @Override
-    public void deleteByLibraryId(Integer libraryId){
+    public void deleteByLibraryId(Integer libraryId) {
         markSpecialTagDao.deleteByLibraryId(libraryId);
     }
+
     @Override
-    public List<MarkSpecialTag> findByLibraryId(Integer libraryId){
+    public List<MarkSpecialTag> findByLibraryId(Integer libraryId) {
         return markSpecialTagDao.findByLibraryIdOrderByIdAsc(libraryId);
     }
-	@Override
-	public void deleteByMarkerId(Integer markerId) {
-		markSpecialTagDao.deleteByMarkerId(markerId,LibraryStatus.ARBITRATED,LibraryStatus.WAIT_ARBITRATE);
-	}
-	@Override
-	public void deleteByExamAndSubjectAndGroup(Integer examId,
-			String subjectCode, Integer groupNumber) {
-		markSpecialTagDao.deleteByExamAndSubjectAndGroup(examId,subjectCode,groupNumber);
-		
-	}
+
+    // @Override
+    // public void deleteByMarkerId(Integer markerId) {
+    // markSpecialTagDao.deleteByMarkerId(markerId,LibraryStatus.ARBITRATED,LibraryStatus.WAIT_ARBITRATE);
+    // }
+    @Override
+    public void deleteByExamAndSubjectAndGroup(Integer examId, String subjectCode, Integer groupNumber) {
+        markSpecialTagDao.deleteByExamAndSubjectAndGroup(examId, subjectCode, groupNumber);
+
+    }
 }

+ 9 - 10
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkTrackServiceImpl.java

@@ -4,7 +4,6 @@ import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import cn.com.qmth.stmms.biz.common.BaseQueryService;
 import cn.com.qmth.stmms.biz.mark.dao.MarkTrackDao;
@@ -17,10 +16,10 @@ public class MarkTrackServiceImpl extends BaseQueryService<MarkTrack> implements
     @Autowired
     private MarkTrackDao markTrackDao;
 
-    @Override
-    public List<MarkTrack> findByStudentId(Integer studentId) {
-        return markTrackDao.findByStudentId(studentId);
-    }
+    // @Override
+    // public List<MarkTrack> findByStudentId(Integer studentId) {
+    // return markTrackDao.findByStudentId(studentId);
+    // }
 
     @Override
     public List<MarkTrack> findByLibraryId(Integer libraryId) {
@@ -32,10 +31,10 @@ public class MarkTrackServiceImpl extends BaseQueryService<MarkTrack> implements
         return markTrackDao.findByPkLibraryIdAndPkQuestionNumberOrderByPkNumberAsc(libraryId, questionNumber);
     }
 
-    @Transactional
-    @Override
-    public MarkTrack save(MarkTrack track) {
-        return markTrackDao.save(track);
-    }
+    // @Transactional
+    // @Override
+    // public MarkTrack save(MarkTrack track) {
+    // return markTrackDao.save(track);
+    // }
 
 }

+ 27 - 2
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/TaskServiceImpl.java

@@ -29,7 +29,11 @@ import cn.com.qmth.stmms.biz.exam.service.MarkerService;
 import cn.com.qmth.stmms.biz.exam.service.SelectiveGroupService;
 import cn.com.qmth.stmms.biz.exam.service.SubjectiveScoreService;
 import cn.com.qmth.stmms.biz.file.service.FileService;
+import cn.com.qmth.stmms.biz.mark.dao.HeaderTagDao;
+import cn.com.qmth.stmms.biz.mark.dao.HeaderTrackDao;
 import cn.com.qmth.stmms.biz.mark.model.ArbitrateHistory;
+import cn.com.qmth.stmms.biz.mark.model.HeaderTag;
+import cn.com.qmth.stmms.biz.mark.model.HeaderTrack;
 import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
 import cn.com.qmth.stmms.biz.mark.model.MarkSpecialTag;
 import cn.com.qmth.stmms.biz.mark.model.MarkStepDTO;
@@ -80,12 +84,18 @@ public class TaskServiceImpl implements TaskService {
     @Autowired
     private MarkTrackService trackService;
 
+    @Autowired
+    private HeaderTrackDao headerTrackDao;
+
     @Autowired
     private MarkGroupService groupService;
 
     @Autowired
     private MarkSpecialTagService markSpecialTagService;
 
+    @Autowired
+    private HeaderTagDao headerTagDao;
+
     @Autowired
     private MarkerService markerService;
 
@@ -133,6 +143,7 @@ public class TaskServiceImpl implements TaskService {
         task.setLibraryId(history.getId());
         task.setSecretNumber(history.getSecretNumber());
         task.setQuestionList(buildArbitrateStep(group, history));
+        task.setSpecialTagList(getHeaderTagList(history.getStudentId(), group.getNumber()));
         task.setSliceUrls(fileService.getSliceUris(student.getExamId(), student.getSecretNumber(), 1,
                 student.getSliceCount()));
         task.setSliceConfig(group.getPictureConfigList());
@@ -151,7 +162,8 @@ public class TaskServiceImpl implements TaskService {
         List<MarkStepDTO> list = new LinkedList<MarkStepDTO>();
         List<ExamQuestion> sList = questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(group.getExamId(),
                 group.getSubjectCode(), false, group.getNumber());
-        List<MarkTrack> tracks = new ArrayList<MarkTrack>();
+        List<HeaderTrack> tracks = headerTrackDao.findByPkStudentIdAndGroupNumber(history.getStudentId(),
+                group.getNumber());
         List<ScoreItem> sItems = new ArrayList<ScoreItem>();
         if (history != null) {
             sItems = history.getScoreItemList();
@@ -170,7 +182,7 @@ public class TaskServiceImpl implements TaskService {
                 }
                 // 增加阅卷轨迹列表获取
                 String questionNumber = question.getQuestionNumber();
-                for (MarkTrack track : tracks) {
+                for (HeaderTrack track : tracks) {
                     if (track.getQuestionNumber().equals(questionNumber)) {
                         step.addTrack(new TrackDTO(track));
                     }
@@ -362,6 +374,19 @@ public class TaskServiceImpl implements TaskService {
         return step;
     }
 
+    public SpecialTagDTO[] getHeaderTagList(Integer studentId, Integer groupNumber) {
+        SpecialTagDTO[] specialTags = null;
+        List<HeaderTag> list = headerTagDao.findByStudentIdAndGroupNumberOrderByIdAsc(studentId, groupNumber);
+        if (!list.isEmpty()) {
+            specialTags = new SpecialTagDTO[list.size()];
+            for (int i = 0; i < list.size(); i++) {
+                SpecialTagDTO specialTagDTO = new SpecialTagDTO(list.get(i));
+                specialTags[i] = specialTagDTO;
+            }
+        }
+        return specialTags;
+    }
+
     public SpecialTagDTO[] getMarkSpecialTagList(Integer libraryId) {
         SpecialTagDTO[] specialTags = null;
         List<MarkSpecialTag> list = markSpecialTagService.findByLibraryId(libraryId);

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

@@ -117,9 +117,10 @@ public interface MarkService {
     /**
      * 管理员/组长处理仲裁卷
      *
-     * @param history
+     * @param markResult
+     * @param userId
      */
-    void processArbitrate(ArbitrateHistory history);
+    void processArbitrate(MarkResult markResult, Integer userId);
 
     /**
      * 管理员/组长重置(打回)某个评卷任务

+ 2 - 2
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkSpecialTagService.java

@@ -6,13 +6,13 @@ import cn.com.qmth.stmms.biz.mark.model.MarkSpecialTag;
 
 public interface MarkSpecialTagService {
 
-    public MarkSpecialTag save(MarkSpecialTag tag);
+    // public MarkSpecialTag save(MarkSpecialTag tag);
 
     public void deleteByLibraryId(Integer libraryId);
 
     public List<MarkSpecialTag> findByLibraryId(Integer libraryId);
 
-    public void deleteByMarkerId(Integer markerId);
+    // public void deleteByMarkerId(Integer markerId);
 
     public void deleteByExamAndSubjectAndGroup(Integer examId, String subjectCode, Integer number);
 

+ 2 - 2
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkTrackService.java

@@ -6,9 +6,9 @@ import cn.com.qmth.stmms.biz.mark.model.MarkTrack;
 
 public interface MarkTrackService {
 
-    MarkTrack save(MarkTrack track);
+    // MarkTrack save(MarkTrack track);
 
-    List<MarkTrack> findByStudentId(Integer studentId);
+    // List<MarkTrack> findByStudentId(Integer studentId);
 
     List<MarkTrack> findByLibraryId(Integer libraryId);
 

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

@@ -105,7 +105,7 @@ public class AnswerCheckController extends BaseExamController {
             @RequestParam(required = false) Boolean absent, @RequestParam String paperType) {
         ExamStudent student = studentService.findById(studentId);
         answers = StringEscapeUtils.unescapeHtml(StringUtils.trimToNull(answers));
-        if (student != null) {
+        if (student != null && student.isUpload()) {
             if (absent != null) {
                 student.setAbsent(absent);
             }

+ 1 - 7
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ArbitrateController.java

@@ -1,7 +1,6 @@
 package cn.com.qmth.stmms.admin.exam;
 
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -324,12 +323,7 @@ public class ArbitrateController extends BaseExamController {
                 lockService.watch(LockType.EXAM_SUBJECT, history.getExamId(), history.getSubjectCode());
                 lockService.watch(LockType.GROUP, history.getExamId(), history.getSubjectCode(),
                         history.getGroupNumber());
-                history.setUserId(wu.getUser().getId());
-                history.setTotalScore(markResult.isUnselective() ? UN_SELECTIVE_SCORE : markResult.getMarkerScore());
-                history.setScoreList(markResult.isUnselective() ? null : markResult.getScoreList());
-                history.setStatus(HistoryStatus.MARKED);
-                history.setUpdateTime(new Date());
-                markService.processArbitrate(history);
+                markService.processArbitrate(markResult, wu.getUser().getId());
                 releaseTask(history.getId());
                 result.accumulate("success", true);
                 result.accumulate("status", status(request, history.getSubjectCode(), history.getGroupNumber()));

+ 87 - 36
stmms-web/src/main/webapp/sql/stmms_ft.sql

@@ -589,6 +589,7 @@ CREATE TABLE `m_arbitrate_history`
     `user_id`       int(11)      DEFAULT NULL COMMENT '处理人ID',
     `total_score`   double       DEFAULT NULL COMMENT '总分',
     `score_list`    text		 DEFAULT NULL COMMENT '给分明细',
+	`unanswered_count`  int(11)		 DEFAULT NULL COMMENT '未作答的步骤数量',
     `create_time`   datetime    NOT NULL COMMENT '创建时间',
     `update_time`   datetime     DEFAULT NULL COMMENT '处理时间',
     PRIMARY KEY (`id`),
@@ -711,6 +712,59 @@ CREATE TABLE `m_track`
 ) ENGINE = InnoDB
   DEFAULT CHARSET = utf8mb4 COMMENT ='轨迹给分表';
 
+  
+# Dump of table m_header_tag
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `m_header_tag`;
+
+CREATE TABLE `m_header_tag`
+(
+    `id`           int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `student_id`   int(11)     NOT NULL COMMENT '考生ID',
+	`group_number` int(11)     NOT NULL COMMENT '大题题号',
+	`user_id`      int(11)     NOT NULL COMMENT '用户ID',
+    `tag_name`     varchar(64) NOT NULL COMMENT '标记内容',
+    `position_x`   double      NOT NULL COMMENT 'X轴位置',
+    `position_y`   double      NOT NULL COMMENT 'Y轴位置',
+    `offset_index` int(11)     NOT NULL COMMENT '裁切图序号',
+    `offset_x`     int(11)     NOT NULL COMMENT '裁切图X轴坐标',
+    `offset_y`     int(11)     NOT NULL COMMENT '裁切图Y轴坐标',
+    PRIMARY KEY (`id`),
+    KEY `index1` (`student_id`,`group_number`),
+	KEY `index2` (`user_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='组长特殊标记表';
+
+
+# Dump of table m_header_track
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `m_header_track`;
+
+CREATE TABLE `m_header_track`
+(
+	`student_id`      int(11)      NOT NULL COMMENT '考生ID',
+    `question_number` varchar(128) NOT NULL COMMENT '完整题号',
+    `number`          int(11)      NOT NULL COMMENT '序号',
+    `exam_id`         int(11)      NOT NULL COMMENT '考试ID',
+    `subject_code`    varchar(32)  NOT NULL COMMENT '科目代码',
+    `group_number`    int(11)      NOT NULL COMMENT '大题题号',
+    `user_id`         int(11)      NOT NULL COMMENT '用户ID',
+    `score`           double       NOT NULL COMMENT '给分',
+    `position_x`      double       NOT NULL COMMENT 'X轴位置',
+    `position_y`      double       NOT NULL COMMENT 'Y轴位置',
+    `offset_index`    int(11)      NOT NULL COMMENT '裁切图序号',
+    `offset_x`        int(11)      NOT NULL COMMENT '裁切图X轴坐标',
+    `offset_y`        int(11)      NOT NULL COMMENT '裁切图Y轴坐标',
+    `unanswered`      tinyint(1)   NOT NULL COMMENT '未作答',
+    PRIMARY KEY (`student_id`, `question_number`, `number`),
+    KEY `index1` (`student_id`, `group_number`),
+    KEY `index2` (`user_id`),
+    KEY `index3` (`exam_id`, `subject_code`, `group_number`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='组长轨迹给分表';
+
 
 # Dump of table m_problem_type
 # ------------------------------------------------------------
@@ -1132,13 +1186,13 @@ CREATE TABLE `eb_answer_card`
 DROP TABLE IF EXISTS `eb_score_verify`;  
 CREATE TABLE `eb_score_verify` 
 (
-	`id`           int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
-    `exam_id`			int(11)     NOT NULL COMMENT '考试ID',
+	`id`			int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `exam_id`		int(11)     NOT NULL COMMENT '考试ID',
   	`user_id`		int(11) 	NOT NULL COMMENT '操作人ID',
-    `student_id`			int(11)     NOT NULL COMMENT '考生ID',
+    `student_id`	int(11)     NOT NULL COMMENT '考生ID',
   	`flagged`		tinyint(1)  DEFAULT NULL COMMENT '是否被标记',
-  	`create_time`  		datetime     NOT NULL COMMENT '创建时间',
-  	`verify_time`  		datetime     DEFAULT NULL COMMENT '校验时间',
+  	`create_time`	datetime    NOT NULL COMMENT '创建时间',
+  	`verify_time`	datetime    DEFAULT NULL COMMENT '校验时间',
   PRIMARY KEY (`id`),
   UNIQUE KEY `index1` (`exam_id`,`user_id`,`student_id`)
 )  ENGINE = InnoDB
@@ -1163,9 +1217,9 @@ CREATE TABLE `eb_answer_card_subject`
 DROP TABLE IF EXISTS `eb_user_student`;
 CREATE TABLE `eb_user_student`
 (
-    `id`           int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
-    `user_id`      int(11)     NOT NULL COMMENT '用户ID',
-    `exam_number` 	varchar(64)	   NOT NULL COMMENT '考生ID',
+    `id`			int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `user_id`		int(11)     NOT NULL COMMENT '用户ID',
+    `exam_number` 	varchar(64)	NOT NULL COMMENT '考生ID',
     PRIMARY KEY (`id`),
     UNIQUE KEY `index1` (`user_id`, `exam_number`)
 ) ENGINE = InnoDB
@@ -1174,53 +1228,50 @@ CREATE TABLE `eb_user_student`
 DROP TABLE IF EXISTS `b_role_info`;
 CREATE TABLE `b_role_info`
 (
-    `id`             int(11)      NOT NULL AUTO_INCREMENT,
-    `school_id` int(11) NOT NULL,
-    `code`           varchar(50) NOT NULL,
-    `name`           varchar(50) NOT NULL,
-    `seq`            int(11)         NOT NULL,
-    `updater_id` int(11)      DEFAULT NULL,
-    `update_time`  		datetime     DEFAULT NULL, 
+    `id`             int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `school_id` 	 int(11)	 NOT NULL COMMENT '学校ID',
+    `code`           varchar(64) NOT NULL COMMENT '角色CODE',
+    `name`           varchar(64) NOT NULL COMMENT '名称',
+    `seq`            int(11)     NOT NULL COMMENT '排序',
+    `updater_id` 	 int(11)	 DEFAULT NULL COMMENT '更新人ID',
+    `update_time`	 datetime    DEFAULT NULL COMMENT '更新时间', 
     PRIMARY KEY (`id`),
     UNIQUE KEY `IDX_ROLE_INFO_01` (`school_id`,`code`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4
-  COLLATE = utf8mb4_bin;
+  DEFAULT CHARSET = utf8mb4 COMMENT ='角色表';
   
 DROP TABLE IF EXISTS `b_privilege`;
 CREATE TABLE `b_privilege`
 (
-    `id`             int(11)      NOT NULL AUTO_INCREMENT,
-    `code`           varchar(50) NOT NULL,
-    `name`           varchar(50) NOT NULL,
-    `parent_code`    varchar(50)      NOT NULL,
-    `privilege_type` varchar(50) NOT NULL,
-    `privilege_uri`  varchar(50)  DEFAULT NULL,
-    `seq`            int(11)         NOT NULL,
-    `level`          int(11)         NOT NULL,
-    `icon` varchar(50)      DEFAULT NULL,
-    `i18n` varchar(50)      DEFAULT NULL,
+    `id`             int(11)		NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `code`           varchar(64)	NOT NULL COMMENT '权限CODE',
+    `name`           varchar(64)	NOT NULL COMMENT '名称',
+    `parent_code`    varchar(64)	NOT NULL COMMENT '父权限CODE',
+    `privilege_type` varchar(64)	NOT NULL COMMENT '类型',
+    `privilege_uri`  varchar(64)	DEFAULT NULL COMMENT 'URI',
+    `seq`            int(11)		NOT NULL COMMENT '排序',
+    `level`          int(11)		NOT NULL COMMENT '树结构层级',
+    `icon` 			 varchar(64)	DEFAULT NULL COMMENT '图表',
+    `i18n` 			 varchar(64)	DEFAULT NULL COMMENT '国际化',
     PRIMARY KEY (`id`),
     UNIQUE KEY `IDX_PRIVILEGE_01` (`code`),
     KEY `IDX_PRIVILEGE_02` (`parent_code`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4
-  COLLATE = utf8mb4_bin;
+  DEFAULT CHARSET = utf8mb4 COMMENT ='权限表';
 
 
 DROP TABLE IF EXISTS `b_role_privilege`;
 CREATE TABLE `b_role_privilege`
 (
-	`id`             int(11)      NOT NULL AUTO_INCREMENT,
-	`school_id` int(11) NOT NULL,
-    `role_code`    varchar(50) NOT NULL,
-    `privilege_code` varchar(50)      NOT NULL,
-    `enable`       tinyint(1)      NOT NULL,
+	`id`				int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
+	`school_id` 		int(11) 	NOT NULL COMMENT '学校ID',
+    `role_code`			varchar(64) NOT NULL COMMENT '角色CODE',
+    `privilege_code`	varchar(64)	NOT NULL COMMENT '权限CODE',
+    `enable`       		tinyint(1)	NOT NULL COMMENT '启用禁用',
     PRIMARY KEY (`id`),
     UNIQUE KEY `IDX_ROLE_PRIVILEGE_01`(`school_id`,`role_code`, `privilege_code`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4
-  COLLATE = utf8mb4_bin;
+  DEFAULT CHARSET = utf8mb4 COMMENT ='角色权限关联表';
   
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 VALUES ('user_list', '用户管理', 'root_code', 'MENU', '/admin/user/list', 10,1,'icon-user','index.user');

+ 83 - 30
stmms-web/src/main/webapp/sql/upgrade/1.3.14.sql

@@ -85,7 +85,7 @@ CREATE TABLE `eb_answer_card_subject`
 )  ENGINE = InnoDB
   DEFAULT CHARSET = utf8mb4 COMMENT ='卡格式科目关联关系';
 
--- 数据订正
+-- 卡格式科目关联关系数据订正
 INSERT INTO `eb_answer_card_subject` (
 	`exam_id`,
 	`subject_code`,
@@ -99,6 +99,61 @@ FROM
 WHERE
 	b.subject_code is not  NULL;
 	
+-- 仲裁轨迹
+ALTER TABLE m_arbitrate_history ADD COLUMN	`unanswered_count`  int(11)	 DEFAULT NULL COMMENT '未作答的步骤数量';
+UPDATE m_arbitrate_history set unanswered_count=0;
+
+# Dump of table m_header_tag
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `m_header_tag`;
+
+CREATE TABLE `m_header_tag`
+(
+    `id`           int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `student_id`   int(11)     NOT NULL COMMENT '考生ID',
+	`group_number` int(11)     NOT NULL COMMENT '大题题号',
+	`user_id`      int(11)     NOT NULL COMMENT '用户ID',
+    `tag_name`     varchar(64) NOT NULL COMMENT '标记内容',
+    `position_x`   double      NOT NULL COMMENT 'X轴位置',
+    `position_y`   double      NOT NULL COMMENT 'Y轴位置',
+    `offset_index` int(11)     NOT NULL COMMENT '裁切图序号',
+    `offset_x`     int(11)     NOT NULL COMMENT '裁切图X轴坐标',
+    `offset_y`     int(11)     NOT NULL COMMENT '裁切图Y轴坐标',
+    PRIMARY KEY (`id`),
+    KEY `index1` (`student_id`,`group_number`),
+	KEY `index2` (`user_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='组长特殊标记表';
+
+
+# Dump of table m_header_track
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `m_header_track`;
+
+CREATE TABLE `m_header_track`
+(
+	`student_id`      int(11)      NOT NULL COMMENT '考生ID',
+    `question_number` varchar(128) NOT NULL COMMENT '完整题号',
+    `number`          int(11)      NOT NULL COMMENT '序号',
+    `exam_id`         int(11)      NOT NULL COMMENT '考试ID',
+    `subject_code`    varchar(32)  NOT NULL COMMENT '科目代码',
+    `group_number`    int(11)      NOT NULL COMMENT '大题题号',
+    `user_id`         int(11)      NOT NULL COMMENT '用户ID',
+    `score`           double       NOT NULL COMMENT '给分',
+    `position_x`      double       NOT NULL COMMENT 'X轴位置',
+    `position_y`      double       NOT NULL COMMENT 'Y轴位置',
+    `offset_index`    int(11)      NOT NULL COMMENT '裁切图序号',
+    `offset_x`        int(11)      NOT NULL COMMENT '裁切图X轴坐标',
+    `offset_y`        int(11)      NOT NULL COMMENT '裁切图Y轴坐标',
+    `unanswered`      tinyint(1)   NOT NULL COMMENT '未作答',
+    PRIMARY KEY (`student_id`, `question_number`, `number`),
+    KEY `index1` (`student_id`, `group_number`),
+    KEY `index2` (`user_id`),
+    KEY `index3` (`exam_id`, `subject_code`, `group_number`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='组长轨迹给分表';
 	
 DROP TABLE IF EXISTS `eb_user_student`;
 CREATE TABLE `eb_user_student`
@@ -110,40 +165,39 @@ CREATE TABLE `eb_user_student`
     UNIQUE KEY `index1` (`user_id`, `exam_number`)
 ) ENGINE = InnoDB
   DEFAULT CHARSET = utf8mb4 COMMENT ='用户考生关联表';
-
+  
 DROP TABLE IF EXISTS `b_privilege`;
 CREATE TABLE `b_privilege`
 (
-    `id`             int(11)      NOT NULL AUTO_INCREMENT,
-    `code`           varchar(50) NOT NULL,
-    `name`           varchar(50) NOT NULL,
-    `parent_code`    varchar(50)      NOT NULL,
-    `privilege_type` varchar(50) NOT NULL,
-    `privilege_uri`  varchar(50)  DEFAULT NULL,
-    `seq`            int(11)         NOT NULL,
-    `level`          int(11)         NOT NULL,
-    `icon` varchar(50)      DEFAULT NULL,
-    `i18n` varchar(50)      DEFAULT NULL,
+    `id`             int(11)		NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `code`           varchar(64)	NOT NULL COMMENT '权限CODE',
+    `name`           varchar(64)	NOT NULL COMMENT '名称',
+    `parent_code`    varchar(64)	NOT NULL COMMENT '父权限CODE',
+    `privilege_type` varchar(64)	NOT NULL COMMENT '类型',
+    `privilege_uri`  varchar(64)	DEFAULT NULL COMMENT 'URI',
+    `seq`            int(11)		NOT NULL COMMENT '排序',
+    `level`          int(11)		NOT NULL COMMENT '树结构层级',
+    `icon` 			 varchar(64)	DEFAULT NULL COMMENT '图表',
+    `i18n` 			 varchar(64)	DEFAULT NULL COMMENT '国际化',
     PRIMARY KEY (`id`),
     UNIQUE KEY `IDX_PRIVILEGE_01` (`code`),
     KEY `IDX_PRIVILEGE_02` (`parent_code`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4
-  COLLATE = utf8mb4_bin;
+  DEFAULT CHARSET = utf8mb4 COMMENT ='权限表';
+
 
 DROP TABLE IF EXISTS `b_role_privilege`;
 CREATE TABLE `b_role_privilege`
 (
-	`id`             int(11)      NOT NULL AUTO_INCREMENT,
-	`school_id` int(11) NOT NULL,
-    `role_code`    varchar(50) NOT NULL,
-    `privilege_code` varchar(50)      NOT NULL,
-    `enable`       tinyint(1)      NOT NULL,
+	`id`				int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
+	`school_id` 		int(11) 	NOT NULL COMMENT '学校ID',
+    `role_code`			varchar(64) NOT NULL COMMENT '角色CODE',
+    `privilege_code`	varchar(64)	NOT NULL COMMENT '权限CODE',
+    `enable`       		tinyint(1)	NOT NULL COMMENT '启用禁用',
     PRIMARY KEY (`id`),
     UNIQUE KEY `IDX_ROLE_PRIVILEGE_01`(`school_id`,`role_code`, `privilege_code`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4
-  COLLATE = utf8mb4_bin;
+  DEFAULT CHARSET = utf8mb4 COMMENT ='角色权限关联表';
   
 INSERT INTO `b_privilege` ( `code`, `name`, `parent_code`, `privilege_type`, `privilege_uri`, `seq`,`level`,`icon`,`i18n`)
 VALUES ('user_list', '用户管理', 'root_code', 'MENU', '/admin/user/list', 10,1,'icon-user','index.user');
@@ -252,18 +306,17 @@ where p.`code` in('exam_score','exam_report_subject','operation_log');
 DROP TABLE IF EXISTS `b_role_info`;
 CREATE TABLE `b_role_info`
 (
-    `id`             int(11)      NOT NULL AUTO_INCREMENT,
-    `school_id` int(11) NOT NULL,
-    `code`           varchar(50) NOT NULL,
-    `name`           varchar(50) NOT NULL,
-    `seq`            int(11)         NOT NULL,
-    `updater_id` int(11)      DEFAULT NULL,
-    `update_time`  		datetime     DEFAULT NULL, 
+    `id`             int(11)     NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `school_id` 	 int(11)	 NOT NULL COMMENT '学校ID',
+    `code`           varchar(64) NOT NULL COMMENT '角色CODE',
+    `name`           varchar(64) NOT NULL COMMENT '名称',
+    `seq`            int(11)     NOT NULL COMMENT '排序',
+    `updater_id` 	 int(11)	 DEFAULT NULL COMMENT '更新人ID',
+    `update_time`	 datetime    DEFAULT NULL COMMENT '更新时间', 
     PRIMARY KEY (`id`),
     UNIQUE KEY `IDX_ROLE_INFO_01` (`school_id`,`code`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4
-  COLLATE = utf8mb4_bin;
+  DEFAULT CHARSET = utf8mb4 COMMENT ='角色表';
 
 DROP TABLE IF EXISTS `b_role_temp`;
 CREATE TABLE `b_role_temp`