Преглед на файлове

新增成绩分析,评卷进度,勾选题目

ting.yin преди 4 години
родител
ревизия
21336291e3
променени са 40 файла, в които са добавени 955 реда и са изтрити 488 реда
  1. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamQuestionService.java
  2. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/MarkGroupService.java
  3. 7 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamQuestionServiceImpl.java
  4. 10 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamSubjectServiceImpl.java
  5. 19 3
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/MarkGroupServiceImpl.java
  6. 20 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/query/ExamSubjectSearchQuery.java
  7. 4 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkLibraryDao.java
  8. 10 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/query/ArbitrateHistorySearchQuery.java
  9. 6 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkLibraryServiceImpl.java
  10. 153 17
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkServiceImpl.java
  11. 9 5
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/TaskServiceImpl.java
  12. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkLibraryService.java
  13. 17 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkService.java
  14. 10 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/query/ReportSubjectQuery.java
  15. 10 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/query/ReportSubjectRangeQuery.java
  16. 10 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/RejectResult.java
  17. 48 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/ReportSubjectRangeDTO.java
  18. 27 15
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ArbitrateController.java
  19. 3 3
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/InspectedController.java
  20. 46 1
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/LibraryController.java
  21. 19 3
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkController.java
  22. 59 145
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkGroupController.java
  23. 35 18
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkTrackController.java
  24. 5 8
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/PaperController.java
  25. 93 42
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/report/ReportSubjectRangeController.java
  26. 13 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/vo/SubjectLibraryVO.java
  27. 4 1
      stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/CoreController.java
  28. 2 2
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/examIndex.jsp
  29. 72 57
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupAdd.jsp
  30. 71 64
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupEditFull.jsp
  31. 3 5
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupEditSimple.jsp
  32. 1 5
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/libraryList.jsp
  33. 68 16
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/markInfo.jsp
  34. 1 1
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/scoreList.jsp
  35. 1 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/report/reportSubjectClass.jsp
  36. 1 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/report/reportSubjectCollege.jsp
  37. 1 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/report/reportSubjectGroup.jsp
  38. 1 1
      stmms-web/src/main/webapp/WEB-INF/views/modules/report/reportSubjectQuestion.jsp
  39. 89 76
      stmms-web/src/main/webapp/WEB-INF/views/modules/report/reportSubjectRange.jsp
  40. 1 0
      stmms-web/src/main/webapp/WEB-INF/views/modules/report/reportSubjectTeacher.jsp

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

@@ -67,4 +67,6 @@ public interface ExamQuestionService {
 
     void deleteById(Integer questionId);
 
+    long countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(Integer examId, String subjectCode, boolean objective);
+
 }

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

@@ -61,4 +61,6 @@ public interface MarkGroupService {
 
     boolean validateStatus(Integer examId, String subjectCode, Integer number, MarkStatus... status);
 
+    int findMaxNumberByExamIdAndSubjectCode(int examId, String subjectCode);
+
 }

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

@@ -8,6 +8,7 @@ import cn.com.qmth.stmms.biz.exam.service.ExamService;
 import cn.com.qmth.stmms.biz.exam.service.query.ExamQuestionSearchQuery;
 import cn.com.qmth.stmms.common.enums.ObjectivePolicy;
 import cn.com.qmth.stmms.common.enums.ObjectiveStatus;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Sort;
@@ -20,6 +21,7 @@ import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
+
 import java.util.*;
 
 @Service
@@ -232,4 +234,9 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
         questionDao.delete(questionId);
     }
 
+    @Override
+    public long countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(Integer examId, String subjectCode,
+            boolean objective) {
+        return questionDao.countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(examId, subjectCode, objective);
+    }
 }

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

@@ -164,6 +164,16 @@ public class ExamSubjectServiceImpl extends BaseQueryService<ExamSubject> implem
                         predicates.add(cb.or(sub));
                     }
                 }
+                if (StringUtils.isNotBlank(query.getCodeNotIn())) {
+                    String[] list = query.getCodeNotIn().split(",");
+                    if (list.length > 0) {
+                        Predicate[] sub = new Predicate[list.length];
+                        for (int i = 0; i < list.length; i++) {
+                            sub[i] = cb.notEqual(root.get("pk").get("code"), list[i]);
+                        }
+                        predicates.add(cb.and(sub));
+                    }
+                }
                 return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                         .size()]));
             }

+ 19 - 3
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/MarkGroupServiceImpl.java

@@ -8,6 +8,7 @@ import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
 import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
 import cn.com.qmth.stmms.common.enums.MarkMode;
 import cn.com.qmth.stmms.common.enums.MarkStatus;
+
 import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -37,9 +38,12 @@ public class MarkGroupServiceImpl extends BaseQueryService<MarkGroup> implements
     @Transactional
     @Override
     public void updatePicList(int examId, String subjectCode, int number, List<PictureConfigItem> configList) {
-        groupDao.updatePicList(examId, subjectCode, number, configList != null && configList.size() > 0 ?
-                StringUtils.join(configList, PictureConfigItem.DB_ITEM_JOINER) :
-                "");
+        groupDao.updatePicList(
+                examId,
+                subjectCode,
+                number,
+                configList != null && configList.size() > 0 ? StringUtils.join(configList,
+                        PictureConfigItem.DB_ITEM_JOINER) : "");
     }
 
     @Transactional
@@ -168,4 +172,16 @@ public class MarkGroupServiceImpl extends BaseQueryService<MarkGroup> implements
         return groupDao.countByExamIdAndSubjectCodeAndNumberAndStatus(examId, subjectCode, number, status) > 0;
     }
 
+    @Override
+    public int findMaxNumberByExamIdAndSubjectCode(int examId, String subjectCode) {
+        List<MarkGroup> groups = groupDao.findByExamIdAndSubjectCode(examId, subjectCode);
+        int number = 0;
+        for (MarkGroup group : groups) {
+            if (number < group.getNumber()) {
+                number = group.getNumber();
+            }
+        }
+        return number;
+    }
+
 }

+ 20 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/query/ExamSubjectSearchQuery.java

@@ -23,6 +23,10 @@ public class ExamSubjectSearchQuery extends BaseQuery<ExamSubject> {
 
     private String codeIn;
 
+    private String codeNotIn;
+
+    private Boolean finished;
+
     public int getExamId() {
         return examId;
     }
@@ -99,4 +103,20 @@ public class ExamSubjectSearchQuery extends BaseQuery<ExamSubject> {
         this.codeIn = codeIn;
     }
 
+    public Boolean getFinished() {
+        return finished;
+    }
+
+    public void setFinished(Boolean finished) {
+        this.finished = finished;
+    }
+
+    public String getCodeNotIn() {
+        return codeNotIn;
+    }
+
+    public void setCodeNotIn(String codeNotIn) {
+        this.codeNotIn = codeNotIn;
+    }
+
 }

+ 4 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkLibraryDao.java

@@ -2,6 +2,7 @@ package cn.com.qmth.stmms.biz.mark.dao;
 
 import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
 import cn.com.qmth.stmms.common.enums.LibraryStatus;
+
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -147,4 +148,7 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
     int updateProblemResult(Integer id, LibraryStatus newStatus, Integer markerId, Date markerTime, Integer spent,
             LibraryStatus... previousStatus);
 
+    @Query("select distinct m.subjectCode from MarkLibrary m where m.examId=?1 and m.status not in (?2) ")
+    Set<String> findSubjectUnFinishByExamId(int examId, LibraryStatus... status);
+
 }

+ 10 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/query/ArbitrateHistorySearchQuery.java

@@ -23,6 +23,8 @@ public class ArbitrateHistorySearchQuery extends BaseQuery<ArbitrateHistory> {
 
     private Integer userId;
 
+    private String secretNumber;
+
     public void orderByIdDesc() {
         setSort(new Sort(Direction.DESC, "id"));
     }
@@ -87,4 +89,12 @@ public class ArbitrateHistorySearchQuery extends BaseQuery<ArbitrateHistory> {
         this.userId = userId;
     }
 
+    public String getSecretNumber() {
+        return secretNumber;
+    }
+
+    public void setSecretNumber(String secretNumber) {
+        this.secretNumber = secretNumber;
+    }
+
 }

+ 6 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkLibraryServiceImpl.java

@@ -200,4 +200,10 @@ public class MarkLibraryServiceImpl extends BaseQueryService<MarkLibrary> implem
         return library.getExamId() + "_" + library.getSubjectCode() + "_" + library.getGroupNumber();
     }
 
+    @Override
+    public Set<String> findSubjectUnFinishByExamId(int examId) {
+        return libraryDao.findSubjectUnFinishByExamId(examId, LibraryStatus.MARKED, LibraryStatus.ARBITRATED,
+                LibraryStatus.INSPECTED);
+    }
+
 }

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

@@ -1,18 +1,11 @@
 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.ExamStudentService;
