1
0
Эх сурвалжийг харах

修复统分进度;增加导入缺考、违纪名单;增加考生审核状态;增加审核考生;增加科目裁切图配置;

ting.yin 5 жил өмнө
parent
commit
6d35e054b9
32 өөрчлөгдсөн 1166 нэмэгдсэн , 37 устгасан
  1. 26 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/CheckStudentDao.java
  2. 4 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamDao.java
  3. 7 3
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamSubjectDao.java
  4. 133 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/CheckStudent.java
  5. 14 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Exam.java
  6. 15 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamStudent.java
  7. 30 11
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamSubject.java
  8. 76 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/CheckStudentSearchQuery.java
  9. 25 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/CheckStudentService.java
  10. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamService.java
  11. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamSubjectService.java
  12. 97 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/CheckStudentServiceImpl.java
  13. 5 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamServiceImpl.java
  14. 4 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamStudentServiceImpl.java
  15. 7 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamSubjectServiceImpl.java
  16. 34 0
      stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/CheckType.java
  17. 34 0
      stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/ScanCheck.java
  18. 99 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/CheckStudentController.java
  19. 32 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ScoreController.java
  20. 6 1
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/parameter/ExamPaperController.java
  21. 55 1
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/parameter/ExamStudentController.java
  22. 4 2
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/ScoreCalculateThread.java
  23. 22 0
      stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/ExamInfoController.java
  24. 15 2
      stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/ScanController.java
  25. 11 0
      stmms-web/src/main/java/cn/com/qmth/stmms/api/utils/ScanStudentParameter.java
  26. 1 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkAnswer.jsp
  27. 1 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkImage.jsp
  28. 1 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkScore.jsp
  29. 90 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkStudent.jsp
  30. 269 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkStudentEdit.jsp
  31. 42 14
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/param/studentList.jsp
  32. 2 1
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/scoreList.jsp

+ 26 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/CheckStudentDao.java

@@ -0,0 +1,26 @@
+package cn.com.qmth.stmms.biz.exam.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.exam.model.CheckStudent;
+import cn.com.qmth.stmms.common.enums.CheckType;
+
+public interface CheckStudentDao extends PagingAndSortingRepository<CheckStudent, Integer>,
+        JpaSpecificationExecutor<CheckStudent> {
+
+    List<CheckStudent> findByExamIdAndCheckedAndType(int examId, boolean checked, CheckType type);
+
+    @Modifying
+    @Query("delete CheckStudent c where c.examId=?1 ")
+    void deleteByExamId(int examId);
+
+    long countByExamIdAndChecked(int examId, boolean checked);
+
+    long countByExamIdAndSubjectCodeAndChecked(int examId, String subjectCode, boolean checked);
+
+}

+ 4 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamDao.java

@@ -35,4 +35,8 @@ public interface ExamDao extends PagingAndSortingRepository<Exam, Integer>, JpaS
     @Query("update Exam e set e.process=?2 where e.id=?1")
     public void updateProcess(Integer id, Double process);
 
+    @Modifying
+    @Query("update Exam e set e.needCalculate=?2 where e.id=?1")
+    public void updateNeedCalculate(Integer examId, boolean needCalculate);
+
 }

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

@@ -88,7 +88,11 @@ public interface ExamSubjectDao extends PagingAndSortingRepository<ExamSubject,
     @Query("delete ExamSubject s where s.pk.examId=?1")
     void deleteByExamId(int examId);
 
-    @Query(value = "select s.* from eb_exam_subject s where 1=1 and s.exam_id = ?1 and s.`code` in ( " +
-            "select f.subject_code  from m_library f where 1=1 and f.marker_id = ?2 and f.`status`=?3 GROUP BY f.subject_code)",nativeQuery = true)
-    List<ExamSubject> findExamSubjectByMarkerId(int examId,int markerId,int status);
+    @Query(value = "select s.* from eb_exam_subject s where 1=1 and s.exam_id = ?1 and s.`code` in ( "
+            + "select f.subject_code  from m_library f where 1=1 and f.marker_id = ?2 and f.`status`=?3 GROUP BY f.subject_code)", nativeQuery = true)
+    List<ExamSubject> findExamSubjectByMarkerId(int examId, int markerId, int status);
+
+    @Modifying
+    @Query("update ExamSubject s set s.sliceConfig=?3 where s.pk.examId=?1 and s.pk.code=?2")
+    public void updateSliceConfig(Integer examId, String subjectCode, String configString);
 }

+ 133 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/CheckStudent.java

@@ -0,0 +1,133 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import cn.com.qmth.stmms.common.enums.CheckType;
+
+@Entity
+@Table(name = "eb_check_student")
+public class CheckStudent implements Serializable {
+
+    private static final long serialVersionUID = -4313571132768546289L;
+
+    @Id
+    @Column(name = "student_id")
+    private Integer studentId;
+
+    /**
+     * 考试ID
+     */
+    @Column(name = "exam_id", nullable = false)
+    private Integer examId;
+
+    /**
+     * 科目代码
+     */
+    @Column(name = "subject_code", nullable = false)
+    private String subjectCode;
+
+    /**
+     * 是否被处理
+     */
+    @Column(name = "is_checked")
+    private boolean checked;
+
+    /**
+     * 处理时间
+     */
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name = "update_time")
+    private Date updateTime;
+
+    /**
+     * 处理类型
+     */
+    @Enumerated(EnumType.STRING)
+    @Column(name = "type", length = 16, nullable = false)
+    private CheckType type;
+
+    /**
+     * 学习中心ID
+     */
+    @Column(name = "campus_name", nullable = false)
+    private String campusName;
+
+    public CheckStudent() {
+    }
+
+    public CheckStudent(Integer studentId, Integer examId, String subjectCode, String campusName, CheckType type) {
+        this.studentId = studentId;
+        this.examId = examId;
+        this.subjectCode = subjectCode;
+        this.campusName = campusName;
+        this.type = type;
+        this.checked = false;
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public boolean isChecked() {
+        return checked;
+    }
+
+    public void setChecked(boolean checked) {
+        this.checked = checked;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public CheckType getType() {
+        return type;
+    }
+
+    public void setType(CheckType type) {
+        this.type = type;
+    }
+
+    public String getCampusName() {
+        return campusName;
+    }
+
+    public void setCampusName(String campusName) {
+        this.campusName = campusName;
+    }
+
+}

+ 14 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Exam.java

@@ -101,6 +101,12 @@ public class Exam implements Serializable {
     @Column(name = "process")
     private Double process;
 
+    /**
+     * 是否需要统分
+     */
+    @Column(name = "need_calculate", nullable = false)
+    private boolean needCalculate;
+
     public Integer getId() {
         return id;
     }
@@ -233,4 +239,12 @@ public class Exam implements Serializable {
         this.process = process;
     }
 
+    public boolean isNeedCalculate() {
+        return needCalculate;
+    }
+
+    public void setNeedCalculate(boolean needCalculate) {
+        this.needCalculate = needCalculate;
+    }
+
 }

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

@@ -20,6 +20,7 @@ import org.apache.commons.lang.StringUtils;
 import cn.com.qmth.stmms.biz.mark.model.TagInfo;
 import cn.com.qmth.stmms.biz.utils.ScoreItem;
 import cn.com.qmth.stmms.common.annotation.ExcelField;
+import cn.com.qmth.stmms.common.enums.ScanCheck;
 
 /**
  * 针对某次考试的考生信息
@@ -222,6 +223,12 @@ public class ExamStudent implements Serializable {
     @Column(name = "subject_category")
     private String subjectCategory;
 
+    /**
+     * 审核状态
+     */
+    @Column(name = "scan_check")
+    private ScanCheck scanCheck;
+
     /**
      * 科目备注信息
      */
@@ -706,4 +713,12 @@ public class ExamStudent implements Serializable {
         this.tagInfo = tagInfo;
     }
 
+    public ScanCheck getScanCheck() {
+        return scanCheck;
+    }
+
+    public void setScanCheck(ScanCheck scanCheck) {
+        this.scanCheck = scanCheck;
+    }
+
 }

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

