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

完成成绩分析功能;增加评卷导出单科目成绩,分列导出明细功能;

ting.yin 6 жил өмнө
parent
commit
de7dc023bb
26 өөрчлөгдсөн 1339 нэмэгдсэн , 153 устгасан
  1. 65 27
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubject.java
  2. 43 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectClass.java
  3. 29 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectClassGroup.java
  4. 28 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectGroup.java
  5. 69 59
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/SasConfigItem.java
  6. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectClassGroupService.java
  7. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectClassService.java
  8. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectGroupService.java
  9. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectQuestionService.java
  10. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectService.java
  11. 55 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectClassGroupServiceImpl.java
  12. 16 4
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectClassServiceImpl.java
  13. 15 4
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectGroupServiceImpl.java
  14. 20 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectQuestionServiceImpl.java
  15. 9 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectServiceImpl.java
  16. 21 9
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/ReportContext.java
  17. 84 6
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectClassQuestionLevelModule.java
  18. 73 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectClassRangeModule.java
  19. 74 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectQuestionLevelModule.java
  20. 38 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectQuestionOptionModule.java
  21. 17 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectRangeModule.java
  22. 67 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/ExamStudentDTO.java
  23. 38 27
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/exam/ScoreController.java
  24. 557 0
      stmms-web/src/main/java/cn/com/qmth/stmms/admin/utils/ExportStudentExcel.java
  25. 9 9
      stmms-web/src/main/webapp/WEB-INF/sas.properties
  26. 0 4
      stmms-web/src/main/webapp/WEB-INF/views/modules/exam/scoreList.jsp

+ 65 - 27
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubject.java

@@ -1,8 +1,6 @@
 package cn.com.qmth.stmms.biz.report.model;
 
 import java.io.Serializable;
-import java.util.LinkedList;
-import java.util.List;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
@@ -11,8 +9,6 @@ import javax.persistence.Id;
 import javax.persistence.Index;
 import javax.persistence.Table;
 
-import org.apache.commons.lang3.StringUtils;
-
 import cn.com.qmth.stmms.common.annotation.ExcelField;
 
 /**
@@ -121,10 +117,10 @@ public class ReportSubject implements Serializable {
     private Integer realityCount;
 
     /**
-     * 分段统计
+     * 高低分段统计
      */
-    @Column(name = "score_range", nullable = true)
-    private String scoreRange;
+    @Column(name = "range_level", nullable = true)
+    private String rangeLevel;
 
     /**
      * 所有选项
@@ -132,6 +128,24 @@ public class ReportSubject implements Serializable {
     @Column(name = "options", nullable = true)
     private String options;
 
+    /**
+     * 难度分布
+     */
+    @Column(name = "difficulity_level", nullable = true)
+    private String difficulityLevel;
+
+    /**
+     * 区分度分布
+     */
+    @Column(name = "discrimination_level", nullable = true)
+    private String discriminationLevel;
+
+    /**
+     * 高低分段统计
+     */
+    @Column(name = "score_range", nullable = true)
+    private String scoreRange;
+
     public Integer getId() {
         return id;
     }
@@ -236,12 +250,12 @@ public class ReportSubject implements Serializable {
         this.realityCount = realityCount;
     }
 