-import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
-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.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -22,8 +15,52 @@ import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
+import cn.com.qmth.stmms.biz.exam.dao.ExamQuestionDao;
+import cn.com.qmth.stmms.biz.exam.dao.MarkGroupDao;
+import cn.com.qmth.stmms.biz.exam.dao.MarkGroupStudentDao;
+import cn.com.qmth.stmms.biz.exam.dao.MarkerDao;
+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.SubjectiveScore;
+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.mark.dao.ArbitrateHistoryDao;
+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.TrialHistoryDao;
+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.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.SubmitResult;
+import cn.com.qmth.stmms.biz.mark.model.TrialHistory;
+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.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;
 
 /**
  * 与评卷相关的所有修改操作(非传播性的新增操作除外),全部汇总到这里进行集中控制
@@ -83,6 +120,9 @@ public class MarkServiceImpl implements MarkService {
     @Autowired
     private ProblemHistoryDao problemHistoryDao;
 
+    @Autowired
+    private ExamService examService;
+
     private Map<Integer, Long> markerLastUpdateTime = new ConcurrentHashMap<>();
 
     /**
@@ -251,8 +291,12 @@ public class MarkServiceImpl implements MarkService {
     @Override
     @Transactional
     public void updateGroup(MarkGroup group, List<ExamQuestion> questionList, ScorePolicy policy, ThirdPolicy third) {
-        questionDao.deleteByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(group.getExamId(), group.getSubjectCode(),
-                false, group.getNumber());
+        List<ExamQuestion> old = questionDao.findByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(group.getExamId(),
+                group.getSubjectCode(), false, group.getNumber());
+        for (ExamQuestion question : old) {
+            question.setGroupNumber(null);
+            questionDao.saveAndFlush(question);
+        }
         double totalScore = 0d;
         for (ExamQuestion question : questionList) {
             totalScore += question.getTotalScore();
@@ -1427,4 +1471,96 @@ public class MarkServiceImpl implements MarkService {
         }
         return true;
     }
+
+    @Transactional
+    @Override
+    public boolean deleteByQuestion(ExamQuestion question) {
+        if (question.getGroupNumber() != null) {
+            return false;
+        } else {
+            int examId = question.getExamId();
+            String subjectCode = question.getSubjectCode();
+            boolean objective = question.isObjective();
+            questionDao.delete(question);
+            if (objective) {
+                examService.updateObjectiveStatus(examId, ObjectiveStatus.WAITING);
+            } else {
+                // 未分组的题目
+                long unGroupQuestionCount = questionDao.countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(examId,
+                        subjectCode, false);
+                // 考生整体状态与总分更新
+                long groupCount = groupDao.countByExamIdAndSubjectCode(examId, subjectCode);
+                if (groupCount == 0 || unGroupQuestionCount >= 0) {
+                    studentService.updateSubjectiveStatusAndScoreAndInspectorId(examId, subjectCode,
+                            SubjectiveStatus.UNMARK, 0, null, null, null);
+                } else {
+                    List<Integer> studentList = studentService.findIdByExamIdAndSubjectCodeAndSubjectiveStatus(examId,
+                            subjectCode, SubjectiveStatus.UNMARK, SubjectiveStatus.MARKED, SubjectiveStatus.INSPECTED);
+                    for (Integer studentId : studentList) {
+                        checkStudentSubjective(studentId, groupCount);
+                    }
+                }
+            }
+            subjectService.updateScore(examId, subjectCode, objective,
+                    questionDao.sumTotalScore(examId, subjectCode, objective));
+
+            return true;
+        }
+    }
+
+    @Override
+    @Transactional
+    public boolean rejectLibrary(MarkLibrary library, MarkStepDTO[] questionList, Integer userId) {
+        MarkGroup group = groupDao.findOne(library.getExamId(), library.getSubjectCode(), library.getGroupNumber());
+        if (group.getStatus() == MarkStatus.FINISH) {
+            return false;
+        }
+        List<ExamQuestion> questions = questionDao.findByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(
+                library.getExamId(), library.getSubjectCode(), false, library.getGroupNumber());
+        List<ScoreItem> sList = library.getScoreList();
+        for (MarkStepDTO markStepDTO : questionList) {
+            trackDao.deleteByLibraryIdAndQuestionNumber(library.getId(), markStepDTO.getMainNumber() + "."
+                    + markStepDTO.getSubNumber());
+            for (int i = 0; i < questions.size(); i++) {
+                ExamQuestion question = questions.get(i);
+                if (markStepDTO.getMainNumber() == question.getMainNumber()
+                        && markStepDTO.getSubNumber().equals(question.getSubNumber())) {
+                    sList.remove(i);
+                    sList.add(i, new ScoreItem(false));
+                }
+            }
+        }
+        StringBuilder markerScoreList = new StringBuilder();
+        for (int i = 0; i < sList.size(); i++) {
+            ScoreItem scoreItem = sList.get(i);
+            if (scoreItem.getScore() != null) {
+                markerScoreList.append(scoreItem.getScore());
+            }
+            if (i < sList.size() - 1) {
+                markerScoreList.append(",");
+            }
+        }
+        if (libraryDao.updateMarkerResult(library.getId(), LibraryStatus.REJECTED, library.getMarkerId(), null,
+                markerScoreList.toString(), null, null, LibraryStatus.MARKED) == 1) {
+            resetStudentGroup(library.getStudentId(), library.getExamId(), library.getSubjectCode(),
+                    library.getGroupNumber());
+            problemHistoryDao.resetByLibraryId(library.getId(), HistoryStatus.WAITING, userId, HistoryStatus.BACK,
+                    new Date());
+            // 开启三评时,打回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);
+                trackDao.deleteByLibraryId(third.getId());
+                specialTagDao.deleteByLibraryId(third.getId());
+                problemHistoryDao.deleteByLibraryId(third.getId());
+                libraryDao.delete(third);
+                updateLibraryCount(group);
+            }
+            updateMarkedCount(group);
+            return true;
+        } else {
+            return false;
+        }
+    }
 }

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

@@ -206,15 +206,19 @@ 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 = trackService.findByLibraryId(library.getId());
-        List<ScoreItem> sItems = library.getScoreList();
+        List<MarkTrack> tracks = new ArrayList<MarkTrack>();
+        List<ScoreItem> sItems = new ArrayList<ScoreItem>();
+        if (library != null) {
+            tracks = trackService.findByLibraryId(library.getId());
+            sItems = library.getScoreList();
+        }
         for (int i = 0; i < sList.size(); i++) {
             ExamQuestion question = sList.get(i);
             MarkStepDTO step = buildStep(question);
-            if (!sItems.isEmpty() && sItems.size() == sList.size()) {
-                step.setScore(sItems.get(i).getScore());
-            }
             if (library != null) {
+                if (!sItems.isEmpty() && sItems.size() == sList.size()) {
+                    step.setScore(sItems.get(i).getScore());
+                }
                 // 增加阅卷轨迹列表获取
                 String questionNumber = question.getQuestionNumber();
                 for (MarkTrack track : tracks) {

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

@@ -43,4 +43,6 @@ public interface MarkLibraryService {
 
     boolean applyLibrary(MarkLibrary library, Integer userId);
 
+    Set<String> findSubjectUnFinishByExamId(int examId);
+
 }

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

@@ -238,4 +238,21 @@ public interface MarkService {
      * @return
      */
     boolean rejectedStudent(ExamStudent student, MarkStepDTO[] questionList, Integer userId);
+
+    /**
+     * 删除某个小题
+     * 
+     * @param question
+     */
+    boolean deleteByQuestion(ExamQuestion question);
+
+    /**
+     * 管理员/组长打回某个任务的指定题目
+     * 
+     * @param library
+     * @param questionList
+     * @param userId
+     * @return
+     */
+    boolean rejectLibrary(MarkLibrary library, MarkStepDTO[] questionList, Integer userId);
 }

+ 10 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/query/ReportSubjectQuery.java

@@ -35,6 +35,8 @@ public class ReportSubjectQuery extends BaseQuery<ReportSubject> {
 
     private String subjectCodeIn;
 
+    private Integer range;
+
     public Integer getExamId() {
         return examId;
     }
@@ -131,4 +133,12 @@ public class ReportSubjectQuery extends BaseQuery<ReportSubject> {
         this.subjectCodeIn = subjectCodeIn;
     }
 
+    public Integer getRange() {
+        return range;
+    }
+
+    public void setRange(Integer range) {
+        this.range = range;
+    }
+
 }

+ 10 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/query/ReportSubjectRangeQuery.java

@@ -12,6 +12,8 @@ public class ReportSubjectRangeQuery extends BaseQuery<ReportSubjectRange> {
 
     private String subjectCode;
 
+    private Integer range;
+
     public Integer getExamId() {
         return examId;
     }
@@ -28,4 +30,12 @@ public class ReportSubjectRangeQuery extends BaseQuery<ReportSubjectRange> {
         this.subjectCode = subjectCode;
     }
 
+    public Integer getRange() {
+        return range;
+    }
+
+    public void setRange(Integer range) {
+        this.range = range;
+    }
+
 }

+ 10 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/RejectResult.java