@@ -2,6 +2,7 @@ package cn.com.qmth.stmms.biz.exam.model;
 
 import java.io.Serializable;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import javax.persistence.CascadeType;
@@ -19,6 +20,7 @@ import javax.persistence.Transient;
 
 import org.apache.commons.lang.StringUtils;
 
+import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
 import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
 import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
 
@@ -71,12 +73,18 @@ public class ExamSubject implements Serializable {
     @Column(name = "remark")
     private String remark;
 
-    @ManyToMany(cascade = CascadeType.PERSIST, fetch=FetchType.LAZY)
-    @JoinTable(name="eb_exam_subject_marker",
-    		joinColumns={@JoinColumn(name="subject_code",referencedColumnName = "code"),@JoinColumn(name="exam_id",referencedColumnName = "exam_id")},
-    		inverseJoinColumns={@JoinColumn(name="marker_id")})
+    @ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
+    @JoinTable(name = "eb_exam_subject_marker", joinColumns = {
+            @JoinColumn(name = "subject_code", referencedColumnName = "code"),
+            @JoinColumn(name = "exam_id", referencedColumnName = "exam_id") }, inverseJoinColumns = { @JoinColumn(name = "marker_id") })
     private Set<Marker> markers = new HashSet<>();
-    
+
+    /**
+     * 裁切图配置
+     */
+    @Column(name = "slice_config", nullable = true)
+    private String sliceConfig;
+
     @Transient
     private long studentCount;
 
@@ -259,12 +267,23 @@ public class ExamSubject implements Serializable {
         this.category = category;
     }
 
-	public Set<Marker> getMarkers() {
-		return markers;
-	}
+    public Set<Marker> getMarkers() {
+        return markers;
+    }
+
+    public void setMarkers(Set<Marker> markers) {
+        this.markers = markers;
+    }
 
-	public void setMarkers(Set<Marker> markers) {
-		this.markers = markers;
-	}
+    public String getSliceConfig() {
+        return sliceConfig;
+    }
 
+    public void setSliceConfig(String sliceConfig) {
+        this.sliceConfig = sliceConfig;
+    }
+    
+    public List<PictureConfigItem> getSliceConfigList() {
+        return PictureConfigItem.parse(sliceConfig);
+    }
 }

+ 76 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/CheckStudentSearchQuery.java

@@ -0,0 +1,76 @@
+package cn.com.qmth.stmms.biz.exam.query;
+
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.exam.model.CheckStudent;
+import cn.com.qmth.stmms.common.enums.CheckType;
+
+public class CheckStudentSearchQuery extends BaseQuery<CheckStudent> {
+
+    private Integer examId;
+
+    private String studentId;
+
+    private String subjectCode;
+
+    private String campusName;
+
+    private Boolean checked;
+
+    private CheckType type;
+
+    public void orderByStudentId() {
+        setSort(new Sort(Direction.ASC, "studentId"));
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(String studentId) {
+        this.studentId = studentId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Boolean getChecked() {
+        return checked;
+    }
+
+    public void setChecked(Boolean checked) {
+        this.checked = checked;
+    }
+
+    public CheckType getType() {
+        return type;
+    }
+
+    public void setType(CheckType type) {
+        this.type = type;
+    }
+
+    public String getCampusName() {
+        return campusName;
+    }
+
+    public void setCampusName(String campusName) {
+        this.campusName = campusName;
+    }
+
+}

+ 25 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/CheckStudentService.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.CheckStudent;
+import cn.com.qmth.stmms.biz.exam.query.CheckStudentSearchQuery;
+import cn.com.qmth.stmms.common.enums.CheckType;
+
+public interface CheckStudentService {
+
+    CheckStudent save(CheckStudent student);
+
+    List<CheckStudent> findByExamIdAndIsCheckedAndType(int examId, boolean checked, CheckType type);
+
+    void deleteByExamId(int examId);
+
+    CheckStudent findByStudentId(Integer studentId);
+
+    long countByExamIdAndChecked(int examId, boolean checked);
+
+    public CheckStudentSearchQuery findByQuery(CheckStudentSearchQuery query);
+
+    long countByExamIdAndSubjectCodeAndChecked(int examId, String subjectCode, boolean checked);
+
+}

+ 2 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamService.java

@@ -31,4 +31,6 @@ public interface ExamService {
 
     void updateProcess(Integer examId, Double process);
 
+    void updateNeedCalculate(Integer id, boolean needCalculate);
+
 }

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

@@ -5,6 +5,7 @@ import java.util.Set;
 
 import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
 import cn.com.qmth.stmms.biz.exam.service.query.ExamSubjectSearchQuery;
+import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
 import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
 import cn.com.qmth.stmms.common.enums.LibraryStatus;
 
@@ -65,4 +66,6 @@ public interface ExamSubjectService {
 
     List<ExamSubject> findExamSubjectByMarkerId(int examId,int markerId ,LibraryStatus status);
 
+    void updateSliceConfig(Integer examId, String subjectCode, List<PictureConfigItem> configList);
+
 }

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

@@ -0,0 +1,97 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+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.exam.dao.CheckStudentDao;
+import cn.com.qmth.stmms.biz.exam.model.CheckStudent;
+import cn.com.qmth.stmms.biz.exam.query.CheckStudentSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.CheckStudentService;
+import cn.com.qmth.stmms.common.enums.CheckType;
+
+@Service("checkStudentService")
+public class CheckStudentServiceImpl extends BaseQueryService<CheckStudent> implements CheckStudentService {
+
+    @Autowired
+    private CheckStudentDao checkStudentDao;
+
+    @Override
+    public CheckStudent save(CheckStudent student) {
+        return checkStudentDao.save(student);
+    }
+
+    @Override
+    public List<CheckStudent> findByExamIdAndIsCheckedAndType(int examId, boolean checked, CheckType type) {
+        return checkStudentDao.findByExamIdAndCheckedAndType(examId, checked, type);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamId(int examId) {
+        checkStudentDao.deleteByExamId(examId);
+    }
+
+    @Override
+    public CheckStudent findByStudentId(Integer studentId) {
+        return checkStudentDao.findOne(studentId);
+    }
+
+    @Override
+    public long countByExamIdAndChecked(int examId, boolean checked) {
+        return checkStudentDao.countByExamIdAndChecked(examId, checked);
+    }
+
+    @Override
+    public CheckStudentSearchQuery findByQuery(final CheckStudentSearchQuery query) {
+        checkQuery(query);
+        Page<CheckStudent> result = checkStudentDao.findAll(new Specification<CheckStudent>() {
+
+            @Override
+            public Predicate toPredicate(Root<CheckStudent> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+
+                if (query.getExamId() != null) {
+                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
+                }
+                if (query.getStudentId() != null) {
+                    predicates.add(cb.equal(root.get("studentId"), query.getStudentId()));
+                }
+                if (StringUtils.isNotBlank(query.getSubjectCode())) {
+                    predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
+                }
+                if (query.getChecked() != null) {
+                    predicates.add(cb.equal(root.get("checked"), query.getChecked()));
+                }
+                if (query.getType() != null) {
+                    predicates.add(cb.equal(root.get("type"), query.getType()));
+                }
+                if (StringUtils.isNotBlank(query.getCampusName())) {
+                    predicates.add(cb.equal(root.get("campusName"), query.getCampusName()));
+                }
+                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
+                        .size()]));
+            }
+        }, query);
+        fillResult(result, query);
+        return query;
+    }
+
+    @Override
+    public long countByExamIdAndSubjectCodeAndChecked(int examId, String subjectCode, boolean checked) {
+        return checkStudentDao.countByExamIdAndSubjectCodeAndChecked(examId, subjectCode, checked);
+    }
+
+}

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