-    public String getScoreRange() {
-        return scoreRange;
+    public String getRangeLevel() {
+        return rangeLevel;
     }
 
-    public void setScoreRange(String scoreRange) {
-        this.scoreRange = scoreRange;
+    public void setRangeLevel(String rangeLevel) {
+        this.rangeLevel = rangeLevel;
     }
 
     public String getOptions() {
@@ -252,23 +266,47 @@ public class ReportSubject implements Serializable {
         this.options = options;
     }
 
-    public void addOptions(String option) {
-        options = StringUtils.trimToNull(options);
-        StringBuilder sb = new StringBuilder(options);
-        if (options != null) {
-            sb.append(DB_ITEM_JOINER);
-        }
-        sb.append(option);
-        this.options = sb.toString();
+    public String getDifficulityLevel() {
+        return difficulityLevel;
+    }
+
+    public void setDifficulityLevel(String difficulityLevel) {
+        this.difficulityLevel = difficulityLevel;
     }
 
-    public List<String> getOptionList() {
-        List<String> list = new LinkedList<String>();
-        options = StringUtils.trimToEmpty(options);
-        String[] values = StringUtils.split(options, DB_ITEM_JOINER);
-        for (String value : values) {
-            list.add(value);
-        }
-        return list;
+    public String getDiscriminationLevel() {
+        return discriminationLevel;
     }
+
+    public void setDiscriminationLevel(String discriminationLevel) {
+        this.discriminationLevel = discriminationLevel;
+    }
+
+    public String getScoreRange() {
+        return scoreRange;
+    }
+
+    public void setScoreRange(String scoreRange) {
+        this.scoreRange = scoreRange;
+    }
+
+//    public void addOptions(String option) {
+//        options = StringUtils.trimToNull(options);
+//        StringBuilder sb = new StringBuilder(options);
+//        if (options != null) {
+//            sb.append(DB_ITEM_JOINER);
+//        }
+//        sb.append(option);
+//        this.options = sb.toString();
+//    }
+//
+//    public List<String> getOptionList() {
+//        List<String> list = new LinkedList<String>();
+//        options = StringUtils.trimToEmpty(options);
+//        String[] values = StringUtils.split(options, DB_ITEM_JOINER);
+//        for (String value : values) {
+//            list.add(value);
+//        }
+//        return list;
+//    }
 }

+ 43 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectClass.java

@@ -125,7 +125,25 @@ public class ReportSubjectClass implements Serializable {
     private Double stdev;
 
     /**
-     * 分段统计
+     * 高低分段统计
+     */
+    @Column(name = "range_level", nullable = true)
+    private String rangeLevel;
+
+    /**
+     * 难度分布
+     */
+    @Column(name = "difficulity_level", nullable = true)
+    private String difficulityLevel;
+
+    /**
+     * 区分度分布
+     */
+    @Column(name = "discrimination_level", nullable = true)
+    private String discriminationLevel;
+
+    /**
+     * 高低分段统计
      */
     @Column(name = "score_range", nullable = true)
     private String scoreRange;
@@ -250,6 +268,30 @@ public class ReportSubjectClass implements Serializable {
         this.stdev = stdev;
     }
 
+    public String getRangeLevel() {
+        return rangeLevel;
+    }
+
+    public void setRangeLevel(String rangeLevel) {
+        this.rangeLevel = rangeLevel;
+    }
+
+    public String getDifficulityLevel() {
+        return difficulityLevel;
+    }
+
+    public void setDifficulityLevel(String difficulityLevel) {
+        this.difficulityLevel = difficulityLevel;
+    }
+
+    public String getDiscriminationLevel() {
+        return discriminationLevel;
+    }
+
+    public void setDiscriminationLevel(String discriminationLevel) {
+        this.discriminationLevel = discriminationLevel;
+    }
+
     public String getScoreRange() {
         return scoreRange;
     }

+ 29 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectClassGroup.java

@@ -18,7 +18,7 @@ import cn.com.qmth.stmms.common.annotation.ExcelField;
  * @date 2019年6月19日
  */
 @Entity
-@Table(name = "s_basic_subject_class_group", indexes = { @Index(columnList = "exam_id,subject_code") })
+@Table(name = "s_basic_class_group", indexes = { @Index(columnList = "exam_id,subject_code") })
 public class ReportSubjectClassGroup implements Serializable {
 
     private static final long serialVersionUID = 9150848313841148117L;
@@ -96,6 +96,18 @@ public class ReportSubjectClassGroup implements Serializable {
     @Column(name = "question_count")
     private Integer questionCount;
 
+    /**
+     * 难度分布
+     */
+    @Column(name = "difficulity_level", nullable = true)
+    private String difficulityLevel;
+
+    /**
+     * 区分度分布
+     */
+    @Column(name = "discrimination_level", nullable = true)
+    private String discriminationLevel;
+
     public Integer getId() {
         return id;
     }
@@ -184,4 +196,20 @@ public class ReportSubjectClassGroup implements Serializable {
         this.questionCount = questionCount;
     }
 
+    public String getDifficulityLevel() {
+        return difficulityLevel;
+    }
+
+    public void setDifficulityLevel(String difficulityLevel) {
+        this.difficulityLevel = difficulityLevel;
+    }
+
+    public String getDiscriminationLevel() {
+        return discriminationLevel;
+    }
+
+    public void setDiscriminationLevel(String discriminationLevel) {
+        this.discriminationLevel = discriminationLevel;
+    }
+
 }

+ 28 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectGroup.java

@@ -157,6 +157,18 @@ public class ReportSubjectGroup implements Serializable {
     @Column(name = "question_count")
     private Integer questionCount;
 
+    /**
+     * 难度分布
+     */
+    @Column(name = "difficulity_level", nullable = true)
+    private String difficulityLevel;
+
+    /**
+     * 区分度分布
+     */
+    @Column(name = "discrimination_level", nullable = true)
+    private String discriminationLevel;
+
     public Integer getId() {
         return id;
     }
@@ -317,4 +329,20 @@ public class ReportSubjectGroup implements Serializable {
         this.questionCount = questionCount;
     }
 
+    public String getDifficulityLevel() {
+        return difficulityLevel;
+    }
+
+    public void setDifficulityLevel(String difficulityLevel) {
+        this.difficulityLevel = difficulityLevel;
+    }
+
+    public String getDiscriminationLevel() {
+        return discriminationLevel;
+    }
+
+    public void setDiscriminationLevel(String discriminationLevel) {
+        this.discriminationLevel = discriminationLevel;
+    }
+
 }

+ 69 - 59
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/SasConfigItem.java

@@ -24,40 +24,40 @@ public class SasConfigItem {
     private Double excellentScore;
 
     // 区分度优
-    @Value("${sas.discriminationExcellentScore}")
-    private Double discriminationExcellentScore;
+    @Value("${sas.discriminationExcellentValue}")
+    private Double discriminationExcellentValue;
 
     // 区分度良
-    @Value("${sas.discriminationGoodScore}")
-    private Double discriminationGoodScore;
+    @Value("${sas.discriminationGoodValue}")
+    private Double discriminationGoodValue;
 
     // 区分度可
-    @Value("${sas.discriminationGeneralScore}")
-    private Double discriminationGeneralScore;
+    @Value("${sas.discriminationGeneralValue}")
+    private Double discriminationGeneralValue;
 
     // 区分度差
-    @Value("${sas.discriminationBadScore}")
-    private Double discriminationBadScore;
+    @Value("${sas.discriminationBadValue}")
+    private Double discriminationBadValue;
 
     // 难度高
-    @Value("${sas.difficultyHighScore}")
-    private Double difficultyHighScore;
+    @Value("${sas.difficultyHighValue}")
+    private Double difficultyHighValue;
 
     // 难度中
-    @Value("${sas.difficultyMiddleScore}")
-    private Double difficultyMiddleScore;
+    @Value("${sas.difficultyMiddleValue}")
+    private Double difficultyMiddleValue;
 
     // 难度低
-    @Value("${sas.difficultyLowScore}")
-    private Double difficultyLowScore;
+    @Value("${sas.difficultyLowValue}")
+    private Double difficultyLowValue;
 
     // 高分段
-    @Value("${sas.highScore}")
-    private Double highScore;
+    @Value("${sas.highValue}")
+    private Double highValue;
 
     // 低分段
-    @Value("${sas.lowScore}")
-    private Double lowScore;
+    @Value("${sas.lowValue}")
+    private Double lowValue;
 
     public SasConfigItem() {
 
@@ -67,7 +67,17 @@ public class SasConfigItem {
         text = StringUtils.trimToEmpty(text);
         try {
             JSONObject jsonObject = JSONObject.fromObject(text);
-            lowScore = jsonObject.getDouble("lowScore");
+            passScore = jsonObject.getDouble("passScore");
+            excellentScore = jsonObject.getDouble("excellentScore");
+            discriminationExcellentValue = jsonObject.getDouble("discriminationExcellentValue");
+            discriminationGoodValue = jsonObject.getDouble("discriminationGoodValue");
+            discriminationGeneralValue = jsonObject.getDouble("discriminationGeneralValue");
+            discriminationBadValue = jsonObject.getDouble("discriminationBadValue");
+            difficultyHighValue = jsonObject.getDouble("difficultyHighValue");
+            difficultyMiddleValue = jsonObject.getDouble("difficultyMiddleValue");
+            difficultyLowValue = jsonObject.getDouble("difficultyLowValue");
+            highValue = jsonObject.getDouble("highValue");
+            lowValue = jsonObject.getDouble("lowValue");
         } catch (Exception e) {
             throw new IllegalArgumentException("Invalid SasConfigItem init text:" + text);
         }
@@ -76,31 +86,31 @@ public class SasConfigItem {
     public static SasConfigItem parse(SasConfigItem configItem, String text) {
         SasConfigItem item = new SasConfigItem(text);
         if (item.getDifficultyHighValue() != null) {
-            configItem.setDifficultyHighScore(item.getDifficultyHighValue());
+            configItem.setDifficultyHighValue(item.getDifficultyHighValue());
         }
         if (item.getDifficultyLowValue() != null) {
-            configItem.setDifficultyLowScore(item.getDifficultyLowValue());
+            configItem.setDifficultyLowValue(item.getDifficultyLowValue());
         }
         if (item.getDifficultyMiddleValue() != null) {
-            configItem.setDifficultyMiddleScore(item.getDifficultyMiddleValue());
+            configItem.setDifficultyMiddleValue(item.getDifficultyMiddleValue());
         }
         if (item.getDiscriminationBadValue() != null) {
-            configItem.setDiscriminationBadScore(item.getDiscriminationBadValue());
+            configItem.setDiscriminationBadValue(item.getDiscriminationBadValue());
         }
         if (item.getDiscriminationExcellentValue() != null) {
-            configItem.setDiscriminationExcellentScore(item.getDiscriminationExcellentValue());
+            configItem.setDiscriminationExcellentValue(item.getDiscriminationExcellentValue());
         }
         if (item.getDiscriminationGoodValue() != null) {
-            configItem.setDiscriminationGoodScore(item.getDiscriminationGoodValue());
+            configItem.setDiscriminationGoodValue(item.getDiscriminationGoodValue());
         }
         if (item.getDiscriminationGeneralValue() != null) {
-            configItem.setDiscriminationGeneralScore(item.getDiscriminationGeneralValue());
+            configItem.setDiscriminationGeneralValue(item.getDiscriminationGeneralValue());
         }
-        if (item.getHighScore() != null) {
-            configItem.setHighScore(item.getHighScore());
+        if (item.getHighValue() != null) {
+            configItem.setHighValue(item.getHighValue());
         }
-        if (item.getLowScore() != null) {
-            configItem.setLowScore(item.getLowScore());
+        if (item.getLowValue() != null) {
+            configItem.setLowValue(item.getLowValue());
         }
         if (item.getExcellentScore() != null) {
             configItem.setExcellentScore(item.getExcellentScore());
@@ -128,75 +138,75 @@ public class SasConfigItem {
     }
 
     public Double getDiscriminationExcellentValue() {
-        return discriminationExcellentScore;
+        return discriminationExcellentValue;
     }
 
-    public void setDiscriminationExcellentScore(Double discriminationExcellentScore) {
-        this.discriminationExcellentScore = discriminationExcellentScore;
+    public void setDiscriminationExcellentValue(Double discriminationExcellentValue) {
+        this.discriminationExcellentValue = discriminationExcellentValue;
     }
 
     public Double getDiscriminationGoodValue() {
-        return discriminationGoodScore;
+        return discriminationGoodValue;
     }
 
-    public void setDiscriminationGoodScore(Double discriminationGoodScore) {
-        this.discriminationGoodScore = discriminationGoodScore;
+    public void setDiscriminationGoodValue(Double discriminationGoodValue) {
+        this.discriminationGoodValue = discriminationGoodValue;
     }
 
     public Double getDiscriminationGeneralValue() {
-        return discriminationGeneralScore;
+        return discriminationGeneralValue;
     }
 
-    public void setDiscriminationGeneralScore(Double discriminationGeneralScore) {
-        this.discriminationGeneralScore = discriminationGeneralScore;
+    public void setDiscriminationGeneralValue(Double discriminationGeneralValue) {
+        this.discriminationGeneralValue = discriminationGeneralValue;
     }
 
     public Double getDiscriminationBadValue() {
-        return discriminationBadScore;
+        return discriminationBadValue;
     }
 
-    public void setDiscriminationBadScore(Double discriminationBadScore) {
-        this.discriminationBadScore = discriminationBadScore;
+    public void setDiscriminationBadValue(Double discriminationBadValue) {
+        this.discriminationBadValue = discriminationBadValue;
     }
 
     public Double getDifficultyHighValue() {
-        return difficultyHighScore;
+        return difficultyHighValue;
     }
 
-    public void setDifficultyHighScore(Double difficultyHighScore) {
-        this.difficultyHighScore = difficultyHighScore;
+    public void setDifficultyHighValue(Double difficultyHighValue) {
+        this.difficultyHighValue = difficultyHighValue;
     }
 
     public Double getDifficultyMiddleValue() {
-        return difficultyMiddleScore;
+        return difficultyMiddleValue;
     }
 
-    public void setDifficultyMiddleScore(Double difficultyMiddleScore) {
-        this.difficultyMiddleScore = difficultyMiddleScore;
+    public void setDifficultyMiddleValue(Double difficultyMiddleValue) {
+        this.difficultyMiddleValue = difficultyMiddleValue;
     }
 
     public Double getDifficultyLowValue() {
-        return difficultyLowScore;
+        return difficultyLowValue;
     }
 
-    public void setDifficultyLowScore(Double difficultyLowScore) {
-        this.difficultyLowScore = difficultyLowScore;
+    public void setDifficultyLowValue(Double difficultyLowValue) {
+        this.difficultyLowValue = difficultyLowValue;
     }
 
-    public Double getHighScore() {
-        return highScore;
+    public Double getHighValue() {
+        return highValue;
     }
 
-    public void setHighScore(Double highScore) {
-        this.highScore = highScore;
+    public void setHighValue(Double highValue) {
+        this.highValue = highValue;
     }
 
-    public Double getLowScore() {
-        return lowScore;
+    public Double getLowValue() {
+        return lowValue;
     }
 
-    public void setLowScore(Double lowScore) {
-        this.lowScore = lowScore;
+    public void setLowValue(Double lowValue) {
+        this.lowValue = lowValue;
     }
 
 }

+ 3 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectClassGroupService.java

@@ -10,4 +10,7 @@ public interface ReportSubjectClassGroupService {
 
     void updateQuestionCount(Integer examId);
 
+    ReportSubjectClassGroup findOne(Integer examId, String subjectCode, String className, boolean objective,
+            Integer groupNumber);
+
 }

+ 2 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectClassService.java

@@ -19,4 +19,6 @@ public interface ReportSubjectClassService {
 
     ReportSubjectClass save(ReportSubjectClass r);
 
+    ReportSubjectClass findOne(Integer examId, String subjectCode, String className);
+
 }

+ 2 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectGroupService.java

@@ -21,4 +21,6 @@ public interface ReportSubjectGroupService {
 
     void updateQuestionCount(Integer examId);
 
+    ReportSubjectGroup findOne(Integer examId, String subjectCode, boolean objective, Integer mainNumber);
+
 }

+ 3 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectQuestionService.java

@@ -19,4 +19,7 @@ public interface ReportSubjectQuestionService {
 
     List<ReportSubjectQuestion> findByQuery(ReportSubjectQuery query);
 
+    ReportSubjectQuestion findOne(Integer examId, String subjectCode, boolean isObjective, String paperType,
+            Integer mainNumber, Integer subNumber);
+
 }

+ 2 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/ReportSubjectService.java

@@ -17,4 +17,6 @@ public interface ReportSubjectService {
 
     ReportSubjectQuery findByQuery(ReportSubjectQuery query);
 
+    ReportSubject findOne(Integer examId, String subjectCode);
+
 }

+ 55 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectClassGroupServiceImpl.java

@@ -1,12 +1,26 @@
 package cn.com.qmth.stmms.biz.report.service.impl;
 
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import cn.com.qmth.stmms.biz.common.BaseQueryService;
 import cn.com.qmth.stmms.biz.report.dao.ReportSubjectClassGroupDao;
 import cn.com.qmth.stmms.biz.report.model.ReportSubjectClassGroup;
+import cn.com.qmth.stmms.biz.report.query.ReportSubjectQuery;
 import cn.com.qmth.stmms.biz.report.service.ReportSubjectClassGroupService;
 
 @Service
@@ -33,4 +47,45 @@ public class ReportSubjectClassGroupServiceImpl extends BaseQueryService<ReportS
         reportSubjectClassGroupDao.updateQuestionCount(examId);
     }
 
+    @Override
+    public ReportSubjectClassGroup findOne(Integer examId, String subjectCode, String className, boolean objective,
+            Integer groupNumber) {
+        ReportSubjectQuery query = new ReportSubjectQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        query.setClassName(className);
+        query.setObjective(objective);
+        query.setGroupNumber(groupNumber);
+        List<ReportSubjectClassGroup> list = findByQuery(query);
+        return list.isEmpty() ? null : list.get(0);
+    }
+
+    public List<ReportSubjectClassGroup> findByQuery(final ReportSubjectQuery query) {
+        query.setSort(new Sort(Direction.ASC, "groupNumber"));
+        Page<ReportSubjectClassGroup> result = reportSubjectClassGroupDao.findAll(
+                new Specification<ReportSubjectClassGroup>() {
+
+                    @Override
+                    public Predicate toPredicate(Root<ReportSubjectClassGroup> root, CriteriaQuery<?> cQuery,
+                            CriteriaBuilder cb) {
+                        List<Predicate> predicates = new LinkedList<Predicate>();
+                        if (query.getExamId() != null) {
+                            predicates.add(cb.equal(root.get("examId"), query.getExamId()));
+                        }
+                        if (StringUtils.isNotBlank(query.getSubjectCode())) {
+                            predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
+                        }
+                        if (StringUtils.isNotBlank(query.getClassName())) {
+                            predicates.add(cb.equal(root.get("className"), query.getClassName()));
+                        }
+                        if (query.getGroupNumber() > 0) {
+                            predicates.add(cb.equal(root.get("groupNumber"), query.getGroupNumber()));
+                        }
+                        return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates
+                                .toArray(new Predicate[predicates.size()]));
+                    }
+                }, query);
+        return result.getContent();
+    }
+
 }

+ 16 - 4
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectClassServiceImpl.java

@@ -30,8 +30,8 @@ import cn.com.qmth.stmms.biz.report.service.ReportSubjectClassService;
  * @date 2019-04-16
  */
 @Service
-public class ReportSubjectClassServiceImpl extends BaseQueryService<ReportSubjectClass>
-        implements ReportSubjectClassService {
+public class ReportSubjectClassServiceImpl extends BaseQueryService<ReportSubjectClass> implements
+        ReportSubjectClassService {
 
     @Autowired
     private ReportSubjectClassDao reportSubjectClassDao;
@@ -60,8 +60,8 @@ public class ReportSubjectClassServiceImpl extends BaseQueryService<ReportSubjec
                 if (StringUtils.isNotBlank(query.getClassName())) {
                     predicates.add(cb.equal(root.get("className"), query.getClassName()));
                 }
-                return predicates.isEmpty() ? cb.conjunction()
-                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
+                        .size()]));
             }
         }, query);
         return result.getContent();
@@ -72,4 +72,16 @@ public class ReportSubjectClassServiceImpl extends BaseQueryService<ReportSubjec
         return reportSubjectClassDao.save(r);
     }
 
+    @Override
+    public ReportSubjectClass findOne(Integer examId, String subjectCode, String className) {
+        if(StringUtils.isBlank(className)){   
+            return null;
+        }
+        ReportSubjectQuery query = new ReportSubjectQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        query.setClassName(className);
+        List<ReportSubjectClass> list = findByQuery(query);
+        return list.isEmpty() ? null : list.get(0);
+    }
 }

+ 15 - 4
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectGroupServiceImpl.java

@@ -30,8 +30,8 @@ import cn.com.qmth.stmms.biz.report.service.ReportSubjectGroupService;
  * @Date 2019-04-18
  */
 @Service
-public class ReportSubjectGroupServiceImpl extends BaseQueryService<ReportSubjectGroup>
-        implements ReportSubjectGroupService {
+public class ReportSubjectGroupServiceImpl extends BaseQueryService<ReportSubjectGroup> implements
+        ReportSubjectGroupService {
 
     @Autowired
     private ReportSubjectGroupDao reportSubjectGroupDao;
@@ -60,8 +60,8 @@ public class ReportSubjectGroupServiceImpl extends BaseQueryService<ReportSubjec
                 if (query.getGroupNumber() > 0) {
                     predicates.add(cb.equal(root.get("groupNumber"), query.getGroupNumber()));
                 }
-                return predicates.isEmpty() ? cb.conjunction()
-                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
+                        .size()]));
             }
         }, query);
         return result.getContent();
@@ -78,4 +78,15 @@ public class ReportSubjectGroupServiceImpl extends BaseQueryService<ReportSubjec
         reportSubjectGroupDao.updateQuestionCount(examId);
     }
 
+    @Override
+    public ReportSubjectGroup findOne(Integer examId, String subjectCode, boolean objective, Integer mainNumber) {
+        ReportSubjectQuery query = new ReportSubjectQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        query.setObjective(objective);
+        query.setGroupNumber(mainNumber);
+        List<ReportSubjectGroup> list = findByQuery(query);
+        return list.isEmpty() ? null : list.get(0);
+    }
+
 }

+ 20 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectQuestionServiceImpl.java

@@ -67,6 +67,12 @@ public class ReportSubjectQuestionServiceImpl extends BaseQueryService<ReportSub
                         if (StringUtils.isNotBlank(query.getSubjectCode())) {
                             predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
                         }
+                        if (query.getMainNumber() != null) {
+                            predicates.add(cb.equal(root.get("mainNumber"), query.getMainNumber()));
+                        }
+                        if (query.getSubNumber() != null) {
+                            predicates.add(cb.equal(root.get("subNumber"), query.getSubNumber()));
+                        }
                         predicates.add(cb.equal(root.get("objective"), query.getObjective()));
                         return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates
                                 .toArray(new Predicate[predicates.size()]));
@@ -75,4 +81,18 @@ public class ReportSubjectQuestionServiceImpl extends BaseQueryService<ReportSub
         return result.getContent();
     }
 
+    @Override
+    public ReportSubjectQuestion findOne(Integer examId, String subjectCode, boolean objective, String paperType,
+            Integer mainNumber, Integer subNumber) {
+        ReportSubjectQuery query = new ReportSubjectQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        query.setObjective(objective);
+        query.setPaperType(paperType);
+        query.setMainNumber(mainNumber);
+        query.setSubNumber(subNumber);
+        List<ReportSubjectQuestion> list = findByQuery(query);
+        return list.isEmpty() ? null : list.get(0);
+    }
+
 }

+ 9 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/service/impl/ReportSubjectServiceImpl.java

@@ -68,4 +68,13 @@ public class ReportSubjectServiceImpl extends BaseQueryService<ReportSubject> im
         return query;
     }
 
+    @Override
+    public ReportSubject findOne(Integer examId, String subjectCode) {
+        ReportSubjectQuery query = new ReportSubjectQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        List<ReportSubject> list = findByQuery(query).getResult();
+        return list.isEmpty() ? null : list.get(0);
+    }
+
 }

+ 21 - 9
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/ReportContext.java

@@ -20,6 +20,7 @@ import cn.com.qmth.stmms.biz.report.utils.module.SubjectClassGroupModule;
 import cn.com.qmth.stmms.biz.report.utils.module.SubjectClassModule;
 import cn.com.qmth.stmms.biz.report.utils.module.SubjectClassQuestionLevelModule;
 import cn.com.qmth.stmms.biz.report.utils.module.SubjectClassQuestionModule;
+import cn.com.qmth.stmms.biz.report.utils.module.SubjectClassRangeModule;
 import cn.com.qmth.stmms.biz.report.utils.module.SubjectCollegeModule;
 import cn.com.qmth.stmms.biz.report.utils.module.SubjectGroupModule;
 import cn.com.qmth.stmms.biz.report.utils.module.SubjectModule;
@@ -49,14 +50,22 @@ public class ReportContext {
     public ReportContext(Exam exam) {
         this.exam = exam;
         this.modules = new LinkedList<Module>();
-
-        this.modules.add(new SubjectRangeModule(this));
+        this.subjectMap = new HashMap<String, ExamSubject>();
+        this.questionMap = new HashMap<String, ExamQuestion>();
+        this.groupMap = new HashMap<String, ExamQuestion>();
+        //以下modules创建有顺序
+        this.sasConfigItem = SpringContextHolder.getBean(SasConfigItem.class);
         this.modules.add(new SubjectModule(this));
         this.modules.add(new SubjectClassModule(this));
+        this.modules.add(new SubjectRangeModule(this));
+        this.modules.add(new SubjectClassRangeModule(this));
+
         this.modules.add(new SubjectCollegeModule(this));
         this.modules.add(new SubjectTeacherModule(this));
         this.modules.add(new SubjectTeacherClassModule(this));
-        this.modules.add(new SubjectQuestionOptionModule(this));
+
+        this.modules.add(new SubjectGroupModule(this));
+        this.modules.add(new SubjectClassGroupModule(this));
 
         SubjectQuestionModule qm = new SubjectQuestionModule(this);
         this.modules.add(qm);
@@ -66,13 +75,8 @@ public class ReportContext {
         this.modules.add(cqm);
         this.modules.add(new SubjectClassQuestionLevelModule(this, cqm));
 
-        this.modules.add(new SubjectGroupModule(this));
-        this.modules.add(new SubjectClassGroupModule(this));
+        this.modules.add(new SubjectQuestionOptionModule(this));
 
-        this.subjectMap = new HashMap<String, ExamSubject>();
-        this.questionMap = new HashMap<String, ExamQuestion>();
-        this.groupMap = new HashMap<String, ExamQuestion>();
-        this.sasConfigItem = SpringContextHolder.getBean(SasConfigItem.class);
     }
 
     public void process(ExamStudent student) {
@@ -185,4 +189,12 @@ public class ReportContext {
         levels[3] = new LevelRange(null, null, sasConfigItem.getDiscriminationBadValue(), null);
         return levels;
     }
+
+    public Double getHighValueConfig() {
+        return sasConfigItem.getHighValue();
+    }
+
+    public Double getLowValueConfig() {
+        return sasConfigItem.getHighValue();
+    }
 }

+ 84 - 6
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectClassQuestionLevelModule.java

@@ -1,19 +1,28 @@
 package cn.com.qmth.stmms.biz.report.utils.module;
 
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import net.sf.json.JSONObject;
+
 import org.apache.commons.lang.StringUtils;
 
 import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.report.model.ReportSubjectClass;
+import cn.com.qmth.stmms.biz.report.model.ReportSubjectClassGroup;
+import cn.com.qmth.stmms.biz.report.service.ReportSubjectClassGroupService;
+import cn.com.qmth.stmms.biz.report.service.ReportSubjectClassService;
 import cn.com.qmth.stmms.biz.report.utils.Module;
 import cn.com.qmth.stmms.biz.report.utils.QuestionCalculatorProvider;
 import cn.com.qmth.stmms.biz.report.utils.ReportContext;
 import cn.com.qmth.stmms.biz.report.utils.unit.BaseCalculatorUnit;
+import cn.com.qmth.stmms.biz.report.utils.unit.QuestionCounter;
+import cn.com.qmth.stmms.biz.utils.SpringContextHolder;
 
 /**
  * 按科目+班级维度统计小题难度等级与区分度等级
@@ -27,6 +36,7 @@ public class SubjectClassQuestionLevelModule extends SubjectQuestionLevelModule
 
     public SubjectClassQuestionLevelModule(ReportContext context, QuestionCalculatorProvider provider) {
         super(context, provider);
+        classMap = new HashMap<String, Set<String>>();
     }
 
     @Override
@@ -36,16 +46,17 @@ public class SubjectClassQuestionLevelModule extends SubjectQuestionLevelModule
         Set<String> set = classMap.get(student.getSubjectCode());
         if (set == null) {
             set = new HashSet<>();
-            classMap.put(student.getSubjectCode(), set);
         }
         set.add(student.getClassName());
+        classMap.put(student.getSubjectCode(), set);
     }
 
     @Override
     protected void beforeSave() {
         for (Entry<String, List<ExamQuestion>> entry : questions.entrySet()) {
-            Set<String> classSet = classMap.get(entry.getKey());
-            if (classSet.isEmpty()) {
+            String[] s = entry.getKey().split("\t");
+            Set<String> classSet = classMap.get(s[0]);
+            if (null==classSet || classSet.isEmpty()) {
                 continue;
             }
             for (String className : classSet) {
@@ -77,8 +88,75 @@ public class SubjectClassQuestionLevelModule extends SubjectQuestionLevelModule
     }
 
     public void save() {
-        super.beforeSave();
-        // TODO
+        beforeSave();
+        ReportSubjectClassService classService = SpringContextHolder.getBean(ReportSubjectClassService.class);
+        ReportSubjectClassGroupService groupService = SpringContextHolder.getBean(ReportSubjectClassGroupService.class);
+        for (String key : this.difficulityLevels.keySet()) {
+            String s[] = key.split("\t");
+            String subjectCode = s[0];
+            QuestionCounter difficulityCounter = difficulityLevels.get(key);
+            QuestionCounter discriminationCounter = discriminationLevels.get(key);
+            JSONObject difficulityLevel = new JSONObject();
+            for (int i = 0; i < difficulityCounter.levelCount; i++) {
+                JSONObject value = new JSONObject();
+                value.accumulate("questionCount", difficulityCounter.totalCount[i]);
+                value.accumulate("fullScore", difficulityCounter.totalScore[i]);
+                String level = null;
+                switch (i) {
+                case 0:
+                    level = "high";
+                    break;
+                case 1:
+                    level = "middle";
+                    break;
+                case 2:
+                    level = "low";
+                    break;
+                }
+                if (level != null) {
+                    difficulityLevel.accumulate(level, value);
+                }
+            }
+            JSONObject discriminationLevel = new JSONObject();
+            for (int i = 0; i < discriminationCounter.levelCount; i++) {
+                JSONObject value = new JSONObject();
+                value.accumulate("questionCount", discriminationCounter.totalCount[i]);
+                value.accumulate("fullScore", discriminationCounter.totalScore[i]);
+                String level = null;
+                switch (i) {
+                case 0:
+                    level = "excellent";
+                    break;
+                case 1:
+                    level = "good";
+                    break;
+                case 2:
+                    level = "general";
+                    break;
+                case 3:
+                    level = "bad";
+                    break;
+                }
+                if (level != null) {
+                    discriminationLevel.accumulate(level, value);
+                }
+            }
+            if (s.length == 3) {
+                String className = s[2];
+                ReportSubjectClass r = classService.findOne(context.getExamId(),subjectCode,className);
+                r.setDifficulityLevel(difficulityLevel.toString());
+                r.setDiscriminationLevel(discriminationLevel.toString());
+                classService.save(r);
+            }
+            if (s.length == 5) {
+                String className = s[1];
+                Boolean objective = Boolean.parseBoolean(s[2]);
+                Integer mainNumber = Integer.parseInt(s[4]);
+                ReportSubjectClassGroup r = groupService.findOne(context.getExamId(),subjectCode,className,objective,mainNumber);
+                r.setDifficulityLevel(difficulityLevel.toString());
+                r.setDiscriminationLevel(discriminationLevel.toString());
+                groupService.save(r);
+            }
+        }
     }
-
 }

+ 73 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectClassRangeModule.java

@@ -0,0 +1,73 @@
+package cn.com.qmth.stmms.biz.report.utils.module;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.json.JSONObject;
+
+import org.apache.commons.lang.StringUtils;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.report.model.ReportSubjectClass;
+import cn.com.qmth.stmms.biz.report.service.ReportSubjectClassService;
+import cn.com.qmth.stmms.biz.report.utils.Module;
+import cn.com.qmth.stmms.biz.report.utils.ReportContext;
+import cn.com.qmth.stmms.biz.report.utils.unit.RangeCounter;
+import cn.com.qmth.stmms.biz.utils.SpringContextHolder;
+
+public class SubjectClassRangeModule implements Module {
+
+    private Map<String, RangeCounter> counters;
+
+    private ReportContext context;
+
+    public SubjectClassRangeModule(ReportContext context) {
+        this.counters = new HashMap<String, RangeCounter>();
+        this.context = context;
+    }
+
+    public void process(ExamStudent student) {
+        if (student.isUpload() && !student.isAbsent() && !student.isBreach() && student.getSubject() != null) {
+            findCounter(getKey(student)).process(student.getTotalScore());
+        }
+    }
+
+    public String getKey(ExamStudent student) {
+        return student.getSubjectCode() + "\t" + StringUtils.trimToEmpty(student.getClassName());
+    }
+
+    public void save() {
+        ReportSubjectClassService service = SpringContextHolder.getBean(ReportSubjectClassService.class);
+        for (String key : this.counters.keySet()) {
+            RangeCounter counter = counters.get(key);
+            String s[] = key.split("\t");
+            String subjectCode = s[0];
+            String className = s[1];
+            ReportSubjectClass r = service.findOne(this.context.getExamId(), subjectCode, className);
+            
+            JSONObject rangeLevel = new JSONObject();
+            rangeLevel.accumulate("highScore", counter.countGeAndLt(100 - context.getHighValueConfig(), null));
+            rangeLevel.accumulate("lowScore", counter.countGeAndLt(null, context.getLowValueConfig()));
+            r.setRangeLevel(rangeLevel.toString());
+            
+            JSONObject scoreRange = new JSONObject();
+            for (int i = 0; i <= 100; i++) {
+                scoreRange.accumulate(String.valueOf(i), counter.countGeAndLt((double) i, (double) (i + 1)));
+            }
+            r.setScoreRange(scoreRange.toString());
+            service.save(r);
+        }
+
+    }
+
+    private RangeCounter findCounter(String key) {
+        RangeCounter counter = counters.get(key);
+        if (counter == null) {
+            counter = new RangeCounter();
+            counter.interval = context.getRangeInterval();
+            counters.put(key, counter);
+        }
+        return counter;
+    }
+
+}

+ 74 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectQuestionLevelModule.java

@@ -6,16 +6,23 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import net.sf.json.JSONObject;
+
 import org.apache.commons.lang.StringUtils;
 
 import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.report.model.ReportSubject;
+import cn.com.qmth.stmms.biz.report.model.ReportSubjectGroup;
+import cn.com.qmth.stmms.biz.report.service.ReportSubjectGroupService;
+import cn.com.qmth.stmms.biz.report.service.ReportSubjectService;
 import cn.com.qmth.stmms.biz.report.utils.Module;
 import cn.com.qmth.stmms.biz.report.utils.QuestionCalculatorProvider;
 import cn.com.qmth.stmms.biz.report.utils.ReportContext;
 import cn.com.qmth.stmms.biz.report.utils.unit.BaseCalculatorUnit;
 import cn.com.qmth.stmms.biz.report.utils.unit.LevelRange;
 import cn.com.qmth.stmms.biz.report.utils.unit.QuestionCounter;
+import cn.com.qmth.stmms.biz.utils.SpringContextHolder;
 
 /**
  * 按科目统计全样本小题难度等级与区分度等级
@@ -60,7 +67,73 @@ public class SubjectQuestionLevelModule implements Module {
     @Override
     public void save() {
         beforeSave();
-        // TODO 补充保存到数据库逻辑
+        ReportSubjectService subjectService = SpringContextHolder.getBean(ReportSubjectService.class);
+        ReportSubjectGroupService groupService = SpringContextHolder.getBean(ReportSubjectGroupService.class);
+        for (String key : this.difficulityLevels.keySet()) {
+            String s[] = key.split("\t");
+            String subjectCode = s[0];
+            QuestionCounter difficulityCounter = difficulityLevels.get(key);
+            QuestionCounter discriminationCounter = discriminationLevels.get(key);
+            JSONObject difficulityLevel = new JSONObject();
+            for (int i = 0; i < difficulityCounter.levelCount; i++) {
+                JSONObject value = new JSONObject();
+                value.accumulate("questionCount", difficulityCounter.totalCount[i]);
+                value.accumulate("fullScore", difficulityCounter.totalScore[i]);
+                String level = null;
+                switch (i) {
+                case 0:
+                    level = "high";
+                    break;
+                case 1:
+                    level = "middle";
+                    break;
+                case 2:
+                    level = "low";
+                    break;
+                }
+                if (level != null) {
+                    difficulityLevel.accumulate(level, value);
+                }
+            }
+            JSONObject discriminationLevel = new JSONObject();
+            for (int i = 0; i < discriminationCounter.levelCount; i++) {
+                JSONObject value = new JSONObject();
+                value.accumulate("questionCount", discriminationCounter.totalCount[i]);
+                value.accumulate("fullScore", discriminationCounter.totalScore[i]);
+                String level = null;
+                switch (i) {
+                case 0:
+                    level = "excellent";
+                    break;
+                case 1:
+                    level = "good";
+                    break;
+                case 2:
+                    level = "general";
+                    break;
+                case 3:
+                    level = "bad";
+                    break;
+                }
+                if (level != null) {
+                    discriminationLevel.accumulate(level, value);
+                }
+            }
+            if (s.length == 1 || s.length == 2) {
+                ReportSubject r = subjectService.findOne(context.getExamId(), subjectCode);
+                r.setDifficulityLevel(difficulityLevel.toString());
+                r.setDiscriminationLevel(discriminationLevel.toString());
+                subjectService.save(r);
+            }
+            if (s.length == 4) {
+                Boolean objective = Boolean.parseBoolean(s[1]);
+                Integer mainNumber = Integer.parseInt(s[3]);
+                ReportSubjectGroup r = groupService.findOne(context.getExamId(), subjectCode, objective, mainNumber);
+                r.setDifficulityLevel(difficulityLevel.toString());
+                r.setDiscriminationLevel(discriminationLevel.toString());
+                groupService.save(r);
+            }
+        }
     }
 
     protected void beforeSave() {

+ 38 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectQuestionOptionModule.java

@@ -3,14 +3,22 @@ package cn.com.qmth.stmms.biz.report.utils.module;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+
+import net.sf.json.JSONObject;
 
 import org.apache.commons.lang.StringUtils;
 
 import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.report.model.ReportSubject;
+import cn.com.qmth.stmms.biz.report.model.ReportSubjectQuestion;
+import cn.com.qmth.stmms.biz.report.service.ReportSubjectQuestionService;
+import cn.com.qmth.stmms.biz.report.service.ReportSubjectService;
 import cn.com.qmth.stmms.biz.report.utils.Module;
 import cn.com.qmth.stmms.biz.report.utils.ReportContext;
 import cn.com.qmth.stmms.biz.report.utils.unit.OptionCounter;
+import cn.com.qmth.stmms.biz.utils.SpringContextHolder;
 
 /**
  * 按科目统计全样本小题选项指标
@@ -24,9 +32,12 @@ public class SubjectQuestionOptionModule implements Module {
 
     private ReportContext context;
 
+    private Map<String, Set<String>> optionMap;
+
     public SubjectQuestionOptionModule(ReportContext context) {
         this.counters = new HashMap<String, OptionCounter>();
         this.context = context;
+        this.optionMap = new HashMap<String, Set<String>>();
     }
 
     public void process(ExamStudent student) {
@@ -61,7 +72,33 @@ public class SubjectQuestionOptionModule implements Module {
     }
 
     public void save() {
-        // TODO 需要补充选项分析结果保存
+        ReportSubjectQuestionService questionService = SpringContextHolder.getBean(ReportSubjectQuestionService.class);
+        ReportSubjectService subjectService = SpringContextHolder.getBean(ReportSubjectService.class);
+        for (String key : this.counters.keySet()) {
+            String s[] = key.split("\t");
+            if (s.length > 4) {
+                String subjectCode = s[0];
+                String paperType = StringUtils.trimToNull(s[2]);
+                Integer mainNumber = Integer.parseInt(s[3]);
+                Integer subNumber = Integer.parseInt(s[4]);
+                OptionCounter optionCounter = this.counters.get(key);
+                JSONObject options = new JSONObject();
+                for (String option : optionCounter.getCounter().keySet()) {
+                    options.accumulate(option, optionCounter.getCounter().get(option));
+                }
+                ReportSubjectQuestion r = questionService.findOne(this.context.getExamId(), subjectCode, true,
+                        paperType, mainNumber, subNumber);
+                r.setOption(options.toString());
+                questionService.save(r);
+                optionMap.put(subjectCode, optionCounter.getCounter().keySet());
+            }
+        }
+        for (String subjectCode : optionMap.keySet()) {
+            ReportSubject r = subjectService.findOne(this.context.getExamId(), subjectCode);
+            String options = optionMap.get(subjectCode).toString();
+            r.setOptions(options);
+            subjectService.save(r);
+        }
     }
 
     private OptionCounter findCounter(String key, ExamQuestion question) {

+ 17 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectRangeModule.java

@@ -3,9 +3,12 @@ package cn.com.qmth.stmms.biz.report.utils.module;
 import java.util.HashMap;
 import java.util.Map;
 
+import net.sf.json.JSONObject;
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.report.model.ReportSubject;
 import cn.com.qmth.stmms.biz.report.model.ReportSubjectRange;
 import cn.com.qmth.stmms.biz.report.service.ReportSubjectRangeService;
+import cn.com.qmth.stmms.biz.report.service.ReportSubjectService;
 import cn.com.qmth.stmms.biz.report.utils.Module;
 import cn.com.qmth.stmms.biz.report.utils.ReportContext;
 import cn.com.qmth.stmms.biz.report.utils.unit.RangeCounter;
@@ -59,6 +62,20 @@ public class SubjectRangeModule implements Module {
             subjectRange.setPercent_lt60(counter.countGeAndLt(0d, 60d) * 1.0 / counter.totalCount);
             subjectRange.setPercent_mte60(counter.countGeAndLt(60d, null) * 1.0 / counter.totalCount);
             service.save(subjectRange);
+
+            ReportSubjectService subjectService = SpringContextHolder.getBean(ReportSubjectService.class);
+            ReportSubject subject = subjectService.findOne(this.context.getExamId(), subjectCode);
+            JSONObject rangeLevel = new JSONObject();
+            rangeLevel.accumulate("highScore", counter.countGeAndLt(100 - context.getHighValueConfig(), null));
+            rangeLevel.accumulate("lowScore", counter.countGeAndLt(null, context.getLowValueConfig()));
+            subject.setRangeLevel(rangeLevel.toString());
+
+            JSONObject scoreRange = new JSONObject();
+            for (int i = 0; i <= 100; i++) {
+                scoreRange.accumulate(String.valueOf(i), counter.countGeAndLt((double) i, (double) (i + 1)));
+            }
+            subject.setScoreRange(scoreRange.toString());
+            subjectService.save(subject);
         }
 
     }

+ 67 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/dto/ExamStudentDTO.java

@@ -1,8 +1,11 @@
 package cn.com.qmth.stmms.admin.dto;
 
+import java.util.List;
+
 import org.apache.commons.lang.StringUtils;
 
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.utils.ScoreItem;
 import cn.com.qmth.stmms.common.annotation.ExcelField;
 
 public class ExamStudentDTO {
@@ -46,6 +49,19 @@ public class ExamStudentDTO {
     @ExcelField(title = "备注", align = 2, sort = 130)
     private String remark;
 
+    @ExcelField(title = "班级", align = 2, sort = 140)
+    private String className;
+
+    @ExcelField(title = "学院", align = 2, sort = 150)
+    private String college;
+
+    @ExcelField(title = "任课老师", align = 2, sort = 160)
+    private String teacher;
+
+    private List<ScoreItem> objectiveList;
+    
+    private List<ScoreItem> subjectiveList;
+
     public ExamStudentDTO(ExamStudent student) {
         setCampusName(student.getCampusName());
         setSubjectCode(student.getSubjectCode());
@@ -60,6 +76,11 @@ public class ExamStudentDTO {
         setSubjectiveScoreList(StringUtils.trimToEmpty(student.getSubjectiveScoreList()));
         setTotalScore(student.getTotalScore());
         setRemark(StringUtils.trimToEmpty(student.getRemark()));
+        setClassName(student.getClassName());
+        setCollege(student.getCollege());
+        setTeacher(student.getTeacher());
+        setObjectiveList(student.getScoreList(true));
+        setSubjectiveList(student.getScoreList(false));
     }
 
     public String getCampusName() {
@@ -165,4 +186,50 @@ public class ExamStudentDTO {
     public void setSubjectCategory(String subjectCategory) {
         this.subjectCategory = subjectCategory;
     }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getCollege() {
+        return college;
+    }
+
+    public void setCollege(String college) {
+        this.college = college;
+    }
+
+    public String getTeacher() {
+        return teacher;
+    }
+
+    public void setTeacher(String teacher) {
+        this.teacher = teacher;
+    }
+
+    
+    public List<ScoreItem> getObjectiveList() {
+        return objectiveList;
+    }
+
+    
+    public void setObjectiveList(List<ScoreItem> objectiveList) {
+        this.objectiveList = objectiveList;
+    }
+
+    
+    public List<ScoreItem> getSubjectiveList() {
+        return subjectiveList;
+    }
+
+    
+    public void setSubjectiveList(List<ScoreItem> subjectiveList) {
+        this.subjectiveList = subjectiveList;
+    }
+
+
 }

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

@@ -1,12 +1,15 @@
 package cn.com.qmth.stmms.admin.exam;
 
 import java.text.DecimalFormat;
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import net.sf.json.JSONObject;
+
 import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -20,8 +23,8 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
 import cn.com.qmth.stmms.admin.dto.ExamStudentDTO;
 import cn.com.qmth.stmms.admin.dto.ScoreEditDTO;
-import cn.com.qmth.stmms.admin.dto.ScoreExportDTO;
 import cn.com.qmth.stmms.admin.thread.ScoreCalculateThread;
+import cn.com.qmth.stmms.admin.utils.ExportStudentExcel;
 import cn.com.qmth.stmms.biz.exam.model.Exam;
 import cn.com.qmth.stmms.biz.exam.model.ExamPackage;
 import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
@@ -47,7 +50,6 @@ import cn.com.qmth.stmms.common.enums.Role;
 import cn.com.qmth.stmms.common.utils.ExportExcel;
 import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
 import cn.com.qmth.stmms.common.utils.RequestUtils;
-import net.sf.json.JSONObject;
 
 @Controller
 @RequestMapping("/admin/exam/score")
@@ -118,9 +120,8 @@ public class ScoreController extends BaseExamController {
             buildPackageUrl(student);
             buildAnswerUrl(student);
         }
-        String exportMessage = StringUtils.isNotBlank(query.getSubjectCode())
-                ? enableExport(examId, query.getSubjectCode())
-                : enableExport(examId);
+        String exportMessage = StringUtils.isNotBlank(query.getSubjectCode()) ? enableExport(examId,
+                query.getSubjectCode()) : enableExport(examId);
         if (exportMessage != null) {
             view.addObject("exportMessage", exportMessage);
             view.addObject("enableExport", false);
@@ -197,8 +198,8 @@ public class ScoreController extends BaseExamController {
     public ModelAndView calculate(HttpServletRequest request) {
         int examId = getSessionExamId(request);
         if (lockService.trylock(LockType.SCORE_CALCULATE, examId)) {
-            ScoreCalculateThread thread = new ScoreCalculateThread(examId, lockService, studentService, questionService,
-                    markService, reportService, examService, subjectService, groupService);
+            ScoreCalculateThread thread = new ScoreCalculateThread(examId, lockService, studentService,
+                    questionService, markService, reportService, examService, subjectService, groupService);
             taskExecutor.submit(thread);
         }
         return new ModelAndView("redirect:/admin/exam/score");
@@ -209,17 +210,15 @@ public class ScoreController extends BaseExamController {
             RedirectAttributes redirectAttributes) {
         WebUser wu = RequestUtils.getWebUser(request);
         int examId = getSessionExamId(request);
-        String exportMessage = StringUtils.isNotBlank(query.getSubjectCode())
-                ? enableExport(examId, query.getSubjectCode())
-                : enableExport(examId);
-        if (exportMessage == null && StringUtils.isNotBlank(query.getStudentCode())) {
-            exportMessage = enableExport(examId, query.getStudentCode());
+        String exportMessage = StringUtils.isNotBlank(query.getSubjectCode()) ? enableExport(examId,
+                query.getSubjectCode()) : enableExport(examId);
+        if (exportMessage == null && StringUtils.isNotBlank(query.getSubjectCode())) {
+            exportMessage = enableExport(examId, query.getSubjectCode());
         }
         if (exportMessage != null) {
             addMessage(redirectAttributes, "评卷未结束不能导出成绩 " + exportMessage);
             return "redirect:/admin/exam/score";
         }
-        String subjectCode = RequestUtils.getSession(request).getParameter("subjectCode");
         query.setExamId(examId);
         query.setPageNumber(1);
         query.setPageSize(Integer.MAX_VALUE);
@@ -227,20 +226,6 @@ public class ScoreController extends BaseExamController {
         query = studentService.findByQuery(query);
         String fileName = "成绩单.xlsx";
         try {
-            if (subjectCode != null) {
-                fileName = subjectService.find(examId, subjectCode).getName() + "-机阅考试成绩表";
-                List<ScoreExportDTO> list = new LinkedList<ScoreExportDTO>();
-                for (ExamStudent student : query.getResult()) {
-                    if (student.isBreach() || student.isAbsent()) {
-                        student.setObjectiveScore(0d);
-                        student.setSubjectiveScore(0d);
-                    }
-                    list.add(new ScoreExportDTO(student));
-                }
-                new ExportExcel(subjectCode + "-" + subjectService.find(examId, subjectCode).getName(),
-                        ScoreExportDTO.class).setDataList(list).write(response, fileName + ".xlsx").dispose();
-                return null;
-            }
             List<ExamStudentDTO> list = new LinkedList<ExamStudentDTO>();
             for (ExamStudent student : query.getResult()) {
                 if (student.isBreach() || student.isAbsent()) {
@@ -249,6 +234,13 @@ public class ScoreController extends BaseExamController {
                 }
                 list.add(new ExamStudentDTO(student));
             }
+            if (StringUtils.isNotBlank(query.getSubjectCode()) && !query.getResult().isEmpty()) {
+                List<String> headerList = getOptionHeader(examId, query.getSubjectCode(),query.getResult().get(0).getPaperType());
+                ExportStudentExcel excel = new ExportStudentExcel("成绩单", headerList, ExamStudentDTO.class);
+                excel.setDataList(list,true);
+                excel.write(response, fileName).dispose();
+                return null;
+            }
             new ExportExcel("成绩单", ExamStudentDTO.class).setDataList(list).write(response, fileName).dispose();
             return null;
         } catch (Exception e) {
@@ -257,6 +249,25 @@ public class ScoreController extends BaseExamController {
         }
     }
 
+    private List<String> getOptionHeader(int examId, String subjectCode, String paerType) {
+        List<String> headerList = new ArrayList<String>();
+        List<ExamQuestion> oQuestions = questionService.findByExamAndSubjectAndObjectiveAndPaperType(examId,
+                subjectCode, true, paerType);
+        List<ExamQuestion> sQestions = questionService.findByExamAndSubjectAndObjective(examId, subjectCode, false);
+        for (ExamQuestion examQuestion : oQuestions) {
+            headerList.add(getTitle(examQuestion) + "选项");
+            headerList.add(getTitle(examQuestion) + "得分");
+        }
+        for (ExamQuestion examQuestion : sQestions) {
+            headerList.add(getTitle(examQuestion));
+        }
+        return headerList;
+    }
+
+    private String getTitle(ExamQuestion examQuestion) {
+        return examQuestion.getMainTitle() + " " + examQuestion.getMainNumber()+"-"+examQuestion.getSubNumber();
+    }
+
     @RequestMapping("/enableExport")
     @ResponseBody
     public JSONObject query(HttpServletRequest request, @RequestParam(required = false) String subjectCode) {

+ 557 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/utils/ExportStudentExcel.java

@@ -0,0 +1,557 @@
+package cn.com.qmth.stmms.admin.utils;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Comment;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.stmms.admin.dto.ExamStudentDTO;
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.utils.ScoreItem;
+import cn.com.qmth.stmms.common.annotation.ExcelField;
+import cn.com.qmth.stmms.common.utils.Encodes;
+import cn.com.qmth.stmms.common.utils.Reflections;
+
+import com.google.common.collect.Lists;
+
+public class ExportStudentExcel {
+
+    private static Logger log = LoggerFactory.getLogger(ExportStudentExcel.class);
+
+    /**
+     * 工作薄对象
+     */
+    private SXSSFWorkbook wb;
+
+    /**
+     * 工作表对象
+     */
+    private Sheet sheet;
+
+    /**
+     * 样式列表
+     */
+    private Map<String, CellStyle> styles;
+
+    /**
+     * 当前行号
+     */
+    private int rownum;
+
+    /**
+     * 注解列表(Object[]{ ExcelField, Field/Method })
+     */
+    private List<Object[]> annotationList = Lists.newArrayList();
+
+    /**
+     * 构造函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param cls
+     *            实体对象,通过annotation.ExportField获取标题
+     */
+    public ExportStudentExcel(String title, List<String> headerList, Class<?> cls) {
+        this(title, cls, 1, headerList);
+    }
+
+    /**
+     * 构造函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param cls
+     *            实体对象,通过annotation.ExportField获取标题
+     * @param type
+     *            导出类型(1:导出数据;2:导出模板)
+     * @param groups
+     *            导入分组
+     */
+    public ExportStudentExcel(String title, Class<?> cls, int type, List<String> addHeaderList, int... groups) {
+        // Get annotation field
+        Field[] fs = cls.getDeclaredFields();
+        for (Field f : fs) {
+            ExcelField ef = f.getAnnotation(ExcelField.class);
+            if (ef != null && (ef.type() == 0 || ef.type() == type)) {
+                if (groups != null && groups.length > 0) {
+                    boolean inGroup = false;
+                    for (int g : groups) {
+                        if (inGroup) {
+                            break;
+                        }
+                        for (int efg : ef.groups()) {
+                            if (g == efg) {
+                                inGroup = true;
+                                annotationList.add(new Object[] { ef, f });
+                                break;
+                            }
+                        }
+                    }
+                } else {
+                    annotationList.add(new Object[] { ef, f });
+                }
+            }
+        }
+        // Get annotation method
+        Method[] ms = cls.getDeclaredMethods();
+        for (Method m : ms) {
+            ExcelField ef = m.getAnnotation(ExcelField.class);
+            if (ef != null && (ef.type() == 0 || ef.type() == type)) {
+                if (groups != null && groups.length > 0) {
+                    boolean inGroup = false;
+                    for (int g : groups) {
+                        if (inGroup) {
+                            break;
+                        }
+                        for (int efg : ef.groups()) {
+                            if (g == efg) {
+                                inGroup = true;
+                                annotationList.add(new Object[] { ef, m });
+                                break;
+                            }
+                        }
+                    }
+                } else {
+                    annotationList.add(new Object[] { ef, m });
+                }
+            }
+        }
+        // Field sorting
+        Collections.sort(annotationList, new Comparator<Object[]>() {
+
+            public int compare(Object[] o1, Object[] o2) {
+                return new Integer(((ExcelField) o1[0]).sort()).compareTo(new Integer(((ExcelField) o2[0]).sort()));
+            };
+        });
+        // Initialize
+        List<String> headerList = Lists.newArrayList();
+        for (Object[] os : annotationList) {
+            String t = ((ExcelField) os[0]).title();
+            // 如果是导出,则去掉注释
+            if (type == 1) {
+                String[] ss = StringUtils.split(t, "**", 2);
+                if (ss.length == 2) {
+                    t = ss[0];
+                }
+            }
+            headerList.add(t);
+        }
+        headerList.addAll(addHeaderList);
+        initialize(title, headerList);
+    }
+
+    /**
+     * 构造函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param headers
+     *            表头数组
+     */
+    public ExportStudentExcel(String title, String[] headers) {
+        initialize(title, Lists.newArrayList(headers));
+    }
+
+    /**
+     * 构造函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param headerList
+     *            表头列表
+     */
+    public ExportStudentExcel(String title, List<String> headerList) {
+        initialize(title, headerList);
+    }
+
+    /**
+     * 初始化函数
+     * 
+     * @param title
+     *            表格标题,传“空值”,表示无标题
+     * @param headerList
+     *            表头列表
+     */
+    public void initialize(String title, List<String> headerList) {
+        this.wb = new SXSSFWorkbook(500);
+        this.sheet = wb.createSheet("Export");
+        this.styles = createStyles(wb);
+        // Create title
+        if (StringUtils.isNotBlank(title)) {
+            Row titleRow = sheet.createRow(rownum++);
+            titleRow.setHeightInPoints(30);
+            Cell titleCell = titleRow.createCell(0);
+            titleCell.setCellStyle(styles.get("title"));
+            titleCell.setCellValue(title);
+            sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(),
+                    titleRow.getRowNum(), headerList.size() - 1));
+        }
+        // Create header
+        if (headerList == null) {
+            throw new RuntimeException("headerList not null!");
+        }
+        Row headerRow = sheet.createRow(rownum++);
+        headerRow.setHeightInPoints(16);
+        for (int i = 0; i < headerList.size(); i++) {
+            Cell cell = headerRow.createCell(i);
+            cell.setCellStyle(styles.get("header"));
+            String[] ss = StringUtils.split(headerList.get(i), "**", 2);
+            if (ss.length == 2) {
+                cell.setCellValue(ss[0]);
+                Comment comment = this.sheet.createDrawingPatriarch().createCellComment(
+                        new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6));
+                comment.setString(new XSSFRichTextString(ss[1]));
+                cell.setCellComment(comment);
+            } else {
+                cell.setCellValue(headerList.get(i));
+            }
+            sheet.autoSizeColumn(i);
+        }
+        for (int i = 0; i < headerList.size(); i++) {
+            int colWidth = sheet.getColumnWidth(i) * 2;
+            sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth);
+        }
+        log.debug("Initialize success.");
+    }
+
+    /**
+     * 创建表格样式
+     * 
+     * @param wb
+     *            工作薄对象
+     * @return 样式列表
+     */
+    private Map<String, CellStyle> createStyles(Workbook wb) {
+        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
+
+        CellStyle style = wb.createCellStyle();
+        style.setAlignment(CellStyle.ALIGN_CENTER);
+        style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
+        Font titleFont = wb.createFont();
+        titleFont.setFontName("Arial");
+        titleFont.setFontHeightInPoints((short) 16);
+        titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
+        style.setFont(titleFont);
+        styles.put("title", style);
+
+        style = wb.createCellStyle();
+        style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
+        style.setBorderRight(CellStyle.BORDER_THIN);
+        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderLeft(CellStyle.BORDER_THIN);
+        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderTop(CellStyle.BORDER_THIN);
+        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderBottom(CellStyle.BORDER_THIN);
+        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        Font dataFont = wb.createFont();
+        dataFont.setFontName("Arial");
+        dataFont.setFontHeightInPoints((short) 10);
+        style.setFont(dataFont);
+        styles.put("data", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        style.setAlignment(CellStyle.ALIGN_LEFT);
+        styles.put("data1", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        style.setAlignment(CellStyle.ALIGN_CENTER);
+        styles.put("data2", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        style.setAlignment(CellStyle.ALIGN_RIGHT);
+        styles.put("data3", style);
+
+        style = wb.createCellStyle();
+        style.cloneStyleFrom(styles.get("data"));
+        // style.setWrapText(true);
+        style.setAlignment(CellStyle.ALIGN_CENTER);
+        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setFillPattern(CellStyle.SOLID_FOREGROUND);
+        Font headerFont = wb.createFont();
+        headerFont.setFontName("Arial");
+        headerFont.setFontHeightInPoints((short) 10);
+        headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
+        headerFont.setColor(IndexedColors.WHITE.getIndex());
+        style.setFont(headerFont);
+        styles.put("header", style);
+
+        return styles;
+    }
+
+    /**
+     * 添加一行
+     * 
+     * @return 行对象
+     */
+    public Row addRow() {
+        return sheet.createRow(rownum++);
+    }
+
+    /**
+     * 添加一个单元格
+     * 
+     * @param row
+     *            添加的行
+     * @param column
+     *            添加列号
+     * @param val
+     *            添加值
+     * @return 单元格对象
+     */
+    public Cell addCell(Row row, int column, Object val) {
+        return this.addCell(row, column, val, 0, Class.class);
+    }
+
+    /**
+     * 添加一个单元格
+     * 
+     * @param row
+     *            添加的行
+     * @param column
+     *            添加列号
+     * @param val
+     *            添加值
+     * @param align
+     *            对齐方式(1:靠左;2:居中;3:靠右)
+     * @return 单元格对象
+     */
+    public Cell addCell(Row row, int column, Object val, int align, Class<?> fieldType) {
+        Cell cell = row.createCell(column);
+        CellStyle style = styles.get("data" + (align >= 1 && align <= 3 ? align : ""));
+        try {
+            if (val == null) {
+                cell.setCellValue("");
+            } else if (val instanceof String) {
+                cell.setCellValue((String) val);
+            } else if (val instanceof Integer) {
+                cell.setCellValue((Integer) val);
+            } else if (val instanceof Long) {
+                cell.setCellValue((Long) val);
+            } else if (val instanceof Double) {
+                cell.setCellValue((Double) val);
+            } else if (val instanceof Float) {
+                cell.setCellValue((Float) val);
+            } else if (val instanceof Date) {
+                DataFormat format = wb.createDataFormat();
+                style.setDataFormat(format.getFormat("yyyy-MM-dd"));
+                cell.setCellValue((Date) val);
+            } else {
+                if (fieldType != Class.class) {
+                    cell.setCellValue((String) fieldType.getMethod("setValue", Object.class).invoke(null, val));
+                } else {
+                    cell.setCellValue((String) Class
+                            .forName(
+                                    this.getClass()
+                                            .getName()
+                                            .replaceAll(this.getClass().getSimpleName(),
+                                                    "fieldtype." + val.getClass().getSimpleName() + "Type"))
+                            .getMethod("setValue", Object.class).invoke(null, val));
+                }
+            }
+        } catch (Exception ex) {
+            log.info("Set cell value [" + row.getRowNum() + "," + column + "] error: " + ex.toString());
+            cell.setCellValue(val.toString());
+        }
+        cell.setCellStyle(style);
+        return cell;
+    }
+
+    /**
+     * 添加数据(通过annotation.ExportField添加数据)
+     * 
+     * @return list 数据列表
+     */
+    public <E> ExportStudentExcel setDataList(List<ExamStudentDTO> list,boolean addOptions) {
+        for (ExamStudentDTO e : list) {
+            int colunm = 0;
+            Row row = this.addRow();
+            StringBuilder sb = new StringBuilder();
+            for (Object[] os : annotationList) {
+                ExcelField ef = (ExcelField) os[0];
+                Object val = null;
+                // Get entity value
+                try {
+                    if (StringUtils.isNotBlank(ef.value())) {
+                        val = Reflections.invokeGetter(e, ef.value());
+                    } else {
+                        if (os[1] instanceof Field) {
+                            val = Reflections.invokeGetter(e, ((Field) os[1]).getName());
+                        } else if (os[1] instanceof Method) {
+                            val = Reflections.invokeMethod(e, ((Method) os[1]).getName(), new Class[] {},
+                                    new Object[] {});
+                        }
+                    }
+                    // If is dict, get dict label
+                    /*
+                     * if (StringUtils.isNotBlank(ef.dictType())){ val =
+                     * DictUtils.getDictLabel(val==null?"":val.toString(),
+                     * ef.dictType(), ""); }
+                     */
+                } catch (Exception ex) {
+                    // Failure to ignore
+                    log.info(ex.toString());
+                    val = "";
+                }
+                this.addCell(row, colunm++, val, ef.align(), ef.fieldType());
+                sb.append(val + ", ");
+            }
+            if(addOptions){
+                for (ScoreItem item : e.getObjectiveList()) {
+                    this.addCell(row, colunm++, item.getAnswer());
+                    this.addCell(row, colunm++, item.getScore());
+                }
+                for (ScoreItem item : e.getSubjectiveList()) {
+                    this.addCell(row, colunm++, item.getScore());
+                }
+            }
+            log.debug("Write success: [" + row.getRowNum() + "] " + sb.toString());
+        }
+        return this;
+    }
+
+    /**
+     * 输出数据流
+     * 
+     * @param os
+     *            输出数据流
+     */
+    public ExportStudentExcel write(OutputStream os) throws IOException {
+        wb.write(os);
+        return this;
+    }
+
+    /**
+     * 输出到客户端
+     * 
+     * @param fileName
+     *            输出文件名
+     */
+    public ExportStudentExcel write(HttpServletResponse response, String fileName) throws IOException {
+        response.reset();
+        response.setContentType("application/octet-stream; charset=utf-8");
+        response.setHeader("Content-Disposition", "attachment; filename=" + Encodes.urlEncode(fileName));
+        write(response.getOutputStream());
+        return this;
+    }
+
+    /**
+     * 输出到文件
+     * 
+     * @param fileName
+     *            输出文件名
+     */
+    public ExportStudentExcel writeFile(String name) throws FileNotFoundException, IOException {
+        FileOutputStream os = new FileOutputStream(name);
+        this.write(os);
+        return this;
+    }
+
+    /**
+     * 清理临时文件
+     */
+    public ExportStudentExcel dispose() {
+        wb.dispose();
+        return this;
+    }
+
+    // /**
+    // * 导出测试
+    // */
+    // public static void main(String[] args) throws Throwable {
+    //
+    // List<String> headerList = Lists.newArrayList();
+    // for (int i = 1; i <= 10; i++) {
+    // headerList.add("表头"+i);
+    // }
+    //
+    // List<String> dataRowList = Lists.newArrayList();
+    // for (int i = 1; i <= headerList.size(); i++) {
+    // dataRowList.add("数据"+i);
+    // }
+    //
+    // List<List<String>> dataList = Lists.newArrayList();
+    // for (int i = 1; i <=1000000; i++) {
+    // dataList.add(dataRowList);
+    // }
+    //
+    // ExportExcel ee = new ExportExcel("表格标题", headerList);
+    //
+    // for (int i = 0; i < dataList.size(); i++) {
+    // Row row = ee.addRow();
+    // for (int j = 0; j < dataList.get(i).size(); j++) {
+    // ee.addCell(row, j, dataList.get(i).get(j));
+    // }
+    // }
+    //
+    // ee.writeFile("target/export.xlsx");
+    //
+    // ee.dispose();
+    //
+    // log.debug("Export success.");
+    //
+    // }
+
+    public void setOptions(List<ExamStudentDTO> list, List<ExamQuestion> oQuestions, List<ExamQuestion> sQestions) {
+        List<String> headerList = Lists.newArrayList();
+        for (Object[] os : annotationList) {
+            String t = ((ExcelField) os[0]).title();
+            headerList.add(t);
+        }
+
+        // int column = 16;
+        // Row headerRow = sheet.getRow(500);
+        for (ExamQuestion examQuestion : oQuestions) {
+            String val = examQuestion.getMainTitle() + "." + examQuestion.getQuestionNumber();
+            headerList.add(val);
+            // addCell(headerRow, column++, val);
+            // addCell(headerRow, column++, val);
+        }
+        for (ExamQuestion examQuestion : sQestions) {
+            String val = examQuestion.getMainTitle() + "." + examQuestion.getQuestionNumber();
+            headerList.add(val);
+            // addCell(headerRow, column++, val);
+        }
+        initialize("", headerList);
+        // for (ExamStudentDTO examStudent : list) {
+        // for (ScoreItem scoreItem : examStudent.getObjectiveList()) {
+        //
+        // }
+        // for (ScoreItem scoreItem : examStudent.getSubjectiveList()) {
+        //
+        // }
+        // }
+
+    }
+
+}

+ 9 - 9
stmms-web/src/main/webapp/WEB-INF/sas.properties

@@ -1,12 +1,12 @@
 #sas config
 sas.passScore=60
 sas.excellentScore=85
-sas.discriminationExcellentScore=40
-sas.discriminationGoodScore=30
-sas.discriminationGeneralScore=20
-sas.discriminationBadScore=10
-sas.difficultyHighScore=40
-sas.difficultyMiddleScore=70
-sas.difficultyLowScore=70
-sas.highScore=27
-sas.lowScore=27
+sas.discriminationExcellentValue=40
+sas.discriminationGoodValue=30
+sas.discriminationGeneralValue=20
+sas.discriminationBadValue=10
+sas.difficultyHighValue=40
+sas.difficultyMiddleValue=70
+sas.difficultyLowValue=70
+sas.highValue=27
+sas.lowValue=27

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

@@ -233,10 +233,6 @@ function goExport(){
 	$("#searchForm").attr('action','${ctx}/admin/exam/score/export');
 	$("#searchForm").submit();
 }
-function goExportScore(){
-	$("#searchForm").attr('action','${ctx}/admin/exam/score/exportScore');
-	$("#searchForm").submit();
-}
 $('#subject-select').change(function(){
     var code = $(this).val();
     $.post('${ctx}/admin/exam/score/enableExport', {subjectCode: code}, function(result){