@@ -9,6 +9,8 @@ public class RejectResult {
      */
     private Integer studentId;
 
+    private Integer libraryId;
+
     private MarkStepDTO[] questionList;
 
     public Integer getStudentId() {
@@ -27,4 +29,12 @@ public class RejectResult {
         this.questionList = questionList;
     }
 
+    public Integer getLibraryId() {
+        return libraryId;
+    }
+
+    public void setLibraryId(Integer libraryId) {
+        this.libraryId = libraryId;
+    }
+
 }

+ 48 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/ReportSubjectRangeDTO.java

@@ -0,0 +1,48 @@
+package cn.com.qmth.stmms.admin.dto;
+
+import java.text.DecimalFormat;
+
+import cn.com.qmth.stmms.common.annotation.ExcelField;
+
+public class ReportSubjectRangeDTO {
+
+    @ExcelField(title = "分数段", align = 2, sort = 10)
+    private String score;
+
+    @ExcelField(title = "人数", align = 2, sort = 20)
+    private Integer rangeCount;
+
+    @ExcelField(title = "频率", align = 2, sort = 30)
+    private String rangeRate;
+
+    public ReportSubjectRangeDTO(String score, Integer rangeCount, Double rangeRate) {
+        this.score = score;
+        this.rangeCount = rangeCount;
+        this.rangeRate = rangeRate > 0 ? (new DecimalFormat("####.###").format(rangeRate) + "%") : "0%";
+    }
+
+    public String getScore() {
+        return score;
+    }
+
+    public void setScore(String score) {
+        this.score = score;
+    }
+
+    public Integer getRangeCount() {
+        return rangeCount;
+    }
+
+    public void setRangeCount(Integer rangeCount) {
+        this.rangeCount = rangeCount;
+    }
+
+    public String getRangeRate() {
+        return rangeRate;
+    }
+
+    public void setRangeRate(String rangeRate) {
+        this.rangeRate = rangeRate;
+    }
+
+}

+ 27 - 15
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ArbitrateController.java

@@ -17,11 +17,11 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.domain.Sort;
 import org.springframework.data.domain.Sort.Direction;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
@@ -102,6 +102,9 @@ public class ArbitrateController extends BaseExamController {
     @Autowired
     private MarkLibraryService libraryService;
 
+    @Value("${slice.split.config}")
+    private String splitConfig;
+
     // 并发处理互斥锁
     private Map<Integer, Integer> currentTaskMap = new HashMap<Integer, Integer>();
 
@@ -159,7 +162,7 @@ public class ArbitrateController extends BaseExamController {
         ExamSubject examSubject = subjectService.find(examId, subjectCode);
         setting.accumulate("fileServer", fileService.getFileServer());
         Exam exam = examService.findById(examId);
-        setting.accumulate("mode", exam.getType());
+        setting.accumulate("examType", exam.getType());
         setting.accumulate("userName", wu.getName());
         JSONObject subject = new JSONObject();
         subject.accumulate("name", examSubject.getName());
@@ -167,9 +170,19 @@ public class ArbitrateController extends BaseExamController {
         subject.accumulate("paperUrl", examSubject.getPaperUrl() == null ? "" : examSubject.getPaperUrl());
         subject.accumulate("answerUrl", examSubject.getAnswerUrl() == null ? "" : examSubject.getAnswerUrl());
         setting.accumulate("subject", subject);
+        setting.accumulate("splitConfig", getSplitConfig());
         return setting;
     }
 
+    private double[] getSplitConfig() {
+        String strs[] = splitConfig.split(",");
+        double[] config = new double[strs.length];
+        for (int i = 0; i < strs.length; i++) {
+            config[i] = Double.parseDouble(strs[i]);
+        }
+        return config;
+    }
+
     @Logging(menu = "打回仲裁任务", type = LogType.UPDATE)
     @RequestMapping(value = "/back", method = RequestMethod.POST)
     @ResponseBody
@@ -197,14 +210,14 @@ public class ArbitrateController extends BaseExamController {
         return obj;
     }
 
-    @RequestMapping(value = "/history/{subjectCode}/{groupNumber}", method = RequestMethod.POST)
+    @RequestMapping(value = "/getHistory", method = RequestMethod.POST)
     @ResponseBody
     @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER })
-    public List<Task> getHistory(HttpServletRequest request, @PathVariable String subjectCode,
-            @PathVariable Integer groupNumber, @RequestParam(required = false) Integer pageNumber,
+    public List<Task> getHistory(HttpServletRequest request, @RequestParam String subjectCode,
+            @RequestParam Integer groupNumber, @RequestParam(required = false) Integer pageNumber,
             @RequestParam(required = false) Integer pageSize, @RequestParam String order, @RequestParam String sort,
             @RequestParam(required = false, defaultValue = "false") Boolean isTag,
-            @RequestParam(required = false) Integer studentId) {
+            @RequestParam(required = false) String secretNumber) {
         int examId = getSessionExamId(request);
         WebUser wu = RequestUtils.getWebUser(request);
         Direction d = Direction.DESC;
@@ -212,11 +225,9 @@ public class ArbitrateController extends BaseExamController {
         if (sort.equals("asc")) {
             d = Direction.ASC;
         }
-        if (order.equals("time")) {
+        if (order.equals("markerTime")) {
             querySort = new Sort(d, "updateTime");
-        } else if (order.equals("studentId")) {
-            querySort = new Sort(d, "studentId");
-        } else if (order.equals("score")) {
+        } else if (order.equals("markerScore")) {
             querySort = new Sort(d, "totalScore");
         }
         MarkGroup group = groupService.findOne(examId, subjectCode, groupNumber);
@@ -230,14 +241,12 @@ public class ArbitrateController extends BaseExamController {
             query.setUserId(wu.getUser().getId());
             query.setPageNumber(pageNumber);
             query.setPageSize(pageSize);
+            query.setSecretNumber(secretNumber);
             if (querySort != null) {
                 query.setSort(querySort);
             } else {
                 query.orderByUpdateTimeDesc();
             }
-            if (studentId != null) {
-                query.setStudentId(studentId);
-            }
             query = arbitrateService.findByQuery(query);
             for (ArbitrateHistory history : query.getResult()) {
                 Task task = taskService.build(history, group);
@@ -329,7 +338,7 @@ public class ArbitrateController extends BaseExamController {
         return result;
     }
 
-    @RequestMapping("/status")
+    @RequestMapping("/getStatus")
     @ResponseBody
     @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER })
     public JSONObject status(HttpServletRequest request, @RequestParam String subjectCode,
@@ -382,12 +391,15 @@ public class ArbitrateController extends BaseExamController {
     @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER })
     public Object clear(HttpServletRequest request, @RequestParam(required = false) Integer libraryId) {
         WebUser wu = RequestUtils.getWebUser(request);
+        JSONObject obj = new JSONObject();
         if (libraryId != null) {
             releaseTask(libraryId);
+            obj.accumulate("success", true);
         } else {
             releaseByUser(wu.getUser().getId());
+            obj.accumulate("success", true);
         }
-        return true;
+        return obj;
     }
 
     private void releaseByUser(Integer userId) {

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

@@ -198,15 +198,15 @@ public class InspectedController extends BaseExamController {
     public JSONObject clear(HttpServletRequest request, @RequestParam(required = false) String subjectCode,
             @RequestParam(required = false) Integer studentId) {
         JSONObject obj = new JSONObject();
-        obj.accumulate("success", false);
         if (studentId != null) {
             releaseStudent(studentId);
             obj.accumulate("success", true);
-        }
-        if (subjectCode != null) {
+        } else if (subjectCode != null) {
             int examId = getSessionExamId(request);
             releaseUser(examId, subjectCode, RequestUtils.getWebUser(request).getId());
             obj.accumulate("success", true);
+        } else {
+            obj.accumulate("success", false);
         }
         return obj;
     }

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

@@ -14,12 +14,14 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
+import cn.com.qmth.stmms.admin.dto.RejectResult;
 import cn.com.qmth.stmms.biz.exam.model.Exam;
 import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
@@ -319,7 +321,7 @@ public class LibraryController extends BaseExamController {
         query.addStatus(LibraryStatus.MARKED);
         long inspectedCount = libraryService.countByQuery(query);
         status.accumulate("totalCount", inspectedCount);
-        status.accumulate("valid", inspectedCount > 0);
+        status.accumulate("valid", true);
         return status;
     }
 
@@ -345,4 +347,47 @@ public class LibraryController extends BaseExamController {
             lockService.unlock(LockType.GROUP_LIBRARY, libraryId);
         }
     }
+
+    @Logging(menu = "打回", type = LogType.UPDATE)
+    @RequestMapping(value = "/rejected", method = RequestMethod.POST)
+    @ResponseBody
+    @RoleRequire({ Role.SCHOOL_ADMIN, Role.SUBJECT_HEADER, Role.INSPECTOR })
+    public JSONObject rejected(HttpServletRequest request, @RequestBody RejectResult rejectResult) {
+        JSONObject obj = new JSONObject();
+        WebUser wu = RequestUtils.getWebUser(request);
+        MarkLibrary library = libraryService.findById(rejectResult.getLibraryId());
+        if (library != null) {
+            if (subjectCheck(library.getSubjectCode(), RequestUtils.getWebUser(request))) {
+                try {
+                    lockService.watch(LockType.EXAM_SUBJECT, library.getExamId(), library.getSubjectCode());
+                    lockService.watch(LockType.GROUP, library.getExamId(), library.getSubjectCode(),
+                            library.getGroupNumber());
+                    if ((library.getStatus().equals(LibraryStatus.MARKED)
+                            || library.getStatus().equals(LibraryStatus.PROBLEM) || library.getStatus().equals(
+                            LibraryStatus.INSPECTED))
+                            && markService.rejectLibrary(library, rejectResult.getQuestionList(), wu.getId())) {
+                        obj.accumulate("success", true);
+                    } else {
+                        obj.accumulate("success", false);
+                        obj.accumulate("message", "无法打回该评卷任务");
+                    }
+                } catch (Exception e) {
+                    obj.accumulate("success", false);
+                    obj.accumulate("message", "打回评卷任务失败");
+                    log.error("back library error", e);
+                } finally {
+                    lockService.unwatch(LockType.GROUP, library.getExamId(), library.getSubjectCode(),
+                            library.getGroupNumber());
+                    lockService.unwatch(LockType.EXAM_SUBJECT, library.getExamId(), library.getSubjectCode());
+                }
+            } else {
+                obj.accumulate("success", false);
+                obj.accumulate("message", "没有操作该评卷任务的权限");
+            }
+        } else {
+            obj.accumulate("success", false);
+            obj.accumulate("message", "该评卷任务不存在");
+        }
+        return obj;
+    }
 }

+ 19 - 3
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkController.java

@@ -4,6 +4,7 @@ import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -86,6 +87,15 @@ public class MarkController extends BaseExamController {
             String subjectCodeIn = StringUtils.join(wu.getSubjectCodeSet(), ",");
             query.setCodeIn(subjectCodeIn);
         }
+        Set<String> unFinishSet = libraryService.findSubjectUnFinishByExamId(examId);
+        if (query.getFinished() != null) {
+            String subjectCodeIn = StringUtils.join(unFinishSet, ",");
+            if (query.getFinished()) {
+                query.setCodeNotIn(subjectCodeIn);
+            } else {
+                query.setCodeIn(subjectCodeIn);
+            }
+        }
         query = subjectService.findByQuery(query);
 
         List<SubjectLibraryVO> list = new LinkedList<SubjectLibraryVO>();
@@ -105,13 +115,19 @@ public class MarkController extends BaseExamController {
             String percent = libraryCount > 0 ? (new DecimalFormat("####.###").format(markedCount * 100.0
                     / libraryCount) + "%") : "0%";
             vo.setPercent(percent);
+            long count = questionService.countByExamIdAndSubjectAndObjectiveAndGroupNumberIsNull(examId,
+                    subject.getCode(), false);
+            vo.setGroupFinish(count == 0);
             list.add(vo);
         }
 
         double total = (double) groupService.sumLibraryCount(examId);
-        double finish = (double) groupService.sumMarkedCount(examId);
-        double percent = total > 0 ? (finish * 100 / total) : 0;
-        model.addAttribute("percent", new DecimalFormat("####.###").format(percent));
+        double markedCount = (double) groupService.sumMarkedCount(examId);
+        long subjectCount = subjectService.count(examId);
+        model.addAttribute("unMarkedCount", total - markedCount);
+        model.addAttribute("markedCount", markedCount);
+        model.addAttribute("unFinishCount", unFinishSet.size());
+        model.addAttribute("finishCount", subjectCount - unFinishSet.size());
         model.addAttribute("resultList", list);
         model.addAttribute("query", query);
         model.addAttribute("subjectList", getExamSubject(examId, wu));

+ 59 - 145
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkGroupController.java

@@ -1,22 +1,9 @@
 package cn.com.qmth.stmms.admin.exam;
 
-import cn.com.qmth.stmms.admin.dto.ExamQuestionDTO;
-import cn.com.qmth.stmms.admin.thread.MarkGroupDeleteThread;
-import cn.com.qmth.stmms.biz.exam.model.*;
-import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
-import cn.com.qmth.stmms.biz.exam.service.*;
-import cn.com.qmth.stmms.biz.file.service.FileService;
-import cn.com.qmth.stmms.biz.lock.LockService;
-import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
-import cn.com.qmth.stmms.biz.mark.service.MarkService;
-import cn.com.qmth.stmms.common.annotation.Logging;
-import cn.com.qmth.stmms.common.annotation.RoleRequire;
-import cn.com.qmth.stmms.common.domain.WebUser;
-import cn.com.qmth.stmms.common.enums.*;
-import cn.com.qmth.stmms.common.utils.RequestUtils;
+import java.util.ArrayList;
+import java.util.List;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import javax.servlet.http.HttpServletRequest;
 
 import net.sf.json.JSONArray;
 import net.sf.json.JSONObject;
@@ -37,9 +24,39 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
-import javax.servlet.http.HttpServletRequest;
+import cn.com.qmth.stmms.admin.thread.MarkGroupDeleteThread;
+import cn.com.qmth.stmms.biz.exam.model.Exam;
+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.query.ExamStudentSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
+import cn.com.qmth.stmms.biz.exam.service.ExamService;
+import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
+import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
+import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
+import cn.com.qmth.stmms.biz.exam.service.MarkerService;
+import cn.com.qmth.stmms.biz.file.service.FileService;
+import cn.com.qmth.stmms.biz.lock.LockService;
+import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
+import cn.com.qmth.stmms.biz.mark.service.MarkService;
+import cn.com.qmth.stmms.common.annotation.Logging;
+import cn.com.qmth.stmms.common.annotation.RoleRequire;
+import cn.com.qmth.stmms.common.domain.WebUser;
+import cn.com.qmth.stmms.common.enums.ExamType;
+import cn.com.qmth.stmms.common.enums.LockType;
+import cn.com.qmth.stmms.common.enums.LogType;
+import cn.com.qmth.stmms.common.enums.MarkMode;
+import cn.com.qmth.stmms.common.enums.MarkStatus;
+import cn.com.qmth.stmms.common.enums.Role;
+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.RequestUtils;
 
-import java.util.*;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 
 @Controller("markGroupController")
 @RequestMapping("/admin/exam/group")
@@ -47,8 +64,6 @@ public class MarkGroupController extends BaseExamController {
 
     protected static Logger log = LoggerFactory.getLogger(MarkGroupController.class);
 
-    private static final String NULL_PAPER_TYPE_PLACEHOLDER = "#";
-
     @Autowired
     private ExamSubjectService subjectService;
 
@@ -249,12 +264,16 @@ public class MarkGroupController extends BaseExamController {
         }
         MarkGroup group = new MarkGroup();
         group.setSubjectCode(subjectCode);
+        Integer number = groupService.findMaxNumberByExamIdAndSubjectCode(examId, subjectCode);
+        group.setNumber(number + 1);
         model.addAttribute("group", group);
+        model.addAttribute("subject", subject);
         model.addAttribute("markModeList", MarkMode.values());
         model.addAttribute("scorePolicyList", ScorePolicy.values());
         model.addAttribute("thirdPolicyList", ThirdPolicy.values());
         Exam exam = examService.findById(examId);
         model.addAttribute("examType", exam.getType());
+        model.addAttribute("questionList", questionService.findByExamAndSubjectAndObjective(examId, subjectCode, false));
         return "modules/exam/groupAdd";
     }
 
@@ -295,29 +314,14 @@ public class MarkGroupController extends BaseExamController {
         MarkGroup group = groupService.findOne(examId, subjectCode, number);
         if (group != null) {
             group.setPicList(buildPictureConfig(group));
-            List<ExamQuestion> list = questionService.findByExamAndSubjectAndObjectiveAndGroupNumber(examId,
-                    subjectCode, false, number);
-            List<ExamQuestionDTO> questionList = new ArrayList<>();
-            Map<Integer, ExamQuestionDTO> mainMap = new HashMap<>();
-            for (ExamQuestion question : list) {
-                ExamQuestionDTO dto = mainMap.get(question.getMainNumber());
-                if (dto == null) {
-                    dto = new ExamQuestionDTO();
-                    dto.setMainNumber(question.getMainNumber());
-                    dto.setMainTitle(question.getMainTitle());
-                    dto.setSubNumber(question.getSubNumber());
-                    dto.setScoreList(new ArrayList<>());
-                    mainMap.put(question.getMainNumber(), dto);
-                    questionList.add(dto);
-                }
-                dto.getScoreList().add(question.getTotalScore());
-            }
+            List<ExamQuestion> list = questionService.findByExamAndSubjectAndObjective(examId, subjectCode, false);
             model.addAttribute("group", group);
-            model.addAttribute("questionList", questionList);
+            model.addAttribute("questionList", list);
             model.addAttribute("pictureConfig", group.getPicList());
             model.addAttribute("markModeList", MarkMode.values());
             model.addAttribute("scorePolicyList", ScorePolicy.values());
             model.addAttribute("thirdPolicyList", ThirdPolicy.values());
+            model.addAttribute("subject", subjectService.find(examId, subjectCode));
             Exam exam = examService.findById(examId);
             model.addAttribute("examType", exam.getType());
             return "modules/exam/groupEditFull";
@@ -368,10 +372,10 @@ public class MarkGroupController extends BaseExamController {
 
     @Logging(menu = "修改大题", type = LogType.UPDATE)
     @SuppressWarnings("unchecked")
-    @RequestMapping("/save")
+    @RequestMapping("/update")
     @RoleRequire(Role.SCHOOL_ADMIN)
     @Transactional
-    public String save(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
+    public String update(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
             @RequestParam String subjectCode, @RequestParam Integer number, @RequestParam Boolean reset,
             @RequestParam(required = false) String picList, @RequestParam(required = false) Double doubleRate,
             @RequestParam(required = false) Double arbitrateThreshold,
@@ -379,49 +383,18 @@ public class MarkGroupController extends BaseExamController {
             @RequestParam(required = false) MarkMode markMode, @RequestParam(required = false) Integer trialCount,
             @RequestParam(required = false, defaultValue = "false") Boolean sheetView,
             @RequestParam(required = false, defaultValue = "false") Boolean enableAllZero,
-            @RequestParam(required = false) String questionDetail,
+            @RequestParam(required = false) Integer[] questionIds,
             @RequestParam(required = false) String intervalScoreList) {
         int examId = getSessionExamId(request);
         MarkGroup group = groupService.findOne(examId, subjectCode, number);
         if (group != null) {
             try {
-                if (questionDetail != null && reset.booleanValue()) {
+                if (questionIds != null && reset.booleanValue()) {
                     // advance update
-                    questionDetail = StringEscapeUtils.unescapeHtml(questionDetail);
-                    JSONArray array = JSONArray.fromObject(questionDetail);
-                    List<ExamQuestionDTO> detailList = JSONArray.toList(array, new ExamQuestionDTO(), new JsonConfig());
-                    for (int i = 0; i < detailList.size(); i++) {
-                        ExamQuestionDTO dto = detailList.get(i);
-                        Object scoreListArray[] = array.getJSONObject(i).getJSONArray("scoreList").toArray();
-                        List<Double> scoreList = new ArrayList<Double>();
-                        for (int j = 0; j < scoreListArray.length; j++) {
-                            scoreList.add(Double.parseDouble(scoreListArray[j].toString()));
-                        }
-                        dto.setScoreList(scoreList);
-                    }
-                    List<ExamQuestion> questionList = buildQuestionList(group, detailList);
-                    List<ExamQuestion> others = questionService.findByExamAndSubjectAndObjectiveAndGroupNumberNotEqual(
-                            examId, subjectCode, false, number);
-                    Set<String> numbers = new HashSet<>();
-                    Map<Integer, String> titles = new HashMap<>();
-                    for (ExamQuestion question : others) {
-                        numbers.add(question.getQuestionNumber());
-                        titles.put(question.getMainNumber(), question.getMainTitle());
-                    }
-                    for (ExamQuestion question : questionList) {
-                        if (numbers.contains(question.getQuestionNumber())) {
-                            addMessage(redirectAttributes, "题号不能重复");
-                            redirectAttributes.addAttribute("subjectCode", subjectCode);
-                            redirectAttributes.addAttribute("number", number);
-                            return "redirect:/admin/exam/group/edit-full";
-                        }
-                        if (titles.get(question.getMainNumber()) != null
-                                && !titles.get(question.getMainNumber()).equals(question.getMainTitle())) {
-                            addMessage(redirectAttributes, "大题名称不一致");
-                            redirectAttributes.addAttribute("subjectCode", subjectCode);
-                            redirectAttributes.addAttribute("number", number);
-                            return "redirect:/admin/exam/group/edit-full";
-                        }
+                    List<ExamQuestion> questionList = new ArrayList<ExamQuestion>();
+                    for (Integer questionId : questionIds) {
+                        ExamQuestion question = questionService.findById(questionId);
+                        questionList.add(question);
                     }
                     if (!questionList.isEmpty()) {
                         ScorePolicy policy = scorePolicy != null ? ScorePolicy.findByValue(scorePolicy) : null;
@@ -500,7 +473,7 @@ public class MarkGroupController extends BaseExamController {
     @RoleRequire(Role.SCHOOL_ADMIN)
     @Transactional
     public String insert(HttpServletRequest request, Model model, RedirectAttributes redirectAttributes,
-            @RequestParam String subjectCode, @RequestParam Integer number, @RequestParam String questionDetail,
+            @RequestParam String subjectCode, @RequestParam Integer number, @RequestParam Integer[] questionIds,
             @RequestParam String picList, @RequestParam(required = false) Double doubleRate,
             @RequestParam(required = false) Double arbitrateThreshold,
             @RequestParam(required = false) Integer thirdPolicy, @RequestParam(required = false) Integer scorePolicy,
@@ -514,8 +487,8 @@ public class MarkGroupController extends BaseExamController {
             addMessage(redirectAttributes, "评卷分组序号不能重复");
             redirectAttributes.addAttribute("subjectCode", subjectCode);
             return "redirect:/admin/exam/group/add";
-        } else if (StringUtils.isBlank(questionDetail)) {
-            addMessage(redirectAttributes, "大题详情必须设置");
+        } else if (questionIds == null || questionIds.length <= 0) {
+            addMessage(redirectAttributes, "题目不能为空");
             redirectAttributes.addAttribute("subjectCode", subjectCode);
             return "redirect:/admin/exam/group/add";
         } else {
@@ -528,52 +501,19 @@ public class MarkGroupController extends BaseExamController {
                     JSONArray array = JSONArray.fromObject(picList);
                     picConfigList = JSONArray.toList(array, new PictureConfigItem(), new JsonConfig());
                 }
-                // build questionDetail
-                questionDetail = StringEscapeUtils.unescapeHtml(questionDetail);
-                JSONArray array = JSONArray.fromObject(questionDetail);
-                List<ExamQuestionDTO> detailList = JSONArray.toList(array, new ExamQuestionDTO(), new JsonConfig());
-                for (int i = 0; i < detailList.size(); i++) {
-                    ExamQuestionDTO dto = detailList.get(i);
-                    Object o[] = array.getJSONObject(i).getJSONArray("scoreList").toArray();
-                    List<Double> scoreList = new ArrayList<Double>();
-                    for (int j = 0; j < o.length; j++) {
-                        scoreList.add(Double.parseDouble(o[j].toString()));
-                    }
-                    dto.setScoreList(scoreList);
-                }
-                List<ExamQuestion> current = questionService.findByExamAndSubjectAndObjectiveAndGroupNumberNotEqual(
-                        examId, subjectCode, false, number);
-                Set<String> numbers = new HashSet<>();
-                Map<Integer, String> titles = new HashMap<>();
-                for (ExamQuestion question : current) {
-                    numbers.add(question.getQuestionNumber());
-                    titles.put(question.getMainNumber(), question.getMainTitle());
-                }
-                if (detailList != null && detailList.size() > 0) {
+                if (questionIds != null && questionIds.length > 0) {
                     group = new MarkGroup(examId, subjectCode, number, picConfigList, 0d, doubleRate,
                             arbitrateThreshold, scorePolicy, markMode, trialCount, sheetView, enableAllZero,
                             thirdPolicy);
-                    List<ExamQuestion> list = buildQuestionList(group, detailList);
-                    for (ExamQuestion question : list) {
-                        if (numbers.contains(question.getQuestionNumber())) {
-                            addMessage(redirectAttributes, "题号不能重复");
-                            redirectAttributes.addAttribute("subjectCode", subjectCode);
-                            return "redirect:/admin/exam/group/add";
-                        }
-                        if (titles.get(question.getMainNumber()) != null
-                                && !titles.get(question.getMainNumber()).equals(question.getMainTitle())) {
-                            addMessage(redirectAttributes, "大题名称不一致");
-                            redirectAttributes.addAttribute("subjectCode", subjectCode);
-                            return "redirect:/admin/exam/group/add";
-                        }
+                    List<ExamQuestion> list = new ArrayList<ExamQuestion>();
+                    for (Integer questionId : questionIds) {
+                        ExamQuestion question = questionService.findById(questionId);
+                        question.setGroupNumber(number);
+                        list.add(question);
                     }
                     // clear and replace exam_question
-                    questionService
-                            .deleteByExamAndSubjectAndObjectiveAndGroupNumber(examId, subjectCode, false, number);
                     questionService.save(list);
                     groupService.save(group);
-                    subjectService.updateScore(examId, subjectCode, false,
-                            groupService.sumTotalScore(examId, subjectCode));
                     studentService.updateSubjectiveStatusAndScoreAndInspectorId(examId, subjectCode,
                             SubjectiveStatus.UNMARK, 0, null, null, null);
                     redirectAttributes.addAttribute("subjectCode", subjectCode);
@@ -635,32 +575,6 @@ public class MarkGroupController extends BaseExamController {
         return fileService.getSliceUris(student.getExamId(), student.getSecretNumber(), 1, student.getSliceCount());
     }
 
-    private List<ExamQuestion> buildQuestionList(MarkGroup group, List<ExamQuestionDTO> detailList) {
-        List<ExamQuestion> list = new LinkedList<>();
-        double totalScore = 0d;
-        for (ExamQuestionDTO detail : detailList) {
-            int i = 0;
-            for (double score : detail.getScoreList()) {
-                totalScore += score;
-                ExamQuestion question = new ExamQuestion();
-                question.setExamId(group.getExamId());
-                question.setSubjectCode(group.getSubjectCode());
-                question.setPaperType(NULL_PAPER_TYPE_PLACEHOLDER);
-                question.setMainTitle(detail.getMainTitle());
-                question.setMainNumber(detail.getMainNumber());
-                question.setSubNumber(detail.getSubNumber() + i);
-                question.setGroupNumber(group.getNumber());
-                question.setObjective(false);
-                question.setTotalScore(score);
-                question.setIntervalScore(1d);
-                list.add(question);
-                i++;
-            }
-        }
-        group.setTotalScore(totalScore);
-        return list;
-    }
-
     private List<Double> buildDoubleList(String content) {
         List<Double> list = new ArrayList<Double>();
         content = StringUtils.trimToNull(content);

+ 35 - 18
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/MarkTrackController.java

@@ -6,13 +6,15 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import org.apache.commons.lang.StringUtils;
+import net.sf.json.JSONObject;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
@@ -24,6 +26,7 @@ import cn.com.qmth.stmms.biz.file.service.FileService;
 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.MarkTrack;
+import cn.com.qmth.stmms.biz.mark.model.SpecialTagDTO;
 import cn.com.qmth.stmms.biz.mark.model.Task;
 import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
 import cn.com.qmth.stmms.biz.mark.service.MarkSpecialTagService;
@@ -31,9 +34,6 @@ import cn.com.qmth.stmms.biz.mark.service.MarkTrackService;
 import cn.com.qmth.stmms.biz.mark.service.TaskService;
 import cn.com.qmth.stmms.biz.utils.OriginTag;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
 @Controller("trackController")
 @RequestMapping("/admin/exam/track")
 public class MarkTrackController extends BaseExamController {
@@ -64,28 +64,35 @@ public class MarkTrackController extends BaseExamController {
     @Autowired
     private TaskService taskService;
 
+    @Value("${slice.split.config}")
+    private String splitConfig;
+
     @ResponseBody
-    @RequestMapping("/student/{studentId}")
-    public HashMap<String, Object> studentTrack(@PathVariable Integer studentId) {
-        HashMap<String, Object> map = new HashMap<String, Object>();
-        map.put("fileServer", fileService.getFileServer());
+    @RequestMapping("/student")
+    public JSONObject studentTrack(@RequestParam Integer studentId) {
+        JSONObject map = new JSONObject();
+        map.accumulate("fileServer", fileService.getFileServer());
         ExamStudent student = studentService.findById(studentId);
+
         if (student != null && student.isUpload()) {
             List<String> sliceUrls = fileService.getSliceUris(student.getExamId(), student.getSecretNumber(), 1,
                     student.getSliceCount());
-            map.put("sliceUrls", StringUtils.join(sliceUrls, ","));
+            map.accumulate("sliceUrls", sliceUrls);
             Map<MarkGroup, List<OriginTag>> maps = studentService.getSliceTags(student, false);
             List<OriginTag> tags = new ArrayList<OriginTag>();
             for (Entry<MarkGroup, List<OriginTag>> entry : maps.entrySet()) {
                 tags.addAll(entry.getValue());
             }
-            ObjectMapper mapper = new ObjectMapper();
-            try {
-                map.put("tagList", mapper.writeValueAsString(tags));
-            } catch (JsonProcessingException e) {
-                e.printStackTrace();
-                log.error("MarkTrackController-轨迹坐标获取出错", e);
+            List<SpecialTagDTO> list = new ArrayList<SpecialTagDTO>();
+            for (OriginTag originTag : tags) {
+                SpecialTagDTO dto = new SpecialTagDTO();
+                dto.setOffsetIndex(originTag.getOffsetIndex());
+                dto.setOffsetX(originTag.getOffsetX());
+                dto.setOffsetY(originTag.getOffsetY());
+                dto.setTagName(originTag.getContent());
+                list.add(dto);
             }
+            map.accumulate("tagList", list);
         }
         return map;
     }
@@ -113,16 +120,26 @@ public class MarkTrackController extends BaseExamController {
     }
 
     @ResponseBody
-    @RequestMapping("/library/{libraryId}")
-    public HashMap<String, Object> byLibrary(@PathVariable Integer libraryId) {
+    @RequestMapping("/library")
+    public HashMap<String, Object> byLibrary(@RequestParam Integer libraryId) {
         MarkLibrary library = libraryService.findById(libraryId);
         HashMap<String, Object> map = new HashMap<String, Object>();
         Task task = taskService.build(library);
         map.put("task", task);
         map.put("fileServer", fileService.getFileServer());
+        map.put("splitConfig", getSplitConfig());
         return map;
     }
 
+    private double[] getSplitConfig() {
+        String strs[] = splitConfig.split(",");
+        double[] config = new double[strs.length];
+        for (int i = 0; i < strs.length; i++) {
+            config[i] = Double.parseDouble(strs[i]);
+        }
+        return config;
+    }
+
     private HashMap<String, Object> set(MarkLibrary library, ExamStudent student) {
         HashMap<String, Object> groups = new HashMap<String, Object>();
         MarkGroup group = groupService.findOne(student.getExamId(), student.getSubjectCode(), library.getGroupNumber());

+ 5 - 8
stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/PaperController.java

@@ -15,6 +15,7 @@ import cn.com.qmth.stmms.biz.exam.service.query.ExamQuestionSearchQuery;
 import cn.com.qmth.stmms.biz.exam.service.query.ExamSubjectSearchQuery;
 import cn.com.qmth.stmms.biz.file.service.FileService;
 import cn.com.qmth.stmms.biz.lock.LockService;
+import cn.com.qmth.stmms.biz.mark.service.MarkService;
 import cn.com.qmth.stmms.biz.report.service.ReportService;
 import cn.com.qmth.stmms.common.annotation.Logging;
 import cn.com.qmth.stmms.common.annotation.RoleRequire;
@@ -76,6 +77,9 @@ public class PaperController extends BaseExamController {
     @Autowired
     private ReportService reportService;
 
+    @Autowired
+    private MarkService markService;
+
     @Logging(menu = "试卷管理查询", type = LogType.QUERY)
     @RequestMapping
     public String list(Model model, HttpServletRequest request, ExamSubjectSearchQuery query,
@@ -409,15 +413,8 @@ public class PaperController extends BaseExamController {
     @RoleRequire(Role.SCHOOL_ADMIN)
     public String delete(HttpServletRequest request, @PathVariable Integer questionId) {
         ExamQuestion question = questionService.findById(questionId);
-        int examId = getSessionExamId(request);
         String subjectCode = question.getSubjectCode();
-        boolean objective = question.isObjective();
-        questionService.deleteById(questionId);
-        if (objective) {
-            examService.updateObjectiveStatus(examId, ObjectiveStatus.WAITING);
-        }
-        subjectService.updateScore(examId, subjectCode, objective,
-                questionService.sumTotalScore(examId, subjectCode, objective));
+        markService.deleteByQuestion(question);
         return "redirect:/admin/exam/paper/detail?subjectCode=" + subjectCode;
     }
 

+ 93 - 42
stmms-web/src/main/java/cn/com/qmth/stmms/admin/report/ReportSubjectRangeController.java

@@ -1,12 +1,15 @@
 package cn.com.qmth.stmms.admin.report;
 
-import java.math.BigDecimal;
-import java.math.RoundingMode;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -15,12 +18,15 @@ import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
+import cn.com.qmth.stmms.admin.dto.ReportSubjectRangeDTO;
 import cn.com.qmth.stmms.admin.exam.BaseExamController;
-import cn.com.qmth.stmms.biz.report.model.ReportSubjectRange;
-import cn.com.qmth.stmms.biz.report.query.ReportSubjectRangeQuery;
-import cn.com.qmth.stmms.biz.report.service.ReportSubjectRangeService;
+import cn.com.qmth.stmms.biz.lock.LockService;
+import cn.com.qmth.stmms.biz.report.model.ReportSubject;
+import cn.com.qmth.stmms.biz.report.query.ReportSubjectQuery;
+import cn.com.qmth.stmms.biz.report.service.ReportSubjectService;
 import cn.com.qmth.stmms.common.annotation.Logging;
 import cn.com.qmth.stmms.common.domain.WebUser;
+import cn.com.qmth.stmms.common.enums.LockType;
 import cn.com.qmth.stmms.common.enums.LogType;
 import cn.com.qmth.stmms.common.utils.ExportExcel;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
@@ -38,58 +44,103 @@ public class ReportSubjectRangeController extends BaseExamController {
     protected static Logger log = LoggerFactory.getLogger(ReportSubjectRangeController.class);
 
     @Autowired
-    private ReportSubjectRangeService reportSubjectRangeService;
+    private ReportSubjectService reportSubjectService;
+
+    @Autowired
+    private LockService lockService;
 
     @Logging(menu = "课程分段统计", type = LogType.QUERY)
     @RequestMapping
-    public String list(Model model, HttpServletRequest request, ReportSubjectRangeQuery query) {
-        WebUser webuser = RequestUtils.getWebUser(request);
+    public String list(Model model, HttpServletRequest request, ReportSubjectQuery query) {
+        WebUser wu = RequestUtils.getWebUser(request);
         int examId = getSessionExamId(request);
-        // reportSubjectRangeService.saveReportRangeSubjectData(1);
-        query.setExamId(examId);
-        if (webuser.isSubjectHeader()) {
-            // TODO - subjectheader check
-            //query.setSubjectCode(webuser.getUser().getSubjectCode());
-        }
-        query = reportSubjectRangeService.findByQuery(query);
-        if (query.getCurrentCount() > 0) {
-            model.addAttribute("list", query.getResult());
+        if (StringUtils.isNotBlank(query.getSubjectCode()) && query.getRange() != null) {
+            ReportSubject subject = reportSubjectService.findOne(query.getExamId(), query.getSubjectCode());
+            model.addAttribute(
+                    "total",
+                    getScoreRange(subject.getScoreRange(), subject.getTotalScore(), subject.getRealityCount(),
+                            query.getRange()));
+            model.addAttribute("locked",
+                    lockService.isLocked(LockType.SCORE_CALCULATE, examId, subject.getSubjectCode()));
+
         }
-        model.addAttribute("subjectList", getExamSubject(examId, webuser));
+        model.addAttribute("subjectList", getExamSubject(examId, wu));
         model.addAttribute("query", query);
         return "modules/report/reportSubjectRange";
     }
 
+    private JSONArray getScoreRange(String scoreRange, double totalScore, Integer totalCount, int range) {
+        JSONArray result = new JSONArray();
+        JSONObject jsonObject = JSONObject.fromObject(scoreRange);
+        int rangeCount = 0;
+        int sumCount = 0;
+        int total = (int) Math.ceil(totalScore / range);
+        for (int i = total; i >= 0; i--) {
+            int start = i * range;
+            int end = (i - 1) * range + 1;
+            if (start > totalScore) {
+                start = (int) Math.ceil(totalScore);
+            }
+            if (end < 0) {
+                end = 0;
+            }
+            rangeCount = getSumCount(jsonObject, start, end);
+            sumCount = sumCount + rangeCount;
+            result.add(getRangeJson(totalCount, rangeCount, sumCount, i * range));
+        }
+        return result;
+    }
+
+    private int getSumCount(JSONObject jsonObject, int start, int end) {
+        int sumCount = 0;
+        int currentCount = 0;
+        if (start < end) {
+            for (int i = start; i <= end; i++) {
+                currentCount = jsonObject.getInt(String.valueOf(i));
+                sumCount = sumCount + currentCount;
+            }
+        } else if (start >= end) {
+            for (int i = end; i <= start; i++) {
+                currentCount = jsonObject.getInt(String.valueOf(i));
+                sumCount = sumCount + currentCount;
+            }
+        } else {
+            sumCount = jsonObject.getInt(String.valueOf(start));
+        }
+        return sumCount;
+    }
+
+    private JSONObject getRangeJson(Integer totalCount, int rangeCount, int sumCount, int score) {
+        JSONObject value = new JSONObject();
+        value.accumulate("score", score);
+        value.accumulate("rangeCount", rangeCount);
+        value.accumulate("rangeRate", rangeCount * 100.0 / totalCount);
+        value.accumulate("sumCount", sumCount);
+        value.accumulate("sumRate", sumCount * 100.0 / totalCount);
+        return value;
+    }
+
     @Logging(menu = "课程分段统计导出", type = LogType.EXPORT)
     @RequestMapping("/export")
-    public String export(ReportSubjectRangeQuery query, HttpServletRequest request, HttpServletResponse response,
+    public String export(ReportSubjectQuery query, HttpServletRequest request, HttpServletResponse response,
             RedirectAttributes redirectAttributes) {
-        WebUser webuser = RequestUtils.getWebUser(request);
-        int examId = getSessionExamId(request);
-        if (webuser.isSubjectHeader()) {
-            // TODO - subjectheader check
-            //query.setSubjectCode(webuser.getUser().getSubjectCode());
-        }
-        query.setExamId(examId);
-        query.setPageNumber(1);
-        query.setPageSize(Integer.MAX_VALUE);
-        query = reportSubjectRangeService.findByQuery(query);
-        List<ReportSubjectRange> list = query.getResult();
-        for (ReportSubjectRange r : list) {
-            r.setPercent0_49(new BigDecimal(r.getPercent0_49() * 100).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            r.setPercent50_59(new BigDecimal(r.getPercent50_59() * 100).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            r.setPercent60_69(new BigDecimal(r.getPercent60_69() * 100).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            r.setPercent70_79(new BigDecimal(r.getPercent70_79() * 100).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            r.setPercent80_89(new BigDecimal(r.getPercent80_89() * 100).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            r.setPercent90_100(new BigDecimal(r.getPercent90_100() * 100).setScale(2, RoundingMode.HALF_UP)
-                    .doubleValue());
-            r.setPercent_lt60(new BigDecimal(r.getPercent_lt60() * 100).setScale(2, RoundingMode.HALF_UP).doubleValue());
-            r.setPercent_mte60(new BigDecimal(r.getPercent_mte60() * 100).setScale(2, RoundingMode.HALF_UP)
-                    .doubleValue());
+        List<ReportSubjectRangeDTO> list = new ArrayList<ReportSubjectRangeDTO>();
+        if (StringUtils.isNotBlank(query.getSubjectCode()) && query.getRange() != null) {
+            ReportSubject subject = reportSubjectService.findOne(query.getExamId(), query.getSubjectCode());
+            JSONArray array = getScoreRange(subject.getScoreRange(), subject.getTotalScore(),
+                    subject.getRealityCount(), query.getRange());
+            for (int i = 0; i < array.size(); i++) {
+                JSONObject jsonObject = array.getJSONObject(i);
+                String score = jsonObject.getInt("score") + "-";
+                Integer rangeCount = jsonObject.getInt("rangeCount");
+                Double rangeRate = jsonObject.getDouble("rangeRate");
+                list.add(new ReportSubjectRangeDTO(score, rangeCount, rangeRate));
+            }
         }
         String fileName = "课程分段统计.xlsx";
         try {
-            new ExportExcel("课程分段统计", ReportSubjectRange.class).setDataList(list).write(response, fileName).dispose();
+            new ExportExcel("课程分段统计", ReportSubjectRangeDTO.class).setDataList(list).write(response, fileName)
+                    .dispose();
             return null;
         } catch (Exception e) {
             addMessage(redirectAttributes, "导出成绩失败!" + e.getMessage());

+ 13 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/vo/SubjectLibraryVO.java

@@ -12,6 +12,11 @@ public class SubjectLibraryVO {
 
     private String percent;
 
+    /**
+     * 是否完成主观题分组
+     */
+    private boolean groupFinish;
+
     public ExamSubject getSubject() {
         return subject;
     }
@@ -44,4 +49,12 @@ public class SubjectLibraryVO {
         this.percent = percent;
     }
 
+    public boolean isGroupFinish() {
+        return groupFinish;
+    }
+
+    public void setGroupFinish(boolean groupFinish) {
+        this.groupFinish = groupFinish;
+    }
+
 }

+ 4 - 1
stmms-web/src/main/java/cn/com/qmth/stmms/api/controller/CoreController.java

@@ -437,6 +437,10 @@ public class CoreController extends BaseApiController {
             subject = new ExamSubject();
             subject.setCode(code);
             subject.setExamId(examId);
+            subject.setObjectiveScore(0d);
+            subject.setSubjectiveScore(0d);
+            subject.setTotalScore(0d);
+            subject.setUploadCount(0);
         }
         subject.setName(name);
         subject.setRemark(remark);
@@ -444,5 +448,4 @@ public class CoreController extends BaseApiController {
         result.accumulate("updateTime", DateUtils.formatDateTime(new Date()));
         return result;
     }
-
 }

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

@@ -137,7 +137,7 @@
                                         <li><a href="${ctx}/admin/exam/inspected" target="mainFrame"><i class="icon-flag"></i><span data-i18n-text="index.inspected">成绩复核</span></a></li>
                                         <li><a href="${ctx}/admin/exam/problem/history" target="mainFrame"><i class="icon-tag"></i><span data-i18n-text="index.problem">问题试卷</span></a></li>
                                         <li><a href="${ctx}/admin/exam/reportSubject" target="mainFrame"><i class="icon-signal"></i><span data-i18n-text="index.report.total">总量分析</span></a></li>
-                                        <li><a href="${ctx}/admin/exam/reportSubjectCollege" target="mainFrame"><i class="icon-asterisk"></i><span data-i18n-text="index.report.subject">科目分析</span></a></li>
+                                        <li><a href="${ctx}/admin/exam/reportSubjectRange" target="mainFrame"><i class="icon-asterisk"></i><span data-i18n-text="index.report.subject">科目分析</span></a></li>
                                         <li><a href="${ctx}/admin/exam/check/answer" target="mainFrame"><i class="icon-check"></i><span data-i18n-text="index.check">数据检查</span></a></li>
                                         <li><a href="${ctx}/admin/operation/log" target="mainFrame"><i class="icon-tasks"></i><span data-i18n-text="index.log">操作日志</span></a></li>
                                     </c:if>
@@ -150,7 +150,7 @@
                                         <li><a href="${ctx}/admin/exam/inspected" target="mainFrame"><i class="icon-flag"></i><span data-i18n-text="index.inspected">成绩复核</span></a></li>
                                         <li><a href="${ctx}/admin/exam/problem/history" target="mainFrame"><i class="icon-tag"></i><span data-i18n-text="index.problem">问题试卷</span></a></li>
                                         <li><a href="${ctx}/admin/exam/reportSubject" target="mainFrame"><i class="icon-signal"></i><span data-i18n-text="index.report.total">总量分析</span></a></li>
-                                        <li><a href="${ctx}/admin/exam/reportSubjectCollege" target="mainFrame"><i class="icon-asterisk"></i><span data-i18n-text="index.report.subject">科目分析</span></a></li>
+                                        <li><a href="${ctx}/admin/exam/reportSubjectRange" target="mainFrame"><i class="icon-asterisk"></i><span data-i18n-text="index.report.subject">科目分析</span></a></li>
                                     </c:if>
                                     
                                     <c:if test="${web_user.inspector==true}">

+ 72 - 57
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupAdd.jsp

@@ -35,12 +35,37 @@
                     $(".doubleDiv").hide();
                 }
             });
+            $("#nextDiv").hide();
+            $("#btnNext").click(function () {
+            	var check_list = []
+            	$("input[name='questionIds']:checked").each(function(){
+	            	if($(this).val()!=""){
+	            		check_list.push($(this).val())
+            		}
+            	})
+                if(check_list.length==0) {
+                    alert('请选择题目');
+                    return false;
+                }
+            	$("#nextDiv").show();
+            	$("#nextLi").attr("class","active");
+            	$("#preDiv").hide();
+            	$("#preLi").attr("class","");
+            	
+            });
+			$("#btnPre").click(function () {
+            	$("#nextDiv").hide();
+            	$("#nextLi").attr("class","");
+				$("#preDiv").show();
+				$("#preLi").attr("class","active");
+            });
         });
     </script>
 </head>
 <body>
 <ul class="nav nav-tabs">
-    <li class="active"><a href="##">新增分组</a></li>
+    <li class="active" id="preLi"><a>勾选试题分组</a></li>
+    <li id="nextLi"><a>分组参数设置</a></li>
 </ul>
 <br/>
 <form:form id="inputForm" modelAttribute="group" action="${ctx}/admin/exam/group/insert" method="post"
@@ -48,31 +73,44 @@
     <tags:message content="${message}"/>
     <form:hidden path="subjectCode"/>
     <input type="hidden" id="questionDetail" name="questionDetail"/>
-    <div class="control-group">
-        <label class="control-label">序号</label>
+<div id="preDiv">
+	<div class="control-group">
+        <label class="control-label">课程</label>
         <div class="controls">
-            <form:input path="number" type="number" htmlEscape="false" max="100" min="1" class="required digits"/>
+		${subject.code }-${subject.name }
         </div>
     </div>
-    <div id="questionDiv">
-        <div class="control-group" id="questionBaseDiv">
-            <label class="control-label">大题</label>
-            <div class="controls">
-                <input name="mainNumber" type="number" htmlEscape="false" max="100" min="1" class="required digits input-mini"
-                       placeholder="大题号"/>
-                <input name="mainTitle" type="text" htmlEscape="false" maxlength="30" class="required"
-                       placeholder="名称"/>
-                <input name="subNumber" type="number" htmlEscape="false" max="100" min="1" class="required digits input-small"
-                       placeholder="起始小题号"/>
-                <input name="scoreList" type="text" htmlEscape="false" maxlength="100" class="required"
-                       placeholder="步骤分"/>
-                <input type="button" class="btn question-delete hide" onclick="questionDelete(this)" value="删除"/>
-            </div>
+    <div class="control-group">
+        <label class="control-label">主观题分</label>
+        <div class="controls">
+		${subject.subjectiveScore }分
         </div>
     </div>
     <div class="control-group">
+        <label class="control-label">主观题</label>
         <div class="controls">
-            <input type="button" class="btn" value="增加大题" id="quetion-add">
+        <table id="contentTable" class="table table-striped table-bordered table-condensed">
+			<c:forEach items="${questionList}" var="item">
+		    <tr>
+		    <td>${item.mainNumber }-${item.subNumber }</td>
+			<td>${item.mainTitle }</td>
+			<td>${item.totalScore}分</td>
+			<td><input type="checkbox" name="questionIds" value="${item.id }" <c:if test="${item.groupNumber!=null}"> disabled="disabled"</c:if>></td>
+			</tr>
+			</c:forEach>
+		</table>
+    	</div>
+    </div>
+    <div class="form-actions">
+        <a href="${ctx}/admin/exam/group?subjectCode=${group.subjectCode}" class="btn">取&nbsp;消</a>&nbsp;&nbsp;
+        <a id="btnNext" href="##" class="btn btn-primary">下一步 </a>
+    </div>
+</div>
+<div id="nextDiv" >
+    <div class="control-group">
+        <label class="control-label">分组号</label>
+        <div class="controls">
+            <form:input path="number" type="number" htmlEscape="false" max="100" min="1" class="required digits" value="${group.number }"/>
         </div>
     </div>
     <div class="control-group">
@@ -159,55 +197,32 @@
                 <input name="enableAllZero" type="checkbox" value="1" <c:if test="${group.enableAllZero}">checked</c:if>/>
             </div>
         </div>
-    </c:if>
+    </c:if>    
     <div class="form-actions">
-        <a id="btnSubmit" href="##" class="btn btn-primary">保 存</a>&nbsp;
-        <a href="${ctx}/admin/exam/group?subjectCode=${group.subjectCode}" class="btn">返回</a>
+        <a id="btnPre" class="btn">上一步</a>&nbsp;
+        <a id="btnSubmit" href="##" class="btn btn-primary">保 存</a>
     </div>
+</div>
 </form:form>
 <script type="text/javascript">
-    $("#quetion-add").click(function () {
-        var dom = $('#questionBaseDiv').clone();
-        dom.find('.question-delete').show();
-        dom.find("input[type='text'],input[type='number']").val('');
-        $("#questionDiv").append(dom)
-    });
-
-    function questionDelete(obj) {
-        $(obj).parent().parent().remove();
-    }
 
     $('#btnSubmit').click(function () {
     	if($("#arbitrateThreshold").val()<0){
     		alert("仲裁阈值不能小于0");
     		return;
     	}
-    	
-        var questionDetail = [];
-        var fill = true;
-        $("#questionDiv div div").each(function () {
-            var question = []
-            $(this).children("input[type='text'],input[type='number']").each(function () {
-                var q = $(this).val();
-                if (q == '') {
-                    fill = false;
-                }
-                question.push(q);
-            });
-            var detail = {
-                mainNumber: question[0],
-                mainTitle: question[1],
-                subNumber: question[2],
-                scoreList: question[3].split(",")
-            };
-            questionDetail.push(detail);
-        });
-        if (fill) {
-            $('#questionDetail').val(JSON.stringify(questionDetail));
-            $('#inputForm').submit();
-        } else {
-            alert('大题不能为空');
+    	var check_list = []
+    	$("input[name='questionIds']:checked").each(function(){
+        	if($(this).val()!=""){
+        		check_list.push($(this).val())
+    		}
+    	})
+        if(check_list.length==0) {
+            alert('请选择题目');
+            return false;
         }
+    	alert(check_list);
+       $('#inputForm').submit();
     });
 </script>
 </body>

+ 71 - 64
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupEditFull.jsp

@@ -46,53 +46,85 @@
                     $("#arbitrateThreshold").attr("value", "");
                     $(".doubleDiv").hide();
                 }
-
+            });
+            
+            $("#preDiv").hide();
+            $("#btnNext").click(function () {
+            	var check_list = []
+            	$("input[name='questionIds']:checked").each(function(){
+	            	if($(this).val()!=""){
+	            		check_list.push($(this).val())
+            		}
+            	})
+                if(check_list.length==0) {
+                    alert('请选择题目');
+                    return false;
+                }
+            	$("#nextDiv").show();
+            	$("#nextLi").attr("class","active");
+            	$("#preDiv").hide();
+            	$("#preLi").attr("class","");
+            	
+            });
+			$("#btnPre").click(function () {
+            	$("#nextDiv").hide();
+            	$("#nextLi").attr("class","");
+				$("#preDiv").show();
+				$("#preLi").attr("class","active");
             });
         });
     </script>
 </head>
 <body>
 <ul class="nav nav-tabs">
-    <li><a href="${ctx}/admin/exam/group?subjectCode=${group.subjectCode}">分组列表</a></li>
-    <li><a href="${ctx}/admin/exam/group/edit-simple?subjectCode=${group.subjectCode}&number=${group.number}">简要修改</a>
-    </li>
-    <li class="active"><a href="##">重置修改</a></li>
+    <li id="preLi"><a>勾选试题分组</a></li>
+    <li class="active" id="nextLi"><a>分组参数设置</a></li>
 </ul>
 <br/>
-<form:form id="inputForm" modelAttribute="group" action="${ctx}/admin/exam/group/save" method="post"
+<form:form id="inputForm" modelAttribute="group" action="${ctx}/admin/exam/group/update" method="post"
            class="form-horizontal">
     <tags:message content="${message}"/>
     <form:hidden path="subjectCode"/>
     <input type="hidden" id="rest" name="reset" value="true"/>
     <input type="hidden" id="number" name="number" value="${group.number }"/>
-    <input type="hidden" id="questionDetail" name="questionDetail"/>
+<div id="preDiv">
+	<div class="control-group">
+        <label class="control-label">课程</label>
+        <div class="controls">
+		${subject.code }-${subject.name }
+        </div>
+    </div>
     <div class="control-group">
-        <label class="control-label">分组序号</label>
+        <label class="control-label">主观题分</label>
         <div class="controls">
-            <form:input path="number" htmlEscape="false" class="required" readonly="true"/>
+		${subject.subjectiveScore }分
         </div>
     </div>
-    <div id="questionDiv">
-        <c:forEach items="${questionList}" var="question" varStatus="questionStatus">
-            <div class="control-group">
-                <label class="control-label">大题</label>
-                <div class="controls">
-                    <input name="mainNumber" type="number" htmlEscape="false" max="100" min="1"
-                           class="required digits input-mini" placeholder="大题号" value="${question.mainNumber }"/>
-                    <input name="mainTitle" type="text" htmlEscape="false" maxlength="30" class="required"
-                           placeholder="名称" value="${question.mainTitle }"/>
-                    <input name="subNumber" type="number" htmlEscape="false" max="100" min="1"
-                           class="required digits input-small" placeholder="起始小题号" value="${question.subNumber }"/>
-                    <input name="scoreList" type="text" htmlEscape="false" maxlength="100" class="required"
-                           placeholder="步骤分" value="${question.scoreString }"/>
-                    <input type="button" class="btn question-delete <c:if test="${questionStatus.first}">hide</c:if>" onclick="questionDelete(this)" value="删除"/>
-                </div>
-            </div>
-        </c:forEach>
+    <div class="control-group">
+        <label class="control-label">主观题</label>
+        <div class="controls">
+        <table id="contentTable" class="table table-striped table-bordered table-condensed">
+			<c:forEach items="${questionList}" var="item">
+		    <tr>
+		    <td>${item.mainNumber }-${item.subNumber }</td>
+			<td>${item.mainTitle }</td>
+			<td>${item.totalScore}分</td>
+			<td><input type="checkbox" name="questionIds" value="${item.id }" <c:if test="${item.groupNumber!=null && item.groupNumber!=group.number}"> disabled="disabled"</c:if> <c:if test="${item.groupNumber==group.number}"> checked</c:if>></td>
+			</tr>
+			</c:forEach>
+		</table>
+    	</div>
+    </div>
+    <div class="form-actions">
+        <a href="${ctx}/admin/exam/group?subjectCode=${group.subjectCode}" class="btn">取&nbsp;消</a>&nbsp;&nbsp;
+        <a id="btnNext" href="##" class="btn btn-primary">下一步 </a>
     </div>
+</div>
+<div id="nextDiv">
     <div class="control-group">
+        <label class="control-label">分组序号</label>
         <div class="controls">
-            <input type="button" class="btn" value="增加大题" id="quetion-add">
+            <form:input path="number" htmlEscape="false" class="required" readonly="true"/>
         </div>
     </div>
     <c:if test="${group.status.value==1}">
@@ -193,52 +225,27 @@
     <div class="form-actions">
         <a id="btnSubmit" href="##" class="btn btn-primary">保 存</a>&nbsp;
         <a href="${ctx}/admin/exam/group/delete?subjectCode=${group.subjectCode}&number=${group.number}" data-number="${group.number}" class="delete-button btn btn-danger">删除</a>
-        <a href="${ctx}/admin/exam/group?subjectCode=${group.subjectCode}&number=${group.number}" class="btn">返回</a>
+        <a id="btnPre" class="btn">上一步</a>
     </div>
+</div>
 </form:form>
 <script type="text/javascript">
-    $("#quetion-add").click(function () {
-        var dom = $('#questionDiv div:first').clone();
-        dom.find('.question-delete').show();
-        dom.find("input[type='text'],input[type='number']").val('');
-        $("#questionDiv").append(dom);
-    });
-
-    function questionDelete(obj) {
-        $(obj).parent().parent().remove();
-    }
-
     $('#btnSubmit').click(function () {
     	if($("#arbitrateThreshold").val()<0){
     		alert("仲裁阈值不能小于0");
     		return;
     	}
-    	
-        var questionDetail = [];
-        var fill = true;
-        $("#questionDiv div div").each(function () {
-            var question = []
-            $(this).children("input[type='text'],input[type='number']").each(function () {
-                var q = $(this).val();
-                if (q == '') {
-                    fill = false;
-                }
-                question.push(q);
-            });
-            var detail = {
-                mainNumber: question[0],
-                mainTitle: question[1],
-                subNumber: question[2],
-                scoreList: question[3].split(",")
-            };
-            questionDetail.push(detail);
-        });
-        if (fill) {
-            $('#questionDetail').val(JSON.stringify(questionDetail));
-            $('#inputForm').submit();
-        } else {
-            alert('大题不能为空');
+    	var check_list = []
+    	$("input[name='questionIds']:checked").each(function(){
+        	if($(this).val()!=""){
+        		check_list.push($(this).val())
+    		}
+    	})
+        if(check_list.length==0) {
+            alert('请选择题目');
+            return false;
         }
+        $('#inputForm').submit();
     });
 
     $('.delete-button').click(function () {

+ 3 - 5
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/groupEditSimple.jsp

@@ -56,11 +56,9 @@
 <ul class="nav nav-tabs">
     <li><a href="${ctx}/admin/exam/group?subjectCode=${group.subjectCode}">分组列表</a></li>
     <li class="active"><a href="##">简要修改</a></li>
-    <li><a href="${ctx}/admin/exam/group/edit-full?subjectCode=${group.subjectCode}&number=${group.number}&">重置修改</a>
-    </li>
 </ul>
 <br/>
-<form:form id="inputForm" modelAttribute="group" action="${ctx}/admin/exam/group/save" method="post"
+<form:form id="inputForm" modelAttribute="group" action="${ctx}/admin/exam/group/update" method="post"
            class="form-horizontal">
     <tags:message content="${message}"/>
     <form:hidden path="subjectCode"/>
@@ -148,8 +146,8 @@
         </div>
     </c:if>
     <div class="form-actions">
-        <a id="btnSubmit" href="##" class="btn btn-primary">保 存</a>&nbsp;
-        <a href="${ctx}/admin/exam/group?subjectCode=${group.subjectCode}" class="btn">返回</a>
+    	<a class="btn" href="${ctx}/admin/exam/group/edit-full?subjectCode=${group.subjectCode}&number=${group.number}">重置修改</a>&nbsp;
+        <a id="btnSubmit" href="##" class="btn btn-primary">保 存</a>
     </div>
 </form:form>
 <script type="text/javascript">

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

@@ -133,7 +133,7 @@
                         <a class="json-link" href="${ctx}/admin/exam/library/getJson?studentId=${result.studentId}&groupNumber=${result.groupNumber}" target="_blank">原图</a>
                     </c:if>
                     <c:if test="${examType!='MULTI_MEDIA'}">
-                        <a class="track-link" href="#" data-image-url="${ctx}/admin/exam/track/byLibrary?libraryId=${result.id}" data-title="${result.secretNumber}">阅卷轨迹</a>
+                      	<a href="${ctx}/web/admin/exam/track/library?libraryId=${result.id}" target="_blank">轨迹图</a>
                     </c:if>
                 </c:if>
                 <c:if test="${result.status.value==1 || result.status.value==5 ||result.status.value==6}">
@@ -161,10 +161,6 @@
             }
         });
     });
-    $('.track-link').click(function () {
-        initTrackPopover($(this).attr('data-title'), $(this).attr('data-image-url'));
-        return false;
-    });
     $('#subject-select').change(function () {
         var code = $(this).val();
         $('#group-select').empty();

+ 68 - 16
stmms-web/src/main/webapp/WEB-INF/views/modules/exam/markInfo.jsp

@@ -6,6 +6,7 @@
 	<meta name="decorator" content="default"/>
 	<%@include file="/WEB-INF/views/include/head.jsp" %>
 	<style type="text/css">.sort{color:#0663A2;cursor:pointer;}</style>
+	<script src="${ctxStatic}/echarts/echarts.min.js" type="text/javascript"></script>
 </head>
 <body>
     <ul class="nav nav-tabs">
@@ -17,6 +18,7 @@
         <li><a href="${ctx}/admin/exam/arbitrate?subjectCode=${query.code}">仲裁管理</a></li>
         <li><a href="${ctx}/admin/exam/quality?subjectCode=${query.code}">质量监控</a></li>
     </ul>
+    	<div id="main" style="width: 800px;height:400px;"></div>
 	<form id="searchForm" action="${ctx}/admin/exam/mark" 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 }"/>
@@ -28,19 +30,11 @@
 				<option value="${subject.code}" <c:if test="${subject.code==query.code}">selected</c:if>>${subject.code}-${subject.name}</option>
 				</c:forEach>
 			</select>
-			<label>层次</label>
-			<select class="input-small" name="level" id="level-select">
-				<option value="">请选择</option>
-				<c:forEach items="${levelList}" var="level">
-				<option value="${level}" data-level="${level}" <c:if test="${level==query.level}">selected</c:if>>${level}</option>
-				</c:forEach>
-			</select>
-			<label>专业类型</label>
-			<select class="input-small" name="category" id="category-select">
-				<option value="">请选择</option>
-				<c:forEach items="${categoryList}" var="category">
-				<option value="${category}" <c:if test="${category==query.category}">selected</c:if>>${category}</option>
-				</c:forEach>
+			<label>完成进度</label>
+			<select class="input-small" name="finished">
+				<option value="" <c:if test="${null==query.finished}">selected</c:if>>请选择</option>
+				<option value="1" <c:if test="${query.finished!=null &&query.finished}">selected</c:if>>已完成</option>
+				<option value="0" <c:if test="${query.finished!=null &&!query.finished}">selected</c:if>>未完成</option>
 			</select>
 			&nbsp;
 			<input id="btnSubmit" class="btn btn-primary" type="button" value="查询" onclick="goSearch()"/>
@@ -54,8 +48,6 @@
 					<li><a href="##" onclick="goExportMarker()">评卷员工作量</a></li>
 				</ul>
 			</div>
-			&nbsp;
-			<input id="btnProgress" class="btn" type="button" value="总进度:${percent}%"/>
 		</div>
 	</form>
 	<tags:message content="${message}"/>
@@ -72,7 +64,9 @@
 		<tbody>
 		<c:forEach items="${resultList}" var="result">
 			<tr>
-				<td>${result.subject.code}-${result.subject.name}&nbsp;${result.subject.remark}</td>
+				<td>${result.subject.code}-${result.subject.name}&nbsp;${result.subject.remark}
+				<c:if test="${!result.groupFinish}"><i class="icon-info-sign" title="主观分未完成分组"></i></c:if>
+				</td>
 				<td>${result.subject.uploadCount}</td>
 				<td>
 				    <fmt:formatNumber type="number" value="${result.subject.subjectiveScore}" pattern="###.#"/>
@@ -109,6 +103,64 @@ function goExportMarker(){
 	$("#searchForm").submit();
 	return false;
 }
+var markedCount =${markedCount};
+var unMarkedCount =${unMarkedCount};
+var finishCount =${finishCount};
+var unFinishCount =${unFinishCount};
+debugger;
+var myChart = echarts.init(document.getElementById('main'));
+myChart.setOption({
+	title: [{
+        text: '阅卷总进度'
+    }, {
+        text: '科目阅卷进度',
+        left: '50%',
+     
+    }],
+	legend: [{
+	    orient: "vertical",
+	    left: "left",
+	    top: "50px",
+	    data: ["任务待完成", "任务已完成",]
+	  },
+	  {
+		orient: "vertical",
+	    left: "50%",
+	    top: "50px",
+	    data: ["科目待完成", "科目已完成",]
+	}],
+    series : [
+        {
+        type: 'pie',
+        radius: '55%',
+        center: ['20%', '50%'],
+        data:[
+              {value:unMarkedCount, name:'任务待完成'},
+  			{value:markedCount, name:'任务已完成'}
+           ],
+        animation: false,
+        label: {
+            position: 'outer',
+            alignTo: 'none',
+            bleedMargin: 5
+        }
+    }, {
+        type: 'pie',
+        radius: '55%',
+        center: ['80%', '50%'],
+        data:[
+            {value:unFinishCount, name:'科目待完成'},
+			{value:finishCount, name:'科目已完成'}
+         ],
+        animation: false,
+        label: {
+            position: 'outer',
+            alignTo: 'none',
+            bleedMargin: 5
+        }
+    }]
+})
+
 </script>	
 </body>
 </html>

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

@@ -192,7 +192,7 @@
                            data-answer-url="<c:if test="${student.answerUrl!=null}">${fileServer}${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>
                         </c:if>
-                        <a href="${ctx}/admin/exam/track/student/${student.id}" target="_blank">轨迹图</a>
+                        <a href="${ctx}/web/admin/exam/track/student?studentId=${student.id}" target="_blank">轨迹图</a>
                     </c:if>
                     <c:if test="${examType=='MULTI_MEDIA'}">
                         <a class="json-link" href="${ctx}/admin/exam/library/getJson?studentId=${student.id}" target="_blank">原图</a>

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

@@ -16,6 +16,7 @@
 </head>
 <body>
 <ul class="nav nav-tabs">
+    <li><a href="${ctx}/admin/exam/reportSubjectRange">分段统计</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectCollege?subjectCode=${query.subjectCode}" data-i18n-text="report.college">学院分析</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectTeacher?subjectCode=${query.subjectCode}" data-i18n-text="report.teacher">任课老师分析</a></li>
     <li class="active"><a href="${ctx}/admin/exam/reportSubjectClass?subjectCode=${query.subjectCode}" data-i18n-text="report.class">班级分析</a></li>

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

@@ -16,6 +16,7 @@
 </head>
 <body>
 <ul class="nav nav-tabs">
+	<li><a href="${ctx}/admin/exam/reportSubjectRange">分段统计</a></li>
     <li class="active"><a href="${ctx}/admin/exam/reportSubjectCollege?subjectCode=${query.subjectCode}" data-i18n-text="report.college">学院分析</a>
     </li>
     <li><a href="${ctx}/admin/exam/reportSubjectTeacher?subjectCode=${query.subjectCode}" data-i18n-text="report.teacher">任课老师分析</a>

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

@@ -15,6 +15,7 @@
     }</style>
 </head>
 <ul class="nav nav-tabs">
+	<li><a href="${ctx}/admin/exam/reportSubjectRange">分段统计</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectCollege?subjectCode=${query.subjectCode}" data-i18n-text="report.college">学院分析</a>
     </li>
     <li><a href="${ctx}/admin/exam/reportSubjectTeacher?subjectCode=${query.subjectCode}" data-i18n-text="report.teacher">任课老师分析</a>

+ 1 - 1
stmms-web/src/main/webapp/WEB-INF/views/modules/report/reportSubjectQuestion.jsp

@@ -16,7 +16,7 @@
 </head>
 <body>
 <ul class="nav nav-tabs">
-
+	<li><a href="${ctx}/admin/exam/reportSubjectRange">分段统计</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectCollege?subjectCode=${query.subjectCode}" data-i18n-text="report.college">学院分析</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectTeacher?subjectCode=${query.subjectCode}" data-i18n-text="report.teacher">任课老师分析</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectClass?subjectCode=${query.subjectCode}" data-i18n-text="report.class">班级分析</a></li>

+ 89 - 76
stmms-web/src/main/webapp/WEB-INF/views/modules/report/reportSubjectRange.jsp

@@ -17,6 +17,7 @@
 </head>
 <body>
 <ul class="nav nav-tabs">
+    <li class="active"><a href="${ctx}/admin/exam/reportSubjectRange">分段统计</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectCollege?subjectCode=${query.subjectCode}" data-i18n-text="report.college">学院分析</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectTeacher?subjectCode=${query.subjectCode}" data-i18n-text="report.teacher">任课老师分析</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectClass?subjectCode=${query.subjectCode}" data-i18n-text="report.class">班级分析</a></li>
@@ -25,7 +26,6 @@
     <li><a href="${ctx}/admin/exam/reportSubjectQuestion?subjectCode=${query.subjectCode}&objective=false" data-i18n-text="report.question.subjective">主观题分析</a>
     </li>
     <li><a href="${ctx}/admin/exam/reportSubjectGroup?subjectCode=${query.subjectCode}" data-i18n-text="report.group">分组统计分析</a></li>
-    <li class="active"><a href="${ctx}/admin/exam/reportSubjectRange">分段统计</a></li>
 </ul>
 <form id="searchForm" action="${ctx}/admin/exam/reportSubjectRange" method="post" class="breadcrumb form-search">
     <input type="hidden" id="pageNumber" name="pageNumber" value="${query.pageNumber }"/>
@@ -39,69 +39,43 @@
             </c:forEach>
         </select>
 		 &nbsp;
+		<label>分数间隔</label>
+        <select class="input-large" name="range">
+                <option value="10" <c:if test="${query.range ==10 }">selected</c:if>>十分一段</option>
+                 <option value="5" <c:if test="${query.range ==5 }">selected</c:if>>五分一段</option>
+        </select>
         <input id="btnSubmit" class="btn btn-primary" type="button" value="查询" onclick="goSearch()"  data-i18n-value="report.group.search"/>
 		&nbsp;
 		<input id="export-button" class="btn" type="button" value="导出"  data-i18n-value="report.group.export"/>
+		<c:if test="${query.subjectCode!=null}">
+		&nbsp;
+		<a href="${ctx}/admin/exam/paper/report?subjectCode=${query.subjectCode}" class="btn" <c:if test="${locked}">disabled="disabled"</c:if>>分析计算</a>
+		</c:if>
+		&nbsp;
+		<a href="#" onclick="viewEcharts()" class="btn  btn-primary">查看统计图</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>0-</th>
-        <th>0-占比(%)</th>
-        <th>50-</th>
-        <th>50-占比(%)</th>
-        <th>60-</th>
-        <th>60-占比(%)</th>
-        <th>70-</th>
-        <th>70-占比(%)</th>
-        <th>80-</th>
-        <th>80-占比(%)</th>
-        <th>90-</th>
-        <th>90-占比(%)</th>
-        <th><60</th>
-        <th><60占比(%)</th>
-        <th>>=60</th>
-        <th>>=60占比(%)</th>
-        <th>总数</th>
-        <th>操作</th>
+        <th>分数段</th>
+        <th>人数</th>
+        <th>频率(%)</th>
     </tr>
     </thead>
     <tbody>
-    <c:forEach items="${list}" var="subject">
+    <c:forEach items="${total}" var="subject">
         <tr>
-            <td>
-                <a href="${ctx}/admin/exam/reportSubjectCollege?subjectCode=${subject.subjectCode}">${subject.subjectCode}-${subject.subjectName}</a>
-            </td>
-            <td>${subject.level}</td>
-            <td>${subject.count0_49}</td>
-            <td><fmt:formatNumber type="number" value="${subject.percent0_49 * 100}" pattern="0.00" maxFractionDigits="2"/></td>
-            <td>${subject.count50_59}</td>
-            <td><fmt:formatNumber type="number" value="${subject.percent50_59 * 100}" pattern="0.00" maxFractionDigits="2"/></td>
-            <td>${subject.count60_69}</td>
-            <td><fmt:formatNumber type="number" value="${subject.percent60_69 * 100}" pattern="0.00" maxFractionDigits="2"/></td>
-            <td>${subject.count70_79}</td>
-            <td><fmt:formatNumber type="number" value="${subject.percent70_79 * 100}" pattern="0.00" maxFractionDigits="2"/></td>
-            <td>${subject.count80_89}</td>
-            <td><fmt:formatNumber type="number" value="${subject.percent80_89 * 100}" pattern="0.00" maxFractionDigits="2"/></td>
-            <td>${subject.count90_100}</td>
-            <td><fmt:formatNumber type="number" value="${subject.percent90_100 * 100}" pattern="0.00" maxFractionDigits="2"/></td>
-            <td>${subject.lt60}</td>
-            <td><fmt:formatNumber type="number" value="${subject.percent_lt60 * 100}" pattern="0.00" maxFractionDigits="2"/></td>
-            <td>${subject.mte60}</td>
-            <td><fmt:formatNumber type="number" value="${subject.percent_mte60 * 100}" pattern="0.00" maxFractionDigits="2"/></td>
-            <td>${subject.totalCount}</td>
-            <td><a href="#" onclick="viewEcharts('${subject.subjectCode}','${subject.subjectName}',${subject.percent0_49},${subject.percent50_59},${subject.percent60_69},${subject.percent70_79},${subject.percent80_89},${subject.percent90_100})">分段图</a>
-            </td>
+            <td>${subject.score}-</td>
+            <td>${subject.rangeCount}</td>
+            <td><fmt:formatNumber type="number" value="${subject.rangeRate}" pattern="0.00" maxFractionDigits="2"/></td>
         </tr>
     </c:forEach>
     </tbody>
 </table>
-<div class="pagination">${query}</div>
 <script type="text/javascript">
+
 $("#export-button").click(function(){
 	if ($("#subjectCode").val() == null || $("#subjectCode").val() == '') {
         alert('请选择科目');
@@ -127,10 +101,31 @@ $("#export-button").click(function(){
         return false;
     }
 
-    function viewEcharts(code, name, d1, d2, d3, d4, d5, d6) {
+    function viewEcharts() {
 
-        var title = name + ' ' + code;
+    	var scores = new Array();
+        var rangeCounts = new Array();
+        var rangeRanges = new Array();
 
+        $('tbody tr').each(function (i) {
+            $(this).children('td').each(function (j) {
+                if(j == 0){
+                	scores.push($(this).text());
+                } else if(j == 1){
+                	rangeCounts.push($(this).text());
+                } else if(j == 2){
+                	rangeRanges.push($(this).text());
+                }
+            });
+            var width = 800;
+            if(i>40){
+            	width = 18*i;
+            }
+            if(i = $('tbody tr').length-1){
+            	$("#echart-content").width(width+"px") ;
+            }
+        });
+	debugger;
         var imageModal = new jBox('Modal');
         imageModal.setWidth($(window).width() * 0.9);
         imageModal.setHeight($(window).height() * 0.85);
@@ -140,35 +135,53 @@ $("#export-button").click(function(){
 
         var myChart = echarts.init(document.getElementById('echart-content'));
 
-        // 指定图表的配置项和数据
         var option = {
-            title: {
-                //text: title
-                // textAlign:'center'
-            },
-            tooltip: {},
-            legend: {
-                data: [title]
-            },
-            toolbox: {
-                feature : {
-                    saveAsImage : {show: true}
-                }
-            },
-            xAxis: {
-                data: ["0-49占比(%)", "50-59占比(%)", "60-69占比(%)", "70-79占比(%)", "80-89占比(%)", "90-100占比(%)"]
-            },
-            yAxis: [
-                {
-                    type: 'value'
-                }
-            ],
-            series: [{
-                name: title,
-                type: 'bar',
-                data: [d1, d2, d3, d4, d5, d6]
-            }]
-        };
+                title: {
+                    text: '课程成绩分段图'
+                    // textAlign:'center'
+                },
+                tooltip: {},
+                legend: {
+                    data: ["分数段",
+                           "人数",
+                           "频率"]
+                },
+                toolbox: {
+                    feature : {
+                        saveAsImage : {show: true}
+                    }
+                },
+           /*      dataZoom: [{
+                    type: 'slider',
+                    show: true,
+                    xAxisIndex: [0],
+                    left: '9%',
+                    bottom: -5,
+                    start: 10,
+                    end: 90 //初始化滚动条
+                }], */
+                xAxis: {
+                    axisLabel: {
+                        interval:0,
+                        rotate:60
+                    },
+                    data: scores
+                },
+                yAxis: [
+                    {
+                        type: 'value'
+                    }
+                ],
+                series: [{
+                    name: "人数",
+                    type: 'bar',
+                    data: rangeCounts
+                },{
+                    name: "频率",
+                    type: 'line',
+                    data: rangeRanges
+                }]
+            };
         // 使用刚指定的配置项和数据显示图表。
         myChart.setOption(option);
 

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

@@ -16,6 +16,7 @@
 </head>
 <body>
 <ul class="nav nav-tabs">
+	<li><a href="${ctx}/admin/exam/reportSubjectRange">分段统计</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectCollege?subjectCode=${query.subjectCode}" data-i18n-text="report.college">学院分析</a></li>
     <li class="active"><a href="${ctx}/admin/exam/reportSubjectTeacher?subjectCode=${query.subjectCode}" data-i18n-text="report.teacher">任课老师分析</a></li>
     <li><a href="${ctx}/admin/exam/reportSubjectClass?subjectCode=${query.subjectCode}" data-i18n-text="report.class">班级分析</a></li>