@@ -152,4 +152,9 @@ public class ExamServiceImpl extends BaseQueryService<Exam> implements ExamServi
         examDao.updateProcess(id, process);
     }
 
+    @Override
+    @Transactional
+    public void updateNeedCalculate(Integer id, boolean needCalculate) {
+        examDao.updateNeedCalculate(id, needCalculate);
+    }
 }

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

@@ -717,7 +717,8 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
         // }
         // 构造评卷标记信息
         Exam exam = examService.findById(student.getExamId());
-        List<PictureConfigItem> sliceConfig = exam.getSliceConfigList();
+        ExamSubject subject = subjectService.find(student.getExamId(), student.getSubjectCode());
+        List<PictureConfigItem> sliceConfig = subject.getSliceConfigList().isEmpty()?subject.getSliceConfigList():exam.getSliceConfigList();
         if (!sliceConfig.isEmpty()) {
             List<PictureTag> tags = PictureConfigTransform
                     .process(sliceConfig, getSliceSet(student), getSliceTags(student)).get(index);
@@ -735,7 +736,8 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
     public Map<Integer, List<PictureTag>> buildSheetTags(ExamStudent student) {
         List<OriginTag> tags = new ArrayList<OriginTag>();
         Exam exam = examService.findById(student.getExamId());
-        List<PictureConfigItem> sliceConfig = exam.getSliceConfigList();
+        ExamSubject subject = subjectService.find(student.getExamId(), student.getSubjectCode());
+        List<PictureConfigItem> sliceConfig = subject.getSliceConfigList().isEmpty()?subject.getSliceConfigList():exam.getSliceConfigList();
         if (!sliceConfig.isEmpty()) {
             // 有裁切图配置时才需要获取原始评卷标记信息
             tags = getSliceTags(student);

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

@@ -23,6 +23,7 @@ import cn.com.qmth.stmms.biz.exam.dao.ExamSubjectDao;
 import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
 import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
 import cn.com.qmth.stmms.biz.exam.service.query.ExamSubjectSearchQuery;
+import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
 import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
 import cn.com.qmth.stmms.common.enums.LibraryStatus;
 
@@ -273,4 +274,10 @@ public class ExamSubjectServiceImpl extends BaseQueryService<ExamSubject> implem
     public List<ExamSubject> findExamSubjectByMarkerId(int examId,int markerId ,LibraryStatus status){
         return subjectDao.findExamSubjectByMarkerId(examId,markerId,status.getValue());
     }
+
+    @Override
+    public void updateSliceConfig(Integer examId, String subjectCode, List<PictureConfigItem> configList) {
+        subjectDao.updateSliceConfig(examId, subjectCode,
+                configList != null ? StringUtils.join(configList, PictureConfigItem.DB_ITEM_JOINER) : "");
+    }
 }

+ 34 - 0
stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/CheckType.java

@@ -0,0 +1,34 @@
+package cn.com.qmth.stmms.common.enums;
+
+public enum CheckType {
+
+    MANUAL("手动更新", 1);
+
+    private String name;
+
+    private int value;
+
+    private CheckType(String name, int value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public static CheckType findByValue(int value) {
+        CheckType type = null;
+        for (CheckType s : CheckType.values()) {
+            if (s.getValue() == value) {
+                type = s;
+                break;
+            }
+        }
+        return type;
+    }
+}

+ 34 - 0
stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/ScanCheck.java

@@ -0,0 +1,34 @@
+package cn.com.qmth.stmms.common.enums;
+
+public enum ScanCheck {
+
+    TODO("未审核", 1), PENDING("待定", 2), CHECKED("已审核", 3);
+
+    private String name;
+
+    private int value;
+
+    private ScanCheck(String name, int value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public static ScanCheck findByValue(int value) {
+        ScanCheck type = null;
+        for (ScanCheck s : ScanCheck.values()) {
+            if (s.getValue() == value) {
+                type = s;
+                break;
+            }
+        }
+        return type;
+    }
+}

+ 99 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/CheckStudentController.java

@@ -0,0 +1,99 @@
+package cn.com.qmth.stmms.admin.exam;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
+
+import cn.com.qmth.stmms.admin.exam.parameter.BaseParameterController;
+import cn.com.qmth.stmms.biz.exam.model.CheckStudent;
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.exam.query.CheckStudentSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.CheckStudentService;
+import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
+import cn.com.qmth.stmms.common.enums.CheckType;
+
+@Controller
+@RequestMapping("/admin/exam/check/student")
+public class CheckStudentController extends BaseParameterController {
+
+    @Autowired
+    private ExamStudentService studentService;
+
+    @Autowired
+    private CheckStudentService checkStudentService;
+
+    @Value("${sheet.image.server}")
+    private String sheetServer;
+
+    @RequestMapping
+    public String index(Model model, HttpServletRequest request, CheckStudentSearchQuery query) {
+        int examId = getSessionExamId(request);
+        if (examId > 0) {
+            List<ExamStudent> studentList = new ArrayList<ExamStudent>();
+            query.setExamId(examId);
+            query.setChecked(false);
+            if (query.getType() == null) {
+                query.setType(CheckType.MANUAL);
+            }
+            query = checkStudentService.findByQuery(query);
+            for (CheckStudent c : query.getResult()) {
+                studentList.add(studentService.findById(c.getStudentId()));
+            }
+            model.addAttribute("typeList", CheckType.values());
+            model.addAttribute("studentList", studentList);
+            model.addAttribute("campusList", studentService.findDistinctCampusName(examId));
+            model.addAttribute("query", query);
+            return "modules/exam/checkStudent";
+        } else {
+            return "redirect:/admin/exam/list";
+        }
+    }
+
+    @RequestMapping("/start")
+    @ResponseBody
+    public ModelAndView start(HttpServletRequest request, @RequestParam CheckType type) {
+        int examId = getSessionExamId(request);
+        if (examId > 0) {
+            ModelAndView view = new ModelAndView("modules/exam/checkStudentEdit");
+            List<Integer> ids = new ArrayList<Integer>();
+            List<CheckStudent> list = checkStudentService.findByExamIdAndIsCheckedAndType(examId, false, type);
+            for (CheckStudent student : list) {
+                ids.add(student.getStudentId());
+            }
+            view.addObject("sheetServer", sheetServer);
+            view.addObject("ids", StringUtils.join(ids, ","));
+            return view;
+        } else {
+            return new ModelAndView("redirect:/admin/exam/list");
+        }
+    }
+
+    @RequestMapping("/save")
+    @ResponseBody
+    public Object save(HttpServletRequest request, @RequestParam Integer studentId, @RequestParam String answers) {
+        ExamStudent student = studentService.findById(studentId);
+        CheckStudent cs = checkStudentService.findByStudentId(studentId);
+        if (student != null && cs != null) {
+            student.setAnswers(answers);
+            cs.setChecked(true);
+            cs.setUpdateTime(new Date());
+            checkStudentService.save(cs);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+}

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

@@ -36,6 +36,7 @@ import cn.com.qmth.stmms.biz.exam.model.ExamStudentPaper;
 import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
 import cn.com.qmth.stmms.biz.exam.model.Marker;
 import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.CheckStudentService;
 import cn.com.qmth.stmms.biz.exam.service.ExamPackageService;
 import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
 import cn.com.qmth.stmms.biz.exam.service.ExamService;
@@ -92,6 +93,9 @@ public class ScoreController extends BaseParameterController {
     @Autowired
     private TagInfoService tagInfoService;
 
+    @Autowired
+    private CheckStudentService checkStudentService;
+
     @Value("${sheet.image.server}")
     private String imageServer;
 
@@ -153,6 +157,13 @@ public class ScoreController extends BaseParameterController {
                 TagInfo tagInfo = tagInfoService.findByStudentIdAndType(student.getId(), TagType.BREACH);
                 student.setTagInfo(tagInfo);
             }
+            String exportMessage = enableExport(examId);
+            if (exportMessage != null) {
+                view.addObject("exportMessage", exportMessage);
+                view.addObject("enableExport", false);
+            } else {
+                view.addObject("enableExport", true);
+            }
             view.addObject("query", query);
             view.addObject("filter", filter);
             view.addObject("subjectList", getExamSubject(examId));
@@ -250,6 +261,11 @@ public class ScoreController extends BaseParameterController {
             RedirectAttributes redirectAttributes) {
         int examId = getSessionExamId(request);
         String subjectCode = RequestUtils.getSession(request).getParameter("subjectCode");
+        String exportMessage = enableExport(examId);
+        if (exportMessage != null) {
+            addMessage(redirectAttributes, "评卷未结束不能导出成绩 " + exportMessage);
+            return "redirect:/admin/exam/score";
+        }
         if (examId > 0) {
             query.setExamId(examId);
             // query.setUpload(true);
@@ -472,4 +488,20 @@ public class ScoreController extends BaseParameterController {
         }
         return ids;
     }
+
+    private String enableExport(int examId) {
+        Exam exam = examService.findById(examId);
+        if (exam.isNeedCalculate()) {
+            String message = "该考试需要统分";
+            return message;
+        }
+
+        if (checkStudentService.countByExamIdAndChecked(examId, false) != 0) {
+            String message = "人工确认未完成";
+            return message;
+        }
+
+        return null;
+    }
+
 }

+ 6 - 1
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/parameter/ExamPaperController.java

@@ -28,6 +28,7 @@ import cn.com.qmth.stmms.admin.dto.SubjectiveQuestionDTO;
 import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
 import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
 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.ExamSubjectPaperService;
 import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
 import cn.com.qmth.stmms.biz.exam.service.query.ExamQuestionSearchQuery;
@@ -47,6 +48,9 @@ public class ExamPaperController extends BaseParameterController {
 
     @Autowired
     private ExamSubjectPaperService examSubjectPaperService;
+    
+    @Autowired
+    private ExamService examService;
 
     @Value("${card.server}")
     private String cardServer;
@@ -184,7 +188,8 @@ public class ExamPaperController extends BaseParameterController {
         if (examId == 0) {
             return "redirect:/admin/exam/list";
         }
-
+        // 每次导入都需要重新统分
+        examService.updateNeedCalculate(examId, true);
         List<String> error = new LinkedList<String>();
         Map<String, SubjectQuestionDTO> map = parseQuestion(file, examId, objective, error);
         if (error.isEmpty()) {

+ 55 - 1
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/parameter/ExamStudentController.java

@@ -42,6 +42,7 @@ import cn.com.qmth.stmms.biz.exam.service.MarkerService;
 import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
 import cn.com.qmth.stmms.biz.user.model.User;
 import cn.com.qmth.stmms.biz.user.service.UserService;
+import cn.com.qmth.stmms.common.enums.ScanCheck;
 import cn.com.qmth.stmms.common.utils.DateUtils;
 import cn.com.qmth.stmms.common.utils.ExportExcel;
 import cn.com.qmth.stmms.common.utils.ImportExcel;
@@ -217,6 +218,7 @@ public class ExamStudentController extends BaseParameterController {
                 student.setSheetCount(0);
                 student.setObjectiveScore(0d);
                 student.setSubjectiveScore(0d);
+                student.setScanCheck(ScanCheck.TODO);
                 if (checkExamNumber(student, null, null)) {
                     studentService.save(student);
                     addMessage(redirectAttributes, "考生" + student.getName() + "保存成功");
@@ -291,7 +293,8 @@ public class ExamStudentController extends BaseParameterController {
                 student.setObjectiveScore(0d);
                 student.setSubjectiveScore(0d);
                 student.setBreach(false);
-
+                student.setScanCheck(ScanCheck.TODO);
+                
                 if (checkExamNumber(student, current, saveMap)) {
                     saveList.add(student);
                     saveMap.put(student.getExamNumber(), student);
@@ -415,6 +418,57 @@ public class ExamStudentController extends BaseParameterController {
         return "redirect:/admin/exam-param/student";
     }
 
+    @RequestMapping(value = "/absentTemplate")
+    public String absentTemplate(HttpServletResponse response, RedirectAttributes redirectAttributes) {
+        try {
+            String fileName = "缺考考生导入模板.xlsx";
+            List<ExamStudentVO> list = Lists.newArrayList();
+            list.add(new ExamStudentVO());
+            new ExportExcel("缺考考生", ExamStudentVO.class, 2).setDataList(list).write(response, fileName).dispose();
+            return null;
+        } catch (Exception e) {
+            addMessage(redirectAttributes, "导入模板下载失败!失败信息:" + e.getMessage());
+        }
+        return "redirect:" + "/admin/exam-param/student";
+    }
+
+    @RequestMapping(value = "/absentImport", method = RequestMethod.POST)
+    public String absentImportFile(HttpServletRequest request, MultipartFile file,
+            RedirectAttributes redirectAttributes) {
+        int examId = getSessionExamId(request);
+        try {
+            int successNum = 0;
+            int failureNum = 0;
+            StringBuilder failureMsg = new StringBuilder();
+            ImportExcel ei = new ImportExcel(file, 1, 0);
+            List<ExamStudentVO> list = ei.getDataList(ExamStudentVO.class);
+            studentService.clearManualAbsent(examId);
+            for (ExamStudentVO studentVO : list) {
+                if (StringUtils.isBlank(studentVO.getExamNumber())) {
+                    continue;
+                }
+                ExamStudent student = studentService.findByExamIdAndExamNumber(examId, studentVO.getExamNumber());
+                if (student != null) {
+                    student.setManualAbsent(true);
+                    student.setScanCheck(ScanCheck.TODO);
+                    successNum++;
+                } else {
+                    failureMsg.append("<br/>准考证号 " + studentVO.getExamNumber() + " 不存在; ");
+                    failureNum++;
+                }
+
+            }
+            if (failureNum > 0) {
+                failureMsg.insert(0, ",失败 " + failureNum + " 条用户");
+            }
+            addMessage(redirectAttributes, "已成功导入 " + successNum + " 条用户" + failureMsg);
+        } catch (Exception e) {
+            log.error("Batch import absentStudent error!", e);
+            addMessage(redirectAttributes, "导入缺考考生失败!失败信息:" + e.getMessage());
+        }
+        return "redirect:" + "/admin/exam-param/student";
+    }
+    
     private boolean checkExamNumber(ExamStudent student, Map<String, ExamStudent> current,
             Map<String, ExamStudent> saveMap) {
         ExamStudent previous = null;

+ 4 - 2
stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/ScoreCalculateThread.java

@@ -89,7 +89,7 @@ public class ScoreCalculateThread implements Runnable {
                 for (ExamStudent student : list) {
                     calculate(student);
                 }
-                double process = pageSize * pageNumber * 1.0 / totalCount;
+                double process = pageSize * pageNumber * 100.0 / totalCount;
                 if (process >= 100) {
                     process = 99;
                 }
@@ -104,7 +104,9 @@ public class ScoreCalculateThread implements Runnable {
             if (finish >= total) {
                 statistics();
             }
-
+            // 统分结束修改标记
+            examService.updateNeedCalculate(exam.getId(), false);
+            examService.updateProcess(exam.getId(), null);
         } catch (Exception e) {
             log.error("calculate exception for examId=" + exam.getId(), e);
         } finally {

+ 22 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/ExamInfoController.java

@@ -163,4 +163,26 @@ public class ExamInfoController extends BaseApiController {
         }
         return success;
     }
+    
+    @AuthValidate("adminUser")
+    @RequestMapping(value = "/sliceConfig/{examId}/{subjectCode}", method = RequestMethod.POST)
+    @ResponseBody
+    public boolean updateSliceConfig(HttpServletRequest request, @PathVariable Integer examId,
+            @PathVariable String subjectCode, @RequestBody PictureConfigItem[] configs) {
+        User user = RequestUtils.getApiUser(request);
+        Exam exam = examService.findById(examId);
+        boolean success = false;
+        if (exam != null && exam.getSchoolId().equals(user.getSchoolId())) {
+            ExamSubject es = subjectService.find(examId, subjectCode);
+            if (configs != null && configs.length > 0 && es != null) {
+                subjectService.updateSliceConfig(examId, subjectCode, Arrays.asList(configs));
+                success = true;
+            } else {
+                success = false;
+            }
+        } else {
+            throw ApiException.EXAM_NOT_ACCESSIBLED;
+        }
+        return success;
+    }
 }

+ 15 - 2
stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/ScanController.java

@@ -6,6 +6,9 @@ import java.util.Date;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -21,15 +24,17 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import cn.com.qmth.stmms.api.utils.ScanStudentParameter;
 import cn.com.qmth.stmms.biz.api.auth.annotation.AuthValidate;
 import cn.com.qmth.stmms.biz.api.auth.exception.ApiException;
+import cn.com.qmth.stmms.biz.exam.model.CheckStudent;
 import cn.com.qmth.stmms.biz.exam.model.Exam;
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.exam.service.CheckStudentService;
 import cn.com.qmth.stmms.biz.exam.service.ExamService;
 import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
 import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.common.enums.CheckType;
+import cn.com.qmth.stmms.common.enums.ScanCheck;
 import cn.com.qmth.stmms.common.utils.DateUtils;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
-import net.sf.json.JSONArray;
-import net.sf.json.JSONObject;
 
 @Controller
 @RequestMapping("/api/scan")
@@ -42,6 +47,9 @@ public class ScanController extends BaseApiController {
 
     @Autowired
     private ExamService examService;
+    
+    @Autowired
+    private CheckStudentService checkStudentService;
 
     /**
      * 上传考生识别结果
@@ -80,6 +88,7 @@ public class ScanController extends BaseApiController {
                     student.setBatchCode(sc.getBatchCode());
                     student.setSliceCount(sc.getSliceCount());
                     student.setSheetCount(sc.getSheetCount());
+                    student.setScanCheck(ScanCheck.CHECKED);
                     // 同步更新评卷任务及客观题分数
                     saveMarkLibrary(student);
 
@@ -88,6 +97,10 @@ public class ScanController extends BaseApiController {
                         obj.accumulate("examNumber", student.getExamNumber());
                         obj.accumulate("uploadTime", DateUtils.formatDateTime(student.getUploadTime()));
                         array.add(obj);
+                        // 增加人工审核数据
+                        if (sc.isManual()) {
+                            checkStudentService.save(new CheckStudent(student.getId(), examId, student.getSubjectCode(),student.getCampusName(), CheckType.MANUAL));
+                        }
                     }
                 }
             }

+ 11 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/api/utils/ScanStudentParameter.java

@@ -14,6 +14,8 @@ public class ScanStudentParameter {
 
     private String batchCode;
 
+    private boolean manual;
+
     public String getExamNumber() {
         return examNumber;
     }
@@ -61,4 +63,13 @@ public class ScanStudentParameter {
     public void setBatchCode(String batchCode) {
         this.batchCode = batchCode;
     }
+
+    public boolean isManual() {
+        return manual;
+    }
+
+    public void setManual(boolean manual) {
+        this.manual = manual;
+    }
+
 }

+ 1 - 0
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkAnswer.jsp

@@ -12,6 +12,7 @@
 	    <li class="active"><a href="${ctx}/admin/exam/check/answer">识别结果检查</a></li>
 		<li><a href="${ctx}/admin/exam/check/image">图片检查</a></li>
 		<li><a href="${ctx}/admin/exam/check/score">分数检查</a></li>
+		<li><a href="${ctx}/admin/exam/check/student">人工确认</a></li>
 	</ul>
 	<form id="searchForm" action="${ctx}/admin/exam/check/answer/start" method="post" class="form-horizontal" target="_blank">
 	    <input type="hidden" class="hiddenField" id="examNumberIn" name="examNumberIn"/>

+ 1 - 0
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkImage.jsp

@@ -12,6 +12,7 @@
 	    <li><a href="${ctx}/admin/exam/check/answer">识别结果检查</a></li>
 		<li class="active"><a href="${ctx}/admin/exam/check/image">图片检查</a></li>
 		<li><a href="${ctx}/admin/exam/check/score">分数检查</a></li>
+		<li><a href="${ctx}/admin/exam/check/student">人工确认</a></li>
 	</ul>
 	<form id="searchForm" action="${ctx}/admin/exam/check/image" method="post" class="breadcrumb form-search">
 		<input type="hidden" id="pageNumber" name="pageNumber" value="${query.pageNumber }"/>

+ 1 - 0
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkScore.jsp

@@ -12,6 +12,7 @@
 	    <li><a href="${ctx}/admin/exam/check/answer">识别结果检查</a></li>
 		<li><a href="${ctx}/admin/exam/check/image">图片检查</a></li>
 		<li class="active"><a href="${ctx}/admin/exam/check/score">分数检查</a></li>
+		<li><a href="${ctx}/admin/exam/check/student">人工确认</a></li>
 	</ul>
 	<form id="searchForm" action="${ctx}/admin/exam/check/score" method="post" class="breadcrumb form-search">
 		<input type="hidden" id="pageNumber" name="pageNumber" value="${query.pageNumber }"/>

+ 90 - 0
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkStudent.jsp

@@ -0,0 +1,90 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
+<html>
+<head>
+	<title>数据检查</title>
+	<meta name="decorator" content="default"/>
+	<%@include file="/WEB-INF/views/include/head.jsp" %>
+	<style type="text/css">.sort{color:#0663A2;cursor:pointer;}</style>
+</head>
+<body>
+	<ul class="nav nav-tabs">
+		<li><a href="${ctx}/admin/exam/check/answer">识别结果检查</a></li>
+		<li><a href="${ctx}/admin/exam/check/image">图片检查</a></li>
+		<li class="active"><a href="${ctx}/admin/exam/check/student">人工确认</a></li>
+	</ul>
+	<form id="searchForm" action="${ctx}/admin/exam/check/student" method="post" class="breadcrumb form-search">
+		<input type="hidden" id="pageNumber" name="pageNumber" value="${query.pageNumber }"/>
+		<input type="hidden" id="pageSize" name="pageSize" value="${query.pageSize }"/>
+		<div>
+			<label>学习中心</label>
+			<select name="campusName">
+				<option value="">请选择</option>
+				<c:forEach items="${campusList}" var="campus">
+				<option value="${campus}" <c:if test="${campus==query.campusName}">selected</c:if>>${campus}</option>
+				</c:forEach>
+			</select>
+			<label>确认类型</label>
+			<select name="type" id="type" >
+				<c:forEach items="${typeList}" var="item">
+				<option value="${item.value}" <c:if test="${item.value==query.type.value}">selected</c:if>>${item.name}</option>
+				</c:forEach>
+			</select>
+			&nbsp;
+			<input id="btnSubmit" class="btn btn-primary" type="button" value="查询" onclick="goSearch()"/>
+			&nbsp;
+			<a href="${ctx}/admin/exam/check/student/start?type=${query.type.value}" target="_blank" class="btn btn-primary" id="start-button">开始处理</a>
+		</div>
+	</form>
+	<tags:message content="${message}"/>
+	<table id="contentTable" class="table table-striped table-bordered table-condensed">
+		<thead>
+			<tr>
+				<th>准考证号</th>
+				<th>姓名</th>
+				<th>学号</th>
+				<th>科目</th>
+				<th>学习中心</th>
+				<th>扫描批次</th>
+				<th>上传时间</th>
+			</tr>
+		</thead>
+		<tbody>
+		<c:forEach items="${studentList}" var="student">
+			<tr>
+				<td>${student.examNumber}</td>
+				<td>${student.name}</td>
+				<td>${student.studentCode}</td>
+				<td>${student.subjectCode}-${student.subjectName}</td>
+				<td>${student.campusName}</td>
+				<td>${student.batchCode}</td>
+				<td><fmt:formatDate value="${student.uploadTime}" pattern="yyyy-MM-dd hh:MM:ss"/></td>
+			</tr>
+		</c:forEach>
+		</tbody>
+	</table>
+	<div class="pagination">${query}</div>
+<script type="text/javascript">
+
+$('#start-button').click(function(){
+	var value = $('#type').val();
+	$('#start-button').attr('href','${ctx}/admin/exam/check/student/start?type='+value);
+});
+
+function page(n,s){
+	$("#pageNumber").val(n);
+	$("#pageSize").val(s);
+	$("#searchForm").attr('action','${ctx}/admin/exam/check/student');
+	$("#searchForm").submit();
+	return false;
+}
+function goSearch(){
+	$("#pageNumber").val(1);
+	$("#pageSize").val('${query.pageSize}');
+	$("#searchForm").attr('action','${ctx}/admin/exam/check/student');
+	$("#searchForm").submit();
+	return false;
+}
+</script>	
+</body>
+</html>

+ 269 - 0
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/checkStudentEdit.jsp

@@ -0,0 +1,269 @@
+<%@ page language="java" pageEncoding="utf-8"%>
+<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>云阅卷</title>
+<meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
+<link rel="stylesheet" href="${ctxStatic}/answer-check/css/style.css"/>
+<script type="text/javascript" src="${ctxStatic}/mark-new/js/jquery.min.js"></script>
+<script type="text/javascript" src="${ctxStatic}/mark-new/js/jquery-ui.min.js "></script>
+<script type="text/javascript" src="${ctxStatic}/mark-new/js/jquery.mousewheel.min.js"></script>
+
+<script type="text/javascript" src="${ctxStatic}/answer-check/js/common.js"></script>
+
+<link rel="stylesheet" href="${ctxStatic}/iviewer/jquery.iviewer.css"/>
+<script type="text/javascript" src="${ctxStatic}/iviewer/jquery.iviewer.js"></script>
+</head>
+<body id="index">
+<div class="wp">
+    <div id="top" class="top cl">
+        <div class="z"><div>
+            <span class="b">进度:</span><span class="i" id="progress"></span><span class="pipe">|</span>
+            <span class="b">姓名:</span><span class="i" id="name"></span><span class="pipe">|</span>
+            <span class="b">准考证:</span><span class="i" id="examNumber"></span><span class="pipe">|</span>
+            <span class="b">学号:</span><span class="i" id="studentCode"></span><span class="pipe">|</span>
+            <span class="b">科目:</span><span class="i" id="subject"></span><span class="pipe">|</span>
+            <span class="b">学习中心:</span><span class="i" id="campusName"></span><span class="pipe">|</span>
+            <span class="b">客观总分:</span><span class="i r" id="objectiveScore"></span><span class="pipe">|</span>
+            <span class="b">主观总分:</span><span class="i r" id="subjectiveScore"></span>
+        </div></div>
+        <div class="y cl">
+            <div class="iviewer_zoom_in" id="zoom-in-button"></div>
+            <div class="iviewer_zoom_out" id="zoom-out-button"></div>
+            <div class="iviewer_zoom_zero" id="zoom-origin-button"></div>
+            <div class="iviewer_zoom_fit" id="zoom-fit-button"></div>
+        </div>
+    </div>
+    <div class="middle">
+        <div class="middle-bg"></div>
+        <div class="box">
+            <div class="cont cl">
+                <div id="left" class="left">
+                        <div class="form-m">
+                      <!--       <div class="form-t">
+                                <span class="b">是否缺考:</span>
+                                <label>
+                                <span class="radio"><input type="button" class="absent-select" data-absent="true"></span><span>是</span>
+                                </label>
+                                <label>
+                                <span class="radio"><input type="button" class="absent-select" data-absent="false"></span><span>否</span>
+                                </label>
+                            </div> -->
+                            <div id="answer-content">
+                            </div>
+                        </div>
+                        <div class="form-b cl">
+                            <input type="button" id="save-button" value="保存"/>
+                            <input type="button" id="previous-button" class="next" value="上一张"/>
+                            <input type="button" id="next-button" class="next" value="下一张"/>
+                        </div>
+                </div>
+                <div class="right">
+                    <div style="position:relative;" class="image-content" id="image-holder">
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+</body>
+<script type="text/javascript">
+var ids = [${ids}];
+var current;
+var student;
+var iviewer;
+var regex = /^[a-z]+$/ig;
+$(document).ready(function() {
+    $('#next-button').click(function(){
+        process(current+1);
+    });
+    $('#previous-button').click(function(){
+        process(current-1);
+    });
+    $('#save-button').click(save);
+    $('.absent-select').click(function(){
+        if(!$(this).hasClass('on')) {
+            $('.absent-select').removeClass('on');
+            $(this).addClass('on');
+        }
+        if(student!=undefined) {
+            student.absent = $(this).attr('data-absent')=='true';
+        }
+    });
+    $('#zoom-in-button').click(function(){
+        if(iviewer!=undefined) {
+            iviewer.iviewer('zoom_by', 1);
+        }
+    });
+    $('#zoom-out-button').click(function(){
+        if(iviewer!=undefined) {
+            iviewer.iviewer('zoom_by', -1);
+        }
+    });
+    $('#zoom-origin-button').click(function(){
+        if(iviewer!=undefined) {
+            iviewer.iviewer('set_zoom', 100);
+        }
+    });
+    $('#zoom-fit-button').click(function(){
+        if(iviewer!=undefined) {
+            iviewer.iviewer('fit');
+        }
+    });
+    if(ids.length==0){
+        alert('没有需要处理的考生,请返回重新搜索');
+        return;
+    }
+    process(1);
+});
+
+function process(index){
+    if(index<1){
+        return;
+    }
+    if(index > ids.length){
+        alert('所有考生已处理完毕,请返回重新搜索');
+        return;
+    }
+    current = index;
+    $('#answer-content').empty();
+    $('#image-holder').hide();
+    $('#save-button').attr("disabled", true);
+    $('#previous-button').attr("disabled", true);
+    $('#next-button').attr("disabled", true);
+    $.post('${ctx}/admin/exam/check/answer/info', {
+        studentId: ids[index-1]
+    }, function(result){
+        student = result;
+        render();
+    }).error(function() {
+        alert('获取考生信息出错');
+        onProcessFinish(true)
+    });
+}
+
+function onProcessFinish(error) {
+    if(!error) {
+        $('#save-button').removeAttr("disabled");
+    }
+    $('#previous-button').removeAttr("disabled");
+    $('#next-button').removeAttr("disabled");
+}
+
+function render(){
+    $('#progress').html(current+'/'+ids.length);
+    $('#name').html(student.name);
+    $('#examNumber').html(student.examNumber);
+    $('#studentCode').html(student.studentCode);
+    $('#subject').html(student.subjectCode+'_'+student.subjectName);
+    $('#campusName').html(student.campusName);
+    $('#objectiveScore').html(student.objectiveScore);
+    $('#subjectiveScore').html(student.subjectiveScore);
+    
+    $('.absent-select').removeClass('on');
+    if(student.absent==true){
+        $('.absent-select[data-absent="true"]').addClass('on');
+    }else{
+        $('.absent-select[data-absent="false"]').addClass('on');
+    }
+    
+    var count = {};
+    for(var i=0;i<student.answers.length;i++){
+        var q = student.answers[i];
+        if(q.exist==true){
+            var title = student.titles[q.mainNumber];
+            var dom = $('#answer-content dl[number="'+q.mainNumber+'"]');
+            if(dom.length<1){
+                dom = $('<dl number="'+q.mainNumber+'"><dt><span class="icon"></span><span class="b"></span><span class="num"></span></dt><dd></dd></dl>').appendTo($('#answer-content'));
+                dom.find('span.b').html(student.titles[q.mainNumber]);
+            }
+            if(count[q.mainNumber]==undefined){
+                count[q.mainNumber] = 0;
+            }
+            count[q.mainNumber]++;
+            dom.find('span.num').html('('+count[q.mainNumber]+')');
+            
+            q.dom = $('<span class="input"><em>'+q.subNumber+'</em><input type="text" value="'+q.answer+'" number="'+i+'"/></span>').appendTo(dom.find('dd'));
+            if(title.indexOf('多项选择')>=0 || title.indexOf('多选')>=0){
+                q.dom.find('input').addClass('large');
+            }
+            q.dom.find('input').on('input', onAnswerInput);
+            q.dom.find('input').on('focus', onAnswerFocus);
+        }
+    }
+
+    if(iviewer==undefined){
+        iviewer = $('#image-holder').iviewer({
+            src: '${sheetServer}' + student.sheetUrls[0],
+            zoom_delta: 1.2,
+            zoom: 'fit',
+            zoom_min: 10,
+            mousewheel: false,
+            zoom_animation: false,
+            update_on_resize: true,
+            ui_disabled: true,
+            onFinishLoad: function(ev, url) {
+                $('#image-holder').show();
+                onProcessFinish(false);
+            },
+            onErrorLoad: function(ev, url) {
+                onProcessFinish(true);
+            }
+        });
+    }else{
+        iviewer.iviewer('loadImage', '${sheetServer}' + student.sheetUrls[0]);
+    }
+}
+
+function save(){
+    if(student==undefined){
+        return;
+    }
+    var array = [];
+    for(var i=0;i<student.answers.length;i++){
+        var q = student.answers[i];
+        if(q.exist==true){
+            var value = q.dom.find('input').val();
+            if(value.length==0){
+                value='#';
+            }
+            array.push(value);
+        }else{
+            array.push(q.answer);
+        }
+    }
+    $.post('${ctx}/admin/exam/check/student/save', {
+        studentId: student.id,
+        absent: student.absent,
+        answers: array.join(',')
+    }, function(result){
+        if(result==true){
+            process(current+1);
+        }else{
+            alert('保存失败,请稍后重试');
+        }
+    });
+}
+
+function onAnswerFocus(){
+    $(this)[0].select();
+}
+
+function onAnswerInput(){
+    var value = $(this).val();
+    var q = student.answers[parseInt($(this).attr('number'))];
+    if(value.length>1 && q.multi==false){
+        value = value.substring(value.length-1);
+    }
+    regex.lastIndex = 0;
+    if(value.length==0 || regex.test(value)==false){
+        value='';
+    }else{
+        value = value.toUpperCase();
+    }
+    $(this).val(value);
+}
+</script>
+</html>

+ 42 - 14
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/param/studentList.jsp

@@ -23,6 +23,14 @@
             <input id="breachBtnImportSubmit" class="btn btn-primary" type="submit" value="违纪考生导入"/>
             <a href="${ctx}/admin/exam-param/student/breachTemplate">下载模板</a>
         </form>
+    </div>
+    <div id="absentImportBox" class="hide">
+        <form id="absentImportForm" action="${ctx}/admin/exam-param/student/absentImport" method="post" enctype="multipart/form-data"
+              style="padding-left:20px;text-align:center;" class="form-search" onsubmit="loading('正在导入,请稍等...');"><br/>
+            <input id="absentUploadFile" name="file" type="file" style="width:330px"/><br/><br/>  
+            <input id="absentBtnImportSubmit" class="btn btn-primary" type="submit" value="缺考考生导入"/>
+            <a href="${ctx}/admin/exam-param/student/absentTemplate">下载模板</a>
+        </form>
     </div>
 	<form id="searchForm"  action="${ctx}/admin/exam-param/student" method="post" class="breadcrumb form-search">
 		<input type="hidden" id="pageNumber" name="pageNumber" value="${query.pageNumber }"/>
@@ -81,6 +89,11 @@
 				<option value="1" <c:if test="${query.breach!=null && query.breach==true}">selected</c:if>>违纪</option>
 				<option value="0" <c:if test="${query.breach!=null && query.breach==false}">selected</c:if>>正常</option>
 			</select>
+			<select id="manualAbsent" name="manualAbsent" class="input-small">
+				<option value="">不限</option>
+				<option value="1" <c:if test="${query.manualAbsent!=null && query.manualAbsent==true}">selected</c:if>>人工指定缺考</option>
+				<option value="0" <c:if test="${query.manualAbsent!=null && query.manualAbsent==false}">selected</c:if>>正常</option>
+			</select>
 			<label>签到表编号</label>
 			<input type="text" name="packageCode" value="${query.packageCode}" maxlength="30" class="input-small"/>
 			<label>批次编号</label>
@@ -92,7 +105,15 @@
 			<c:if test="${query.totalCount>0 && query.totalCount<=10000}">
 			&nbsp;<input id="export-button" class="btn" type="button" value="导出"/>
 			</c:if>
-            &nbsp;<input id="breachBtnImport" class="btn" type="button" value="违纪名单导入"/>
+			<div class="btn-group">
+                        <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+                            导入名单<span class="caret"></span>
+                        </a>
+                        <ul class="dropdown-menu">
+                            <li><a href="##" id="breachBtnImport">违纪名单</a></li>
+                            <li><a href="##" id="absentBtnImport">缺考名单</a></li>
+                        </ul>
+            </div>
 			<!-- &nbsp;<input id="clear-button" class="btn btn-danger" type="button" value="清空"/> -->
 		</div>
 	</form>
@@ -107,11 +128,11 @@
 				<th>层次</th>
 				<th>专业类型</th>
 				<th>学习中心</th>
-				<th>状态</th>
+				<th>扫描识别</th>
+				<th>人工指定</th>
 				<th>批次编号</th>
 				<th>签到表编号</th>
 				<th>考试备注信息</th>
-				<th>是否违纪</th>
 				<th>操作</th>
 			</tr>
 		</thead>
@@ -129,9 +150,6 @@
 				<c:if test="${student.upload==true}">
 				    <a class="sheet-link" href="##" data-sheet-url="${student.sheetUrlString}" data-answer-url="<c:if test="${student.answerUrl!=null}">${cardServer}${student.answerUrl}</c:if>" data-title="${student.examNumber}&nbsp;&nbsp;${student.name}&nbsp;&nbsp;客观总分${student.objectiveScoreString}&nbsp;&nbsp;主观总分${student.subjectiveScoreString}&nbsp;&nbsp;全卷总分${student.totalScoreString}">已上传</a>
 				    &nbsp;
-				    <c:if test="${student.manualAbsent==true}">
-				    人工指定
-				    </c:if>
 				    <c:if test="${student.absent==true}">
 				    缺考
 				    </c:if>
@@ -144,6 +162,20 @@
 				    未上传
 				</c:if>
 
+				</td>
+				<td>
+				    <c:if test="${student.breach==true}">
+                        <a href="##" onclick="updateBreach(${student.id});">违纪</a>
+                    </c:if>
+                    <c:if test="${student.breach==false}">
+                        正常
+                    </c:if>
+				 	<c:if test="${student.manualAbsent==true}">
+				    人工指定
+				    </c:if>
+				    <c:if test="${student.manualAbsent==false}">
+				    正常
+				    </c:if>
 				</td>
 				<td>${student.batchCode}</td>
 				<td>
@@ -155,14 +187,6 @@
 				</c:if>
 				</td>
 				<td>${student.examSite}&nbsp;${student.examRoom}</td>
-                <td >
-                    <c:if test="${student.breach==true}">
-                        <a href="##" onclick="updateBreach(${student.id});">违纪</a>
-                    </c:if>
-                    <c:if test="${student.breach==false}">
-                        正常
-                    </c:if>
-                </td>
 				<td>
                     <c:if test="${student.upload==false}">
     				    <a href="${ctx}/admin/exam-param/student/update?id=${student.id}">修改</a>
@@ -202,6 +226,10 @@ $("#breachBtnImport").click(function(){
 	$.jBox($("#breachImportBox").html(), {title:"导入数据", buttons:{"关闭":true},
 		bottomText:"导入文件不能超过5M,仅允许导入“xls”或“xlsx”格式文件!"});
 });
+$("#absentBtnImport").click(function(){
+	$.jBox($("#absentImportBox").html(), {title:"导入数据", buttons:{"关闭":true},
+		bottomText:"导入文件不能超过5M,仅允许导入“xls”或“xlsx”格式文件!"});
+});
 $("#clear-button").click(function(){
 	if(confirm('确定要删除当前的所有考生?')){
 		$("#searchForm").attr("action","${ctx}/admin/exam-param/student/clear");

+ 2 - 1
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/scoreList.jsp

@@ -93,7 +93,8 @@
                             导出<span class="caret"></span>
                         </a>
                         <ul class="dropdown-menu">
-                            <li><a href="##" onclick="goExport()">列表导出</a></li>
+                           <!--  <li><a href="##" onclick="goExport()">列表导出</a></li> -->
+                            <li><a id="export-button" onclick="goExport()"<c:if test="${!enableExport}"> href ="javascript:return false;" style="cursor: default;"</c:if> title="${exportMessage}">列表导出</a></li>
                             <c:if test="${showExportScore}">
                                 <li><a href="##" onclick="goExportScore()">成绩导出</a></li>
                             </c:if>