Explorar el Código

Merge branch 'release_1.3.9'

luoshi hace 2 años
padre
commit
5927a87b7c
Se han modificado 100 ficheros con 3750 adiciones y 570 borrados
  1. 21 11
      pom.xml
  2. 1 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/BaseQuery.java
  3. 1 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/BaseQueryService.java
  4. 40 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/AnswerArea.java
  5. 149 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/CardFile.java
  6. 168 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/CardPage.java
  7. 17 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/CardPageWrapper.java
  8. 33 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/CheckArea.java
  9. 54 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/Extension.java
  10. 27 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/FieldArea.java
  11. 66 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/FillArea.java
  12. 56 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/FillItem.java
  13. 55 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/FillLocator.java
  14. 30 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/Locator.java
  15. 46 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/MarkConfig.java
  16. 44 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/SliceConfig.java
  17. 24 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/AnswerCardDao.java
  18. 6 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/CheckStudentDao.java
  19. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamQuestionDao.java
  20. 46 14
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamStudentDao.java
  21. 29 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/InspectHistoryDao.java
  22. 8 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkerDao.java
  23. 6 4
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/SelectiveGroupDao.java
  24. 21 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/SelectiveStudentDao.java
  25. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/SubjectiveScoreDao.java
  26. 164 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/AnswerCard.java
  27. 72 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/AnswerCardPK.java
  28. 42 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Exam.java
  29. 58 4
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamQuestion.java
  30. 55 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamStudent.java
  31. 29 3
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamSubject.java
  32. 115 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/InspectHistory.java
  33. 26 16
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroup.java
  34. 11 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Marker.java
  35. 56 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/SelectiveGroup.java
  36. 84 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/SelectiveStudent.java
  37. 30 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/SubjectiveScore.java
  38. 10 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/CheckStudentSearchQuery.java
  39. 50 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/ExamStudentSearchQuery.java
  40. 9 13
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/MarkerSearchQuery.java
  41. 21 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/AnswerCardService.java
  42. 6 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/CheckStudentService.java
  43. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamQuestionService.java
  44. 24 3
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamStudentService.java
  45. 19 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/InspectHistoryService.java
  46. 13 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/InspectedService.java
  47. 5 5
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/MarkGroupService.java
  48. 7 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/MarkerService.java
  49. 10 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/SelectiveGroupService.java
  50. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/SubjectiveScoreService.java
  51. 59 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/AnswerCardServiceImpl.java
  52. 12 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/CheckStudentServiceImpl.java
  53. 74 35
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamQuestionServiceImpl.java
  54. 131 56
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamStudentServiceImpl.java
  55. 57 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/InspectHistoryServiceImpl.java
  56. 64 10
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/InspectedServiceImpl.java
  57. 11 11
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/MarkGroupServiceImpl.java
  58. 82 19
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/MarkerServiceImpl.java
  59. 82 2
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/SelectiveGroupServiceImpl.java
  60. 33 20
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/SubjectiveScoreServiceImpl.java
  61. 2 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/enums/FileType.java
  62. 1 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/enums/FormatType.java
  63. 13 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/service/FileService.java
  64. 32 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/service/impl/FileServiceImpl.java
  65. 16 7
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkLibraryDao.java
  66. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkTrackDao.java
  67. 5 14
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/ProblemHistoryDao.java
  68. 6 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/TrialLibraryDao.java
  69. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/TrialTrackDao.java
  70. 128 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkConfigItem.java
  71. 25 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkLibrary.java
  72. 5 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkResult.java
  73. 20 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkStepDTO.java
  74. 15 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkTrack.java
  75. 16 3
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/Task.java
  76. 14 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/TrackDTO.java
  77. 14 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/TrialLibrary.java
  78. 14 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/TrialTrack.java
  79. 31 21
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/query/MarkLibrarySearchQuery.java
  80. 19 9
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkLibraryServiceImpl.java
  81. 409 204
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkServiceImpl.java
  82. 28 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/TaskServiceImpl.java
  83. 5 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/TrialServiceImpl.java
  84. 3 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkLibraryService.java
  85. 6 4
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkService.java
  86. 2 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/TrialService.java
  87. 23 7
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectClass.java
  88. 30 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectCollege.java
  89. 34 15
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectTeacher.java
  90. 4 1
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectClassModule.java
  91. 4 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectCollegeModule.java
  92. 6 5
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectModule.java
  93. 1 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/utils/module/SubjectTeacherModule.java
  94. 6 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/dao/UserDao.java
  95. 62 4
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/model/User.java
  96. 10 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/service/UserService.java
  97. 222 16
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/service/impl/UserServiceImpl.java
  98. 7 7
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/OriginTag.java
  99. 20 13
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/PictureConfigTransform.java
  100. 6 6
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/PictureTag.java

+ 21 - 11
pom.xml

@@ -29,7 +29,7 @@
         <poi.version>3.9</poi.version>
         <guava.version>14.0.1</guava.version>
         <commons-lang3.version>3.1</commons-lang3.version>
-        <qmth-boot-version>1.0.2</qmth-boot-version>
+        <qmth-boot-version>1.0.3</qmth-boot-version>
     </properties>
 
     <dependencyManagement>
@@ -270,10 +270,20 @@
                 <artifactId>jackson-core-asl</artifactId>
                 <version>1.9.12</version>
             </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.core</groupId>
+                <artifactId>jackson-core</artifactId>
+                <version>2.11.3</version>
+            </dependency>
             <dependency>
                 <groupId>com.fasterxml.jackson.core</groupId>
                 <artifactId>jackson-databind</artifactId>
-                <version>2.8.8</version>
+                <version>2.11.3</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.core</groupId>
+                <artifactId>jackson-annotations</artifactId>
+                <version>2.11.3</version>
             </dependency>
             <dependency>
                 <groupId>log4j</groupId>
@@ -323,15 +333,15 @@
                 <version>3.27.0-GA</version>
             </dependency>
             <dependency>
-            	<groupId>com.qmth.boot</groupId>
-          		<artifactId>tools-device</artifactId>
-          		<version>${qmth-boot-version}</version>
-        	</dependency>
-        	<dependency>
-       			<groupId>com.qmth.boot</groupId>
-           		<artifactId>tools-common</artifactId>
-           		<version>${qmth-boot-version}</version>
-       		</dependency>
+                <groupId>com.qmth.boot</groupId>
+                <artifactId>tools-device</artifactId>
+                <version>${qmth-boot-version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.qmth.boot</groupId>
+                <artifactId>tools-common</artifactId>
+                <version>${qmth-boot-version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 

+ 1 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/BaseQuery.java

@@ -11,7 +11,7 @@ public class BaseQuery<T> implements Pageable {
 
     private int pageNumber = 1;
 
-    private int pageSize = 10;
+    private int pageSize = 20;
 
     private Sort sort;
 

+ 1 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/BaseQueryService.java

@@ -9,7 +9,7 @@ public class BaseQueryService<T> {
             query.setPageNumber(1);
         }
         if (query.getPageSize() < 1) {
-            query.setPageSize(10);
+            query.setPageSize(20);
         }
     }
 

+ 40 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/AnswerArea.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AnswerArea {
+
+    @JsonProperty("main_number")
+    private Integer mainNumber;
+
+    @JsonProperty("sub_number")
+    private String subNumber;
+
+    private double[] area;
+
+    public Integer getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public String getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(String subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public double[] getArea() {
+        return area;
+    }
+
+    public void setArea(double[] area) {
+        this.area = area;
+    }
+}

+ 149 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/CardFile.java

@@ -0,0 +1,149 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import cn.com.qmth.stmms.biz.mark.model.MarkConfigItem;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.DecimalFormat;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 卡格式文件内容结构
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class CardFile {
+
+    private String version;
+
+    private boolean adapted;
+
+    private List<CardPageWrapper> pages = Collections.emptyList();
+
+    @JsonIgnore
+    private SliceConfig sliceConfig;
+
+    @JsonIgnore
+    private MarkConfig markConfig;
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public boolean isAdapted() {
+        return adapted;
+    }
+
+    public void setAdapted(boolean adapted) {
+        this.adapted = adapted;
+    }
+
+    public List<CardPageWrapper> getPages() {
+        return pages;
+    }
+
+    public void setPages(List<CardPageWrapper> pages) {
+        this.pages = pages;
+    }
+
+    private void postInit() {
+        // 解析卡格式文件中的裁切图坐标,用于云阅卷同步
+        this.sliceConfig = new SliceConfig();
+        if (pages != null) {
+            int pageNumber = 0;
+            for (CardPageWrapper pageWrapper : pages) {
+                pageNumber++;
+                // 强制使用遮盖模式
+                sliceConfig.addConfig(pageNumber, 0, 0, 0, 0);
+                // 如果没有infoArea则补一个
+                if (pageWrapper.getExchange().getInfoArea().isEmpty()) {
+                    pageWrapper.getExchange().getInfoArea().add(new double[] { 0, 0, 0.001, 0.001 });
+                }
+            }
+        }
+        // 解析卡格式文件中的大题评卷坐标,用于云阅卷评卷分组设置
+        this.markConfig = new MarkConfig();
+        if (pages != null) {
+            int pageNumber = 0;
+            for (CardPageWrapper pageWrapper : pages) {
+                pageNumber++;
+                for (AnswerArea area : pageWrapper.getExchange().getAnswerArea()) {
+                    if (area.getMainNumber() != null && area.getArea() != null && area.getArea().length >= 4) {
+                        markConfig.addConfig(area.getMainNumber(), pageNumber, area.getArea()[0], area.getArea()[1],
+                                area.getArea()[2], area.getArea()[3]);
+                    }
+                }
+            }
+        }
+    }
+
+    public SliceConfig getSliceConfig() {
+        return sliceConfig;
+    }
+
+    public List<MarkConfig.ConfigItem> getMarkConfig(int mainNumber) {
+        return markConfig.getConfig(mainNumber);
+    }
+
+    public String getMarkConfigAdd(List<MarkConfig.ConfigItem> list, double position) {
+        DecimalFormat format = new DecimalFormat("####.###");
+        for (MarkConfig.ConfigItem configItem : list) {
+            configItem.left = configItem.left < position ? configItem.left : configItem.left - position;
+            configItem.top = configItem.top < position ? configItem.top : configItem.top - position;
+            configItem.width = configItem.width + position * 2;
+            configItem.height = configItem.height + position * 2;
+
+            configItem.left = Double.valueOf(format.format(configItem.left));
+            configItem.top = Double.valueOf(format.format(configItem.top));
+            configItem.width = Double.valueOf(format.format(configItem.width));
+            configItem.height = Double.valueOf(format.format(configItem.height));
+        }
+        return StringUtils.join(list, MarkConfigItem.DB_ITEM_JOINER);
+    }
+
+    /**
+     * 输出到文件前,进行必要的字段值转换与处理
+     */
+    private void format() {
+        version = "1.0.0";
+        adapted = false;
+        for (CardPageWrapper cpw : pages) {
+            cpw.getExchange().format();
+        }
+    }
+
+    /**
+     * 输出为字节数组,用于保存到文件或其他输出流
+     *
+     * @return
+     * @throws JsonProcessingException
+     */
+    public byte[] output() throws JsonProcessingException {
+        ObjectMapper mapper = new ObjectMapper();
+        this.format();
+        return mapper.writeValueAsBytes(this);
+    }
+
+    /**
+     * 从输入流解析卡格式文件
+     *
+     * @param ins
+     * @return
+     * @throws IOException
+     */
+    public static CardFile parse(InputStream ins) throws IOException {
+        ObjectMapper mapper = new ObjectMapper();
+        CardFile obj = mapper.readValue(ins, CardFile.class);
+        obj.postInit();
+        return obj;
+    }
+}

+ 168 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/CardPage.java

@@ -0,0 +1,168 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Collections;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class CardPage {
+
+    @JsonProperty("card_type")
+    private int cardType;
+
+    @JsonProperty("page_size")
+    private String pageSize;
+
+    @JsonProperty("page_image")
+    private String pageImage;
+
+    @JsonProperty("locator")
+    private Locator locator = new Locator();
+
+    @JsonProperty("fill_locator")
+    private List<FillLocator> fillLocator = Collections.emptyList();
+
+    @JsonProperty("check_area")
+    private CheckArea checkArea = new CheckArea();
+
+    @JsonProperty("info_area")
+    private List<double[]> infoArea = Collections.emptyList();
+
+    @JsonProperty("answer_area")
+    private List<AnswerArea> answerArea = Collections.emptyList();
+
+    @JsonProperty("barcode")
+    private List<FieldArea> barcode = Collections.emptyList();
+
+    @JsonProperty("qrcode")
+    private List<FieldArea> qrcode = Collections.emptyList();
+
+    @JsonProperty("fill_area")
+    private List<FillArea> fillArea = Collections.emptyList();
+
+    @JsonProperty("ocr_area")
+    private List<FieldArea> ocrArea = Collections.emptyList();
+
+    @JsonProperty("extension")
+    private Extension extension = new Extension();
+
+    public int getCardType() {
+        return cardType;
+    }
+
+    public void setCardType(int cardType) {
+        this.cardType = cardType;
+    }
+
+    public String getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(String pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public String getPageImage() {
+        return pageImage;
+    }
+
+    public void setPageImage(String pageImage) {
+        this.pageImage = pageImage;
+    }
+
+    public Locator getLocator() {
+        return locator;
+    }
+
+    public void setLocator(Locator locator) {
+        this.locator = locator;
+    }
+
+    public List<double[]> getInfoArea() {
+        return infoArea;
+    }
+
+    public void setInfoArea(List<double[]> infoArea) {
+        this.infoArea = infoArea;
+    }
+
+    public List<AnswerArea> getAnswerArea() {
+        return answerArea;
+    }
+
+    public void setAnswerArea(List<AnswerArea> answerArea) {
+        this.answerArea = answerArea;
+    }
+
+    public List<FillArea> getFillArea() {
+        return fillArea;
+    }
+
+    public void setFillArea(List<FillArea> fillArea) {
+        this.fillArea = fillArea;
+    }
+
+    public Extension getExtension() {
+        return extension;
+    }
+
+    public void setExtension(Extension extension) {
+        this.extension = extension;
+    }
+
+    public List<FillLocator> getFillLocator() {
+        return fillLocator;
+    }
+
+    public void setFillLocator(List<FillLocator> fillLocator) {
+        this.fillLocator = fillLocator;
+    }
+
+    public CheckArea getCheckArea() {
+        return checkArea;
+    }
+
+    public void setCheckArea(CheckArea checkArea) {
+        this.checkArea = checkArea;
+    }
+
+    public List<FieldArea> getBarcode() {
+        return barcode;
+    }
+
+    public void setBarcode(List<FieldArea> barcode) {
+        this.barcode = barcode;
+    }
+
+    public List<FieldArea> getQrcode() {
+        return qrcode;
+    }
+
+    public void setQrcode(List<FieldArea> qrcode) {
+        this.qrcode = qrcode;
+    }
+
+    public List<FieldArea> getOcrArea() {
+        return ocrArea;
+    }
+
+    public void setOcrArea(List<FieldArea> ocrArea) {
+        this.ocrArea = ocrArea;
+    }
+
+    /**
+     * 输出到文件前,进行必要的字段值转换与处理
+     */
+    public void format() {
+        //默认题卡类型
+        if (cardType < 1 || cardType > 3) {
+            cardType = 2;
+        }
+        //图片内容留空
+        pageImage = "";
+        //主观题答题区清空,避免影响遮盖模式
+        answerArea.clear();
+    }
+}

+ 17 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/CardPageWrapper.java

@@ -0,0 +1,17 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class CardPageWrapper {
+
+    private CardPage exchange;
+
+    public CardPage getExchange() {
+        return exchange;
+    }
+
+    public void setExchange(CardPage exchange) {
+        this.exchange = exchange;
+    }
+}

+ 33 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/CheckArea.java

@@ -0,0 +1,33 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Collections;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class CheckArea {
+
+    @JsonProperty("black_line")
+    private List<double[]> blackLine = Collections.emptyList();
+
+    @JsonProperty("white_line")
+    private List<double[]> whiteLine = Collections.emptyList();
+
+    public List<double[]> getBlackLine() {
+        return blackLine;
+    }
+
+    public void setBlackLine(List<double[]> blackLine) {
+        this.blackLine = blackLine;
+    }
+
+    public List<double[]> getWhiteLine() {
+        return whiteLine;
+    }
+
+    public void setWhiteLine(List<double[]> whiteLine) {
+        this.whiteLine = whiteLine;
+    }
+}

+ 54 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/Extension.java

@@ -0,0 +1,54 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Collections;
+import java.util.List;
+
+public class Extension {
+
+    @JsonProperty("barcode")
+    private List<FieldArea> barcode = Collections.emptyList();
+
+    @JsonProperty("qrcode")
+    private List<FieldArea> qrcode = Collections.emptyList();
+
+    @JsonProperty("fill_area")
+    private List<FillArea> fillArea = Collections.emptyList();
+
+    @JsonProperty("ocr_area")
+    private List<FieldArea> ocrArea = Collections.emptyList();
+
+    public List<FieldArea> getBarcode() {
+        return barcode;
+    }
+
+    public void setBarcode(List<FieldArea> barcode) {
+        this.barcode = barcode;
+    }
+
+    public List<FieldArea> getQrcode() {
+        return qrcode;
+    }
+
+    public void setQrcode(List<FieldArea> qrcode) {
+        this.qrcode = qrcode;
+    }
+
+    public List<FillArea> getFillArea() {
+        return fillArea;
+    }
+
+    public void setFillArea(List<FillArea> fillArea) {
+        this.fillArea = fillArea;
+    }
+
+    public List<FieldArea> getOcrArea() {
+        return ocrArea;
+    }
+
+    public void setOcrArea(List<FieldArea> ocrArea) {
+        this.ocrArea = ocrArea;
+    }
+
+}

+ 27 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/FieldArea.java

@@ -0,0 +1,27 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class FieldArea {
+
+    private String field;
+
+    private double[] area;
+
+    public String getField() {
+        return field;
+    }
+
+    public void setField(String field) {
+        this.field = field;
+    }
+
+    public double[] getArea() {
+        return area;
+    }
+
+    public void setArea(double[] area) {
+        this.area = area;
+    }
+}

+ 66 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/FillArea.java

@@ -0,0 +1,66 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Collections;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class FillArea {
+
+    @JsonProperty("field")
+    private String field;
+
+    @JsonProperty("index")
+    private int index;
+
+    @JsonProperty("single")
+    private boolean single;
+
+    @JsonProperty("horizontal")
+    private boolean horizontal;
+
+    @JsonProperty("items")
+    private List<FillItem> items = Collections.emptyList();
+
+    public String getField() {
+        return field;
+    }
+
+    public void setField(String field) {
+        this.field = field;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    public boolean isSingle() {
+        return single;
+    }
+
+    public void setSingle(boolean single) {
+        this.single = single;
+    }
+
+    public boolean isHorizontal() {
+        return horizontal;
+    }
+
+    public void setHorizontal(boolean horizontal) {
+        this.horizontal = horizontal;
+    }
+
+    public List<FillItem> getItems() {
+        return items;
+    }
+
+    public void setItems(List<FillItem> items) {
+        this.items = items;
+    }
+}

+ 56 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/FillItem.java

@@ -0,0 +1,56 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.util.Collections;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class FillItem {
+
+    @JsonProperty("main_number")
+    private Integer mainNumber;
+
+    @JsonProperty("sub_number")
+    private Integer subNumber;
+
+    @JsonProperty("options")
+    private List<double[]> options = Collections.emptyList();
+
+    @JsonProperty("recog_info")
+    private List<JsonNode> recogInfo = Collections.emptyList();
+
+    public Integer getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public Integer getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(Integer subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public List<double[]> getOptions() {
+        return options;
+    }
+
+    public void setOptions(List<double[]> options) {
+        this.options = options;
+    }
+
+    public List<JsonNode> getRecogInfo() {
+        return recogInfo;
+    }
+
+    public void setRecogInfo(List<JsonNode> recogInfo) {
+        this.recogInfo = recogInfo;
+    }
+}

+ 55 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/FillLocator.java

@@ -0,0 +1,55 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Collections;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class FillLocator {
+
+    @JsonProperty("area")
+    private double[] area;
+
+    @JsonProperty("dot_num")
+    private int dotNum;
+
+    @JsonProperty("dots")
+    private List<double[]> dots = Collections.emptyList();
+
+    @JsonProperty("horizontal")
+    private boolean horizontal;
+
+    public double[] getArea() {
+        return area;
+    }
+
+    public void setArea(double[] area) {
+        this.area = area;
+    }
+
+    public int getDotNum() {
+        return dotNum;
+    }
+
+    public void setDotNum(int dotNum) {
+        this.dotNum = dotNum;
+    }
+
+    public List<double[]> getDots() {
+        return dots;
+    }
+
+    public void setDots(List<double[]> dots) {
+        this.dots = dots;
+    }
+
+    public boolean isHorizontal() {
+        return horizontal;
+    }
+
+    public void setHorizontal(boolean horizontal) {
+        this.horizontal = horizontal;
+    }
+}

+ 30 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/Locator.java

@@ -0,0 +1,30 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+import java.util.Collections;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Locator {
+
+    private List<double[]> top = Collections.emptyList();
+
+    private List<double[]> bottom = Collections.emptyList();
+
+    public List<double[]> getTop() {
+        return top;
+    }
+
+    public void setTop(List<double[]> top) {
+        this.top = top;
+    }
+
+    public List<double[]> getBottom() {
+        return bottom;
+    }
+
+    public void setBottom(List<double[]> bottom) {
+        this.bottom = bottom;
+    }
+}

+ 46 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/MarkConfig.java

@@ -0,0 +1,46 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import cn.com.qmth.stmms.biz.mark.model.MarkConfigItem;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.*;
+
+/**
+ * 评卷分组的显示坐标
+ */
+public class MarkConfig {
+
+    private Map<Integer, List<ConfigItem>> map;
+
+    public MarkConfig() {
+        this.map = new HashMap<>();
+    }
+
+    public void addConfig(int mainNumber, int index, double left, double top, double width, double height) {
+        ConfigItem item = new ConfigItem();
+        item.index = index;
+        item.left = left;
+        item.top = top;
+        item.width = width;
+        item.height = height;
+        this.map.computeIfAbsent(mainNumber, key -> new LinkedList<>()).add(item);
+    }
+
+    public List<ConfigItem> getConfig(int mainNumber) {
+        return map.get(mainNumber);
+    }
+
+    static class ConfigItem {
+
+        // 对应的图片序号
+        int index;
+
+        // 坐标点与宽高的相对比例
+        double left, top, width, height;
+
+        @Override
+        public String toString() {
+            return StringUtils.join(Arrays.asList(index, left, top, width, height), MarkConfigItem.DB_FIELD_JOINER);
+        }
+    }
+}

+ 44 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/domain/card/SliceConfig.java

@@ -0,0 +1,44 @@
+package cn.com.qmth.stmms.biz.common.domain.card;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * 裁切坐标
+ */
+public class SliceConfig {
+
+    private List<ConfigItem> items;
+
+    public SliceConfig() {
+        this.items = new LinkedList<>();
+    }
+
+    public void addConfig(int number, int left, int top, int width, int height) {
+        ConfigItem item = new ConfigItem();
+        item.number = number;
+        item.left = left;
+        item.top = top;
+        item.width = width;
+        item.height = height;
+        this.items.add(item);
+    }
+
+    @Override
+    public String toString() {
+        return StringUtils.join(items, ",");
+    }
+
+    static class ConfigItem {
+
+        int number, left, top, width, height;
+
+        @Override
+        public String toString() {
+            return StringUtils.join(Arrays.asList(number, left, top, width, height), ":");
+        }
+    }
+}

+ 24 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/AnswerCardDao.java

@@ -0,0 +1,24 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.AnswerCard;
+import cn.com.qmth.stmms.biz.exam.model.AnswerCardPK;
+
+public interface AnswerCardDao extends PagingAndSortingRepository<AnswerCard, AnswerCardPK>,
+        JpaSpecificationExecutor<AnswerCard> {
+
+    @Query("select s from AnswerCard s where s.pk.examId=?1 and s.pk.number=?2")
+    AnswerCard findByExamIdAndNumber(Integer examId, Integer number);
+
+    @Query("select q from AnswerCard q where q.pk.examId=?1 order by q.pk.number")
+    List<AnswerCard> findByExamId(Integer examId);
+
+    @Query("select q from AnswerCard q where q.pk.examId=?1 and q.subjectCode=?2 order by q.pk.number")
+    List<AnswerCard> findByExamIdAndSubjectCode(Integer examId, String subjectCode);
+
+}

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

@@ -23,4 +23,10 @@ public interface CheckStudentDao extends PagingAndSortingRepository<CheckStudent
 
     long countByExamIdAndSubjectCodeAndChecked(int examId, String subjectCode, boolean checked);
 
+    List<CheckStudent> findByExamIdAndSubjectCodeAndCheckedAndType(int examId, String subjectCode, boolean checked,
+            CheckType type);
+
+    @Query("select distinct c.subjectCode from CheckStudent c where c.examId=?1 and c.checked=?2 and c.type=?3")
+    List<String> findCheckSubjectCodeAndCheckedAndType(int examId, boolean checked, CheckType type);
+
 }

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

@@ -104,4 +104,7 @@ public interface ExamQuestionDao extends JpaRepository<ExamQuestion, Integer>, J
     @Query("select distinct q.subjectCode from ExamQuestion q where q.examId=?1 and q.objective=?2 and q.groupNumber is null  ")
     public Set<String> FindSubjectCodeByExamIdAndObjectiveAndGroupNumberIsNull(int examId, boolean objective);
 
+    @Query(value = "select sum(cast(q.total_score as decimal(10,3))) from eb_exam_question q where q.exam_id=?1 and q.subject_code=?2 and q.is_objective=?3 and q.group_number=?4 ", nativeQuery = true)
+    public Double sumTotalScoreByGroupNumber(int examId, String subjectCode, boolean objective, Integer groupNumber);
+
 }

+ 46 - 14
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamStudentDao.java

@@ -1,20 +1,20 @@
 package cn.com.qmth.stmms.biz.exam.dao;
 
-import java.math.BigDecimal;
-import java.util.Date;
-import java.util.List;
-
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.PagingAndSortingRepository;
 
-import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
-import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
 
-public interface ExamStudentDao extends PagingAndSortingRepository<ExamStudent, Integer>,
-        JpaSpecificationExecutor<ExamStudent> {
+public interface ExamStudentDao
+        extends PagingAndSortingRepository<ExamStudent, Integer>, JpaSpecificationExecutor<ExamStudent> {
 
     public List<ExamStudent> findByExamId(int examId, Pageable pageable);
 
@@ -72,8 +72,8 @@ public interface ExamStudentDao extends PagingAndSortingRepository<ExamStudent,
 
     @Modifying
     @Query("update ExamStudent s set s.subjectiveStatus=?3, s.subjectiveScore=?4, s.subjectiveScoreList=?5,s.inspectTime=?6,s.inspectorId=?7 where s.examId=?1 and s.subjectCode=?2")
-    public void updateSubjectiveStatusAndScore(Integer examId, String subjetCode, SubjectiveStatus status,
-            double score, String scoreList, Date inspectTime, Integer inspectorId);
+    public void updateSubjectiveStatusAndScore(Integer examId, String subjetCode, SubjectiveStatus status, double score,
+            String scoreList, Date inspectTime, Integer inspectorId);
 
     @Modifying
     @Query("update ExamStudent s set s.subjectiveStatus=?3, s.subjectiveScore=?4, s.subjectiveScoreList=?5 "
@@ -109,9 +109,17 @@ public interface ExamStudentDao extends PagingAndSortingRepository<ExamStudent,
 
     @Modifying
     @Query("update ExamStudent s set s.sheetCount=?2, s.sliceCount=?3, s.answers=?4, s.batchCode=?5, s.paperType=?6,"
-            + " s.absent=?7, s.upload=true, s.uploadTime=?8, s.objectiveScore=?9, s.objectiveScoreList=?10 where s.id=?1")
+            + " s.absent=?7, s.upload=true, s.uploadTime=?8, s.objectiveScore=?9, s.objectiveScoreList=?10, "
+            + "s.cardNumber=?11 where s.id=?1")
     public int updateScanInfo(Integer id, Integer sheetCount, Integer sliceCount, String answers, String batchCode,
-            String paperType, boolean absent, Date uploadTime, Double objectiveScore, String objectiveScoreList);
+            String paperType, boolean absent, Date uploadTime, Double objectiveScore, String objectiveScoreList,
+            Integer cardNumber);
+
+    @Modifying
+    @Query("update ExamStudent s set s.sheetCount=0, s.sliceCount=0, s.answers=null, s.batchCode=null, s.paperType=?2,"
+            + " s.absent=false, s.upload=false, s.uploadTime=null, s.objectiveScore=0, s.objectiveScoreList=null, "
+            + " s.cardNumber=null, s.inspectCount=0 where s.id=?1")
+    public int resetScanInfo(Integer id, String paperType);
 
     @Modifying
     @Query("update ExamStudent s set s.manualAbsent=0 where s.examId=?1")
@@ -145,7 +153,8 @@ public interface ExamStudentDao extends PagingAndSortingRepository<ExamStudent,
 
     @Query("select s from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.upload=true and s.absent=false and s.breach=false and s.uploadTime!=null "
             + "and not exists (select l.id from MarkLibrary l where l.studentId=s.id and l.groupNumber=?3)")
-    public List<ExamStudent> findUnLibraryStudent(Integer examId, String subjectCode, Integer groupNumber, Pageable page);
+    public List<ExamStudent> findUnLibraryStudent(Integer examId, String subjectCode, Integer groupNumber,
+            Pageable page);
 
     @Query("select s from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.upload=true and s.absent=false and s.breach=false and s.uploadTime!=null and s.uploadTime>=?4 "
             + "and not exists (select l.id from MarkLibrary l where l.studentId=s.id and l.groupNumber=?3)")
@@ -196,6 +205,29 @@ public interface ExamStudentDao extends PagingAndSortingRepository<ExamStudent,
     public void updateSubjectiveStatusAndTimeAndInspectorId(Integer studentId, SubjectiveStatus status,
             Date inspectTime, Integer inspectorId);
 
-    public List<ExamStudent> findByExamIdAndStudentCodeAndSubjectCode(int examId, String studentCode, String subjectCode);
+    public List<ExamStudent> findByExamIdAndStudentCodeAndSubjectCode(int examId, String studentCode,
+            String subjectCode);
+
+    @Query("select sum(s.sheetCount) from ExamStudent s where s.examId=?1 ")
+    public Long sumSheetCountByExamId(Integer examId);
+
+    @Query("select sum(s.sheetCount) from ExamStudent s where s.examId=?1 and s.subjectCode=?2 ")
+    public Long sumSheetCountByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    @Query("select distinct m.subjectCode from ExamStudent m where m.examId=?1 and m.subjectiveStatus in (?2)  and m.upload=true and m.absent=false and m.breach=false ")
+    Set<String> findSubjectUnInspectedByExamId(int examId, SubjectiveStatus... status);
+
+    @Query("select s.college from ExamStudent s where s.examId=?1 group by s.college")
+    public List<String> findDistinctCollege(int examId);
+
+    @Query("select distinct m.subjectCode from ExamStudent m where m.examId=?1 and m.college=?2 ")
+    public List<String> findDistinctSubjectCodeByCollege(int examId, String college);
+
+    @Query("select min(s.inspectCount) from ExamStudent s where s.examId=?1 and s.subjectCode=?2  and s.upload=true and s.absent=false and s.breach=false ")
+    public Integer findMinInspectCountByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    @Modifying
+    @Query("update ExamStudent s set s.inspectCount=?2 where s.id=?1 ")
+    public void updateInspectCount(Integer studentId, Integer inspectCount);
 
 }

+ 29 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/InspectHistoryDao.java

@@ -0,0 +1,29 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.InspectHistory;
+
+public interface InspectHistoryDao extends PagingAndSortingRepository<InspectHistory, Integer>,
+        JpaSpecificationExecutor<InspectHistory>, JpaRepository<InspectHistory, Integer> {
+
+    @Query(value = "select * from eb_inspect_history s where s.student_id=?1 order by s.inspect_time desc limit ?2 ", nativeQuery = true)
+    List<InspectHistory> findByStudentIdLimit3(int studentId, int count);
+
+    Integer countByStudentId(Integer studentId);
+
+    @Modifying
+    @Query("delete from InspectHistory m where m.studentId=?1")
+    void deleteByStudentId(Integer studentId);
+
+    @Modifying
+    @Query("delete from InspectHistory m where m.examId=?1 and m.subjectCode=?2")
+    void deleteByExamIdAndSubjectCode(int examId, String subjectCode);
+
+}

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

@@ -67,4 +67,12 @@ public interface MarkerDao extends PagingAndSortingRepository<Marker, Integer>,
     public List<Marker> findByExamIdAndSubjectCodeAndUserIdAndEnable(Integer examId, String subjectCode,
             Integer userId, boolean enable);
 
+    @Modifying
+    @Query(value = "update eb_marker m set m.reject_count=?2 where m.id=?1", nativeQuery = true)
+    public void updateRejectCountById(Integer markerId, Integer rejectCount);
+
+    @Modifying
+    @Query(value = "update Marker m set m.enable=?2 where m.userId=?1")
+    public void updateEnableByUserId(Integer userId, boolean enable);
+
 }

+ 6 - 4
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/SelectiveGroupDao.java

@@ -7,20 +7,22 @@ import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.PagingAndSortingRepository;
 
-import cn.com.qmth.stmms.biz.exam.model.MarkGroupPK;
 import cn.com.qmth.stmms.biz.exam.model.SelectiveGroup;
+import cn.com.qmth.stmms.biz.exam.model.SelectiveGroupPK;
 
-public interface SelectiveGroupDao extends PagingAndSortingRepository<SelectiveGroup, MarkGroupPK>,
+public interface SelectiveGroupDao extends PagingAndSortingRepository<SelectiveGroup, SelectiveGroupPK>,
         JpaSpecificationExecutor<SelectiveGroup> {
 
     @Query("select q from SelectiveGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.pk.mainNumber=?3")
     SelectiveGroup findOne(Integer examId, String subjectCode, Integer mainNumber);
 
     @Modifying(clearAutomatically = true)
-    @Query("delete from SelectiveGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2")
-    void deleteByExamIdAndSubjectCode(Integer examId, String subjectCode);
+    @Query("delete from SelectiveGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.selectiveIndex=?3 ")
+    void deleteByExamIdAndSubjectCodeAndSelectiveIndex(Integer examId, String subjectCode, int selectiveIndex);
 
     @Query("select q from SelectiveGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 order by q.pk.mainNumber")
     List<SelectiveGroup> findByExamIdAndSubjectCode(Integer examId, String subjectCode);
 
+    long countByPkExamIdAndPkSubjectCode(int examId, String subjectCode);
+
 }

+ 21 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/SelectiveStudentDao.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.SelectiveStudent;
+
+public interface SelectiveStudentDao extends JpaRepository<SelectiveStudent, Integer>,
+        PagingAndSortingRepository<SelectiveStudent, Integer>, JpaSpecificationExecutor<SelectiveStudent> {
+
+    @Modifying(clearAutomatically = true)
+    void deleteByExamIdAndSubjectCode(Integer examId, String subjectCode);
+
+    @Modifying(clearAutomatically = true)
+    @Query("delete SelectiveStudent s where s.studentId=?1")
+    void deleteByStudentId(Integer studentId);
+
+}

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

@@ -41,4 +41,7 @@ public interface SubjectiveScoreDao extends JpaRepository<SubjectiveScore, Subje
             + "(select g.pk.studentId from MarkGroupStudent g where g.pk.studentId=s.pk.studentId and g.status=?4)")
     void deleteByStudentGroupStatus(Integer examId, String subjectCode, Integer groupNumber, SubjectiveStatus status);
 
+    @Query("select s from SubjectiveScore s where s.pk.studentId=?1 and s.uncalculate=?2 order by s.pk.mainNumber, s.pk.subNumber")
+    List<SubjectiveScore> findByStudentIdAndUncalculate(Integer studentId, Boolean uncalculate);
+
 }

+ 164 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/AnswerCard.java

@@ -0,0 +1,164 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
+import cn.com.qmth.stmms.common.enums.CardSource;
+
+/**
+ * 卡格式
+ */
+@Entity
+@Table(name = "eb_answer_card")
+public class AnswerCard implements Serializable {
+
+    private static final long serialVersionUID = 9094397873995690949L;
+
+    @EmbeddedId
+    private AnswerCardPK pk;
+
+    @Column(name = "subject_code", nullable = true)
+    private String subjectCode;
+
+    @Column(name = "paper_count", nullable = false)
+    private Integer paperCount;
+
+    @Enumerated(EnumType.STRING)
+    @Column(name = "source", length = 16, nullable = false)
+    private CardSource source;
+
+    @Column(name = "need_adapte", nullable = true)
+    private Boolean needAdapte;
+
+    @Column(name = "single_page", nullable = true)
+    private Boolean singlePage;
+
+    private String parameter;
+
+    private String remark;
+
+    private String md5;
+
+    @Column(name = "slice_config", nullable = false)
+    private String sliceConfig;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name = "update_time")
+    private Date updateTime;
+
+    public AnswerCard() {
+        this.pk = new AnswerCardPK();
+    }
+
+    public Integer getExamId() {
+        return pk.getExamId();
+    }
+
+    public void setExamId(Integer examId) {
+        pk.setExamId(examId);
+    }
+
+    public Integer getNumber() {
+        return pk.getNumber();
+    }
+
+    public void setNumber(Integer number) {
+        pk.setNumber(number);
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Integer getPaperCount() {
+        return paperCount;
+    }
+
+    public void setPaperCount(Integer paperCount) {
+        this.paperCount = paperCount;
+    }
+
+    public CardSource getSource() {
+        return source;
+    }
+
+    public void setSource(CardSource source) {
+        this.source = source;
+    }
+
+    public Boolean getNeedAdapte() {
+        return needAdapte;
+    }
+
+    public void setNeedAdapte(Boolean needAdapte) {
+        this.needAdapte = needAdapte;
+    }
+
+    public Boolean getSinglePage() {
+        return singlePage;
+    }
+
+    public void setSinglePage(Boolean singlePage) {
+        this.singlePage = singlePage;
+    }
+
+    public String getParameter() {
+        return parameter;
+    }
+
+    public void setParameter(String parameter) {
+        this.parameter = parameter;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String getMd5() {
+        return md5;
+    }
+
+    public void setMd5(String md5) {
+        this.md5 = md5;
+    }
+
+    public String getSliceConfig() {
+        return sliceConfig;
+    }
+
+    public void setSliceConfig(String sliceConfig) {
+        this.sliceConfig = sliceConfig;
+    }
+
+    public List<PictureConfigItem> getSliceConfigList() {
+        return PictureConfigItem.parse(sliceConfig);
+    }
+
+}

+ 72 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/AnswerCardPK.java

@@ -0,0 +1,72 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class AnswerCardPK implements Serializable {
+
+    private static final long serialVersionUID = 7454931281820903561L;
+
+    @Column(name = "exam_id", nullable = false)
+    private Integer examId;
+
+    @Column(name = "number", nullable = false)
+    private Integer number;
+
+    public AnswerCardPK() {
+
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public Integer getNumber() {
+        return number;
+    }
+
+    public void setNumber(Integer number) {
+        this.number = number;
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((examId == null) ? 0 : examId.hashCode());
+        result = PRIME * result + ((number == null) ? 0 : number.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final AnswerCardPK other = (AnswerCardPK) obj;
+        if (examId == null) {
+            if (other.examId != null)
+                return false;
+        } else if (!examId.equals(other.examId))
+            return false;
+
+        if (number == null) {
+            if (other.number != null)
+                return false;
+        } else if (!number.equals(other.number))
+            return false;
+
+        return true;
+    }
+
+}

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

@@ -150,6 +150,24 @@ public class Exam implements Serializable {
     @Column(name = "sheet_view", nullable = false)
     private boolean sheetView;
 
+    /**
+     * 扫描配置
+     */
+    @Column(name = "scan_config", nullable = true)
+    private String scanConfig;
+
+    /**
+     * 自动跳转
+     */
+    @Column(name = "auto_scroll", nullable = false)
+    private boolean autoScroll;
+
+    /**
+     * 是否裁切
+     */
+    @Column(name = "enable_split", nullable = false)
+    private boolean enableSplit;
+
     public Integer getId() {
         return id;
     }
@@ -362,4 +380,28 @@ public class Exam implements Serializable {
         this.sheetView = sheetView;
     }
 
+    public String getScanConfig() {
+        return scanConfig;
+    }
+
+    public void setScanConfig(String scanConfig) {
+        this.scanConfig = scanConfig;
+    }
+
+    public boolean isAutoScroll() {
+        return autoScroll;
+    }
+
+    public void setAutoScroll(boolean autoScroll) {
+        this.autoScroll = autoScroll;
+    }
+
+    public boolean isEnableSplit() {
+        return enableSplit;
+    }
+
+    public void setEnableSplit(boolean enableSplit) {
+        this.enableSplit = enableSplit;
+    }
+
 }

+ 58 - 4
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamQuestion.java

@@ -1,12 +1,21 @@
 package cn.com.qmth.stmms.biz.exam.model;
 
-import cn.com.qmth.stmms.common.enums.ObjectivePolicy;
-
-import javax.persistence.*;
 import java.io.Serializable;
 import java.util.LinkedList;
 import java.util.List;
 
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import cn.com.qmth.stmms.common.enums.ObjectivePolicy;
+import cn.com.qmth.stmms.common.enums.QuestionType;
+
 @Entity
 @Table(name = "eb_exam_question")
 public class ExamQuestion implements Serializable {
@@ -51,12 +60,16 @@ public class ExamQuestion implements Serializable {
     private Double intervalScore;
 
     /**
-     * 客观题判分策略(1-平均,2-最高,3-最低)
+     * 客观题判分策略
      */
     @Column(name = "objective_policy", nullable = true)
     @Enumerated(EnumType.STRING)
     private ObjectivePolicy objectivePolicy;
 
+    @Column(name = "question_type", nullable = true)
+    @Enumerated(EnumType.ORDINAL)
+    private QuestionType type;
+
     @Transient
     private ExamSubject subject;
 
@@ -81,6 +94,15 @@ public class ExamQuestion implements Serializable {
     @Transient
     private boolean selective;
 
+    @Transient
+    private boolean enableUpdate;
+
+    @Transient
+    private Integer selectiveIndex;
+
+    @Transient
+    private Integer selectivePart;
+
     public Integer getId() {
         return id;
     }
@@ -287,4 +309,36 @@ public class ExamQuestion implements Serializable {
         this.selective = selective;
     }
 
+    public QuestionType getType() {
+        return type;
+    }
+
+    public void setType(QuestionType type) {
+        this.type = type;
+    }
+
+    public boolean isEnableUpdate() {
+        return enableUpdate;
+    }
+
+    public void setEnableUpdate(boolean enableUpdate) {
+        this.enableUpdate = enableUpdate;
+    }
+
+    public Integer getSelectiveIndex() {
+        return selectiveIndex;
+    }
+
+    public void setSelectiveIndex(Integer selectiveIndex) {
+        this.selectiveIndex = selectiveIndex;
+    }
+
+    public Integer getSelectivePart() {
+        return selectivePart;
+    }
+
+    public void setSelectivePart(Integer selectivePart) {
+        this.selectivePart = selectivePart;
+    }
+
 }

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

@@ -277,6 +277,12 @@ public class ExamStudent implements Serializable {
     @Column(name = "inspector_id")
     private Integer inspectorId;
 
+    @Column(name = "card_number", nullable = true)
+    private Integer cardNumber;
+
+    @Column(name = "inspect_count", nullable = true)
+    private Integer inspectCount;
+
     /**
      * 科目备注信息
      */
@@ -329,6 +335,15 @@ public class ExamStudent implements Serializable {
     @Transient
     private ProblemType problemType;
 
+    @Transient
+    private String problemUserName;
+
+    @Transient
+    private String problemRestTime;
+
+    @Transient
+    private List<InspectHistory> inspectHistoryList;
+
     public Integer getId() {
         return id;
     }
@@ -854,4 +869,44 @@ public class ExamStudent implements Serializable {
         this.inspector = inspector;
     }
 
+    public String getProblemUserName() {
+        return problemUserName;
+    }
+
+    public void setProblemUserName(String problemUserName) {
+        this.problemUserName = problemUserName;
+    }
+
+    public String getProblemRestTime() {
+        return problemRestTime;
+    }
+
+    public void setProblemRestTime(String problemRestTime) {
+        this.problemRestTime = problemRestTime;
+    }
+
+    public Integer getCardNumber() {
+        return cardNumber;
+    }
+
+    public void setCardNumber(Integer cardNumber) {
+        this.cardNumber = cardNumber;
+    }
+
+    public List<InspectHistory> getInspectHistoryList() {
+        return inspectHistoryList;
+    }
+
+    public void setInspectHistoryList(List<InspectHistory> inspectHistoryList) {
+        this.inspectHistoryList = inspectHistoryList;
+    }
+
+    public Integer getInspectCount() {
+        return inspectCount;
+    }
+
+    public void setInspectCount(Integer inspectCount) {
+        this.inspectCount = inspectCount;
+    }
+
 }

+ 29 - 3
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamSubject.java

@@ -93,13 +93,25 @@ public class ExamSubject implements Serializable {
      */
     @Column(name = "sas_config", nullable = true)
     private String sasConfig;
-    
+
     /**
      * 试评数量
      */
     @Column(name = "trial_count", nullable = true)
     private Integer trialCount;
 
+    /**
+     * 自动跳转
+     */
+    @Column(name = "auto_scroll", nullable = true)
+    private Boolean autoScroll;
+
+    /**
+     * 是否裁切
+     */
+    @Column(name = "enable_split", nullable = true)
+    private Boolean enableSplit;
+
     /**
      * 大题数量
      */
@@ -358,14 +370,28 @@ public class ExamSubject implements Serializable {
         this.paperType = paperType;
     }
 
-    
     public Integer getTrialCount() {
         return trialCount;
     }
 
-    
     public void setTrialCount(Integer trialCount) {
         this.trialCount = trialCount;
     }
 
+    public Boolean getAutoScroll() {
+        return autoScroll;
+    }
+
+    public void setAutoScroll(Boolean autoScroll) {
+        this.autoScroll = autoScroll;
+    }
+
+    public Boolean getEnableSplit() {
+        return enableSplit;
+    }
+
+    public void setEnableSplit(Boolean enableSplit) {
+        this.enableSplit = enableSplit;
+    }
+
 }

+ 115 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/InspectHistory.java

@@ -0,0 +1,115 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+
+/**
+ * 复核记录表
+ */
+@Entity
+@Table(name = "eb_inspect_history")
+public class InspectHistory implements Serializable {
+
+    private static final long serialVersionUID = 8663161504344806413L;
+
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    /**
+     * 考试ID
+     */
+    @Column(name = "exam_id")
+    private Integer examId;
+
+    /**
+     * 科目CODE
+     */
+    @Column(name = "subject_code")
+    private String subjectCode;
+
+    /**
+     * 考生
+     */
+    @Column(name = "student_id")
+    private Integer studentId;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name = "inspect_time", nullable = false)
+    private Date inspectTime;
+
+    /**
+     * 复核人id
+     */
+    @Column(name = "inspector_id")
+    private Integer inspectorId;
+
+    @Transient
+    private String inspectorName;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public Date getInspectTime() {
+        return inspectTime;
+    }
+
+    public void setInspectTime(Date inspectTime) {
+        this.inspectTime = inspectTime;
+    }
+
+    public Integer getInspectorId() {
+        return inspectorId;
+    }
+
+    public void setInspectorId(Integer inspectorId) {
+        this.inspectorId = inspectorId;
+    }
+
+    public String getInspectorName() {
+        return inspectorName;
+    }
+
+    public void setInspectorName(String inspectorName) {
+        this.inspectorName = inspectorName;
+    }
+
+}

+ 26 - 16
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroup.java

@@ -1,14 +1,5 @@
 package cn.com.qmth.stmms.biz.exam.model;
 
-import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
-import cn.com.qmth.stmms.biz.utils.ScoreItem;
-import cn.com.qmth.stmms.common.enums.MarkMode;
-import cn.com.qmth.stmms.common.enums.MarkStatus;
-import cn.com.qmth.stmms.common.enums.ScorePolicy;
-import cn.com.qmth.stmms.common.enums.ThirdPolicy;
-import org.apache.commons.lang.StringUtils;
-
-import javax.persistence.*;
 import java.io.Serializable;
 import java.text.DecimalFormat;
 import java.util.Date;
@@ -16,6 +7,25 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
 
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+
+import org.apache.commons.lang.StringUtils;
+
+import cn.com.qmth.stmms.biz.mark.model.MarkConfigItem;
+import cn.com.qmth.stmms.biz.utils.ScoreItem;
+import cn.com.qmth.stmms.common.enums.MarkMode;
+import cn.com.qmth.stmms.common.enums.MarkStatus;
+import cn.com.qmth.stmms.common.enums.ScorePolicy;
+import cn.com.qmth.stmms.common.enums.ThirdPolicy;
+
 /**
  * 评卷分组对象
  */
@@ -145,7 +155,7 @@ public class MarkGroup implements Serializable {
         this.pk = new MarkGroupPK();
     }
 
-    public MarkGroup(Integer examId, String subjectCode, Integer number, List<PictureConfigItem> configList,
+    public MarkGroup(Integer examId, String subjectCode, Integer number, List<MarkConfigItem> configList,
             Double totalScore, Double doubleRate, Double arbitrateThreshold, Integer scorePolicy, String markMode,
             Integer trialCount, boolean sheetView, boolean enableAllZero, Integer thirdPolicy, boolean selective) {
         this.pk = new MarkGroupPK();
@@ -153,7 +163,7 @@ public class MarkGroup implements Serializable {
         this.pk.setNumber(number);
         this.pk.setSubjectCode(subjectCode);
         this.picList = configList != null && configList.size() > 0 ? StringUtils.join(configList,
-                PictureConfigItem.DB_ITEM_JOINER) : "";
+                MarkConfigItem.DB_ITEM_JOINER) : "";
         this.totalScore = totalScore;
         this.libraryCount = 0;
         this.markedCount = 0;
@@ -170,7 +180,7 @@ public class MarkGroup implements Serializable {
         } else {
             this.scorePolicy = ScorePolicy.AVG;
         }
-        if (markMode != null) {
+        if (StringUtils.isNotBlank(markMode)) {
             this.markMode = MarkMode.findByName(markMode);
         }
         if (trialCount != null && trialCount > 0) {
@@ -221,13 +231,13 @@ public class MarkGroup implements Serializable {
         this.picList = picList;
     }
 
-    public void setPicList(List<PictureConfigItem> configList) {
+    public void setPicList(List<MarkConfigItem> configList) {
         this.picList = configList != null && configList.size() > 0 ? StringUtils.join(configList,
-                PictureConfigItem.DB_ITEM_JOINER) : "";
+                MarkConfigItem.DB_ITEM_JOINER) : "";
     }
 
-    public List<PictureConfigItem> getPictureConfigList() {
-        return PictureConfigItem.parse(this.picList);
+    public List<MarkConfigItem> getPictureConfigList() {
+        return MarkConfigItem.parse(this.picList);
     }
 
     public Double getTotalScore() {

+ 11 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Marker.java

@@ -47,6 +47,9 @@ public class Marker implements Serializable {
     @Column(name = "valid_count")
     private Integer validCount;
 
+    @Column(name = "reject_count")
+    private Integer rejectCount;
+
     @Column(name = "avg_speed")
     private Double avgSpeed;
 
@@ -292,4 +295,12 @@ public class Marker implements Serializable {
         this.classCount = classCount;
     }
 
+    public Integer getRejectCount() {
+        return rejectCount;
+    }
+
+    public void setRejectCount(Integer rejectCount) {
+        this.rejectCount = rejectCount;
+    }
+
 }

+ 56 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/SelectiveGroup.java

@@ -5,7 +5,12 @@ import java.io.Serializable;
 import javax.persistence.Column;
 import javax.persistence.EmbeddedId;
 import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import cn.com.qmth.stmms.common.enums.ScorePolicy;
 
 @Entity
 @Table(name = "eb_selective_group")
@@ -16,24 +21,43 @@ public class SelectiveGroup implements Serializable {
     @EmbeddedId
     private SelectiveGroupPK pk;
 
+    // 选做题分组
     @Column(name = "selective_index", nullable = false)
     private Integer selectiveIndex;
 
+    // 选做题合分数量
     @Column(name = "selective_count", nullable = false)
     private Integer selectiveCount;
 
+    // 选做题分区
+    @Column(name = "selective_part", nullable = false)
+    private Integer selectivePart;
+
+    // 选做题合分方式
+    @Column(name = "score_policy", nullable = true, length = 16)
+    @Enumerated(EnumType.STRING)
+    private ScorePolicy scorePolicy;
+
+    @Transient
+    private String title;
+
+    @Transient
+    private Double partScore;
+
     public SelectiveGroup() {
         this.pk = new SelectiveGroupPK();
     }
 
     public SelectiveGroup(Integer examId, String subjectCode, Integer mainNumber, Integer selectiveIndex,
-            Integer selectiveCount) {
+            Integer selectiveCount, Integer selectivePart, ScorePolicy scorePolicy) {
         this.pk = new SelectiveGroupPK();
         this.pk.setExamId(examId);
         this.pk.setSubjectCode(subjectCode);
         this.pk.setMainNumber(mainNumber);
         this.selectiveCount = selectiveCount;
         this.selectiveIndex = selectiveIndex;
+        this.selectivePart = selectivePart;
+        this.scorePolicy = scorePolicy == null ? ScorePolicy.MAX : scorePolicy;
     }
 
     public Integer getExamId() {
@@ -76,4 +100,35 @@ public class SelectiveGroup implements Serializable {
         this.selectiveCount = selectiveCount;
     }
 
+    public ScorePolicy getScorePolicy() {
+        return scorePolicy;
+    }
+
+    public void setScorePolicy(ScorePolicy scorePolicy) {
+        this.scorePolicy = scorePolicy;
+    }
+
+    public Integer getSelectivePart() {
+        return selectivePart;
+    }
+
+    public void setSelectivePart(Integer selectivePart) {
+        this.selectivePart = selectivePart;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Double getPartScore() {
+        return partScore;
+    }
+
+    public void setPartScore(Double partScore) {
+        this.partScore = partScore;
+    }
 }

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

@@ -0,0 +1,84 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * 选做题得分详情状态
+ */
+@Entity
+@Table(name = "eb_selective_student")
+public class SelectiveStudent implements Serializable {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -2163077169203698621L;
+
+    @Id
+    @Column(name = "student_id", nullable = false)
+    private Integer studentId;
+
+    /**
+     * 考试ID
+     */
+    @Column(name = "exam_id", nullable = false)
+    private Integer examId;
+
+    /**
+     * 科目代码
+     */
+    @Column(name = "subject_code", length = 32, nullable = false)
+    private String subjectCode;
+
+    @Column(name = "muti_selective", nullable = false)
+    private Boolean mutiSelective;
+
+    @Column(name = "less_selective", nullable = false)
+    private Boolean lessSelective;
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Boolean getMutiSelective() {
+        return mutiSelective;
+    }
+
+    public void setMutiSelective(Boolean mutiSelective) {
+        this.mutiSelective = mutiSelective;
+    }
+
+    public Boolean getLessSelective() {
+        return lessSelective;
+    }
+
+    public void setLessSelective(Boolean lessSelective) {
+        this.lessSelective = lessSelective;
+    }
+
+}

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

@@ -4,6 +4,7 @@ import javax.persistence.Column;
 import javax.persistence.EmbeddedId;
 import javax.persistence.Entity;
 import javax.persistence.Table;
+
 import java.io.Serializable;
 
 /**
@@ -54,6 +55,18 @@ public class SubjectiveScore implements Serializable, Comparable<SubjectiveScore
     @Column(name = "score", nullable = false)
     private Double score;
 
+    /**
+     * 未作答的步骤数量
+     */
+    @Column(name = "unanswered_count", nullable = false)
+    private Integer unansweredCount;
+
+    /**
+     * 未计分
+     */
+    @Column(name = "uncalculate", nullable = false)
+    private Boolean uncalculate;
+
     public SubjectiveScore() {
         this.pk = new SubjectiveScorePK();
     }
@@ -130,6 +143,14 @@ public class SubjectiveScore implements Serializable, Comparable<SubjectiveScore
         this.mainScore = mainScore;
     }
 
+    public Integer getUnansweredCount() {
+        return unansweredCount;
+    }
+
+    public void setUnansweredCount(Integer unansweredCount) {
+        this.unansweredCount = unansweredCount;
+    }
+
     @Override
     public int compareTo(SubjectiveScore other) {
         int i = this.getMainNumber() - other.getMainNumber();
@@ -149,4 +170,13 @@ public class SubjectiveScore implements Serializable, Comparable<SubjectiveScore
         }
         return i;
     }
+
+    public Boolean getUncalculate() {
+        return uncalculate;
+    }
+
+    public void setUncalculate(Boolean uncalculate) {
+        this.uncalculate = uncalculate;
+    }
+
 }

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

@@ -15,6 +15,8 @@ public class CheckStudentSearchQuery extends BaseQuery<CheckStudent> {
 
     private String subjectCode;
 
+    private String examSite;
+
     private Boolean checked;
 
     private CheckType type;
@@ -63,4 +65,12 @@ public class CheckStudentSearchQuery extends BaseQuery<CheckStudent> {
         this.type = type;
     }
 
+    public String getExamSite() {
+        return examSite;
+    }
+
+    public void setExamSite(String examSite) {
+        this.examSite = examSite;
+    }
+
 }

+ 50 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/ExamStudentSearchQuery.java

@@ -40,6 +40,10 @@ public class ExamStudentSearchQuery extends BaseQuery<ExamStudent> {
 
     private String subjectCategory;
 
+    private String examSite;
+
+    private String examRoom;
+
     private Double objectiveScore;
 
     private Double objectiveScoreGt;
@@ -72,10 +76,14 @@ public class ExamStudentSearchQuery extends BaseQuery<ExamStudent> {
 
     private String subjectCodeIn;
 
+    private String examSiteIn;
+
     private String campusNameNotIn;
 
     private String subjectCodeNotIn;
 
+    private String examSiteNotIn;
+
     private String ids;
 
     private Double startScore;
@@ -96,6 +104,8 @@ public class ExamStudentSearchQuery extends BaseQuery<ExamStudent> {
 
     private Integer inspectorId;
 
+    private Integer sheetCount;
+
     public ExamStudentSearchQuery() {
         super();
         this.statusSet = new HashSet<>();
@@ -445,4 +455,44 @@ public class ExamStudentSearchQuery extends BaseQuery<ExamStudent> {
         this.inspectorId = inspectorId;
     }
 
+    public String getExamSite() {
+        return examSite;
+    }
+
+    public void setExamSite(String examSite) {
+        this.examSite = examSite;
+    }
+
+    public String getExamRoom() {
+        return examRoom;
+    }
+
+    public void setExamRoom(String examRoom) {
+        this.examRoom = examRoom;
+    }
+
+    public String getExamSiteIn() {
+        return examSiteIn;
+    }
+
+    public void setExamSiteIn(String examSiteIn) {
+        this.examSiteIn = examSiteIn;
+    }
+
+    public String getExamSiteNotIn() {
+        return examSiteNotIn;
+    }
+
+    public void setExamSiteNotIn(String examSiteNotIn) {
+        this.examSiteNotIn = examSiteNotIn;
+    }
+
+    public Integer getSheetCount() {
+        return sheetCount;
+    }
+
+    public void setSheetCount(Integer sheetCount) {
+        this.sheetCount = sheetCount;
+    }
+
 }

+ 9 - 13
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/MarkerSearchQuery.java

@@ -16,13 +16,9 @@ public class MarkerSearchQuery extends BaseQuery<Marker> {
 
     private Integer groupNumber;
 
-    private Integer userId;
-
     private String loginName;
 
-    public void orderByUserId() {
-        setSort(new Sort(Direction.ASC, "userId"));
-    }
+    private String name;
 
     public void orderById() {
         setSort(new Sort(Direction.ASC, "id"));
@@ -60,14 +56,6 @@ public class MarkerSearchQuery extends BaseQuery<Marker> {
         this.groupNumber = groupNumber;
     }
 
-    public Integer getUserId() {
-        return userId;
-    }
-
-    public void setUserId(Integer userId) {
-        this.userId = userId;
-    }
-
     public String getLoginName() {
         return loginName;
     }
@@ -76,4 +64,12 @@ public class MarkerSearchQuery extends BaseQuery<Marker> {
         this.loginName = loginName;
     }
 
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
 }

+ 21 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/AnswerCardService.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.AnswerCard;
+
+public interface AnswerCardService {
+
+    List<AnswerCard> findByExamId(Integer examId);
+
+    AnswerCard findByExamIdAndNumber(Integer examId, Integer number);
+
+    int findMaxNumberByExamId(Integer examId);
+
+    void save(AnswerCard card);
+
+    void delete(AnswerCard card);
+
+    AnswerCard findByExamIdAndSubjectCode(Integer examId, String subjectCode);
+
+}

+ 6 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/CheckStudentService.java

@@ -10,7 +10,7 @@ public interface CheckStudentService {
 
     CheckStudent save(CheckStudent student);
 
-    List<CheckStudent> findByExamIdAndIsCheckedAndType(int examId, boolean checked, CheckType type);
+    List<CheckStudent> findByExamIdAndCheckedAndType(int examId, boolean checked, CheckType type);
 
     void deleteByStudentId(int examId);
 
@@ -22,4 +22,9 @@ public interface CheckStudentService {
 
     long countByExamIdAndSubjectCodeAndChecked(int examId, String subjectCode, boolean checked);
 
+    List<String> findCheckSubjectCode(int examId);
+
+    List<CheckStudent> findByExamIdAndSubjectCodeAndCheckedAndType(int examId, String subjectCode, boolean checked,
+            CheckType type);
+
 }

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

@@ -76,4 +76,6 @@ public interface ExamQuestionService {
 
     void resetByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(Integer examId, String subjectCode, boolean objective,
             Integer number);
+
+    double sumTotalScoreByGroupNumber(int examId, String subjectCode, boolean objective, Integer groupNumber);
 }

+ 24 - 3
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamStudentService.java

@@ -4,6 +4,7 @@ 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.mark.model.PictureConfigItem;
 import cn.com.qmth.stmms.biz.utils.OriginTag;
 import cn.com.qmth.stmms.biz.utils.PictureTag;
 import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
@@ -11,6 +12,7 @@ import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 public interface ExamStudentService {
 
@@ -103,7 +105,8 @@ public interface ExamStudentService {
     public Long countByExamIdAndSubjectCodeAndCampus(Integer examId, String code, String campusName, boolean upload,
             boolean absent);
 
-    public long countByNoAbsentAndBreach(int examId, String subjectCode, boolean upload, boolean absent, boolean breach);
+    public long countByNoAbsentAndBreach(int examId, String subjectCode, boolean upload, boolean absent,
+            boolean breach);
 
     public long countByAbsentAndBreach(int examId, String subjectCode, Boolean absent, Boolean breach);
 
@@ -122,10 +125,13 @@ public interface ExamStudentService {
 
     Map<Integer, List<PictureTag>> buildSheetTags(ExamStudent student, boolean withGroupScore);
 
-    Map<MarkGroup, List<OriginTag>> getSliceTags(ExamStudent student, boolean withGroupScore);
+    Map<MarkGroup, List<OriginTag>> getSliceTags(ExamStudent student, boolean withGroupScore,
+            List<PictureConfigItem> sliceConfig);
 
     boolean updateScanInfo(ExamStudent student);
 
+    boolean resetScanInfo(ExamStudent student);
+
     long countUploadedByExamIdAndSubjectCode(Integer examId, String subjectCode);
 
     long countUploadedByExamId(Integer examId);
@@ -143,9 +149,24 @@ public interface ExamStudentService {
     public void updateSubjectiveStatusAndTimeAndInspectorId(Integer studentId, SubjectiveStatus status,
             Date inspectTime, Integer inspectorId);
 
-    public List<ExamStudent> findByExamIdAndStudentCodeAndSubjectCode(int examId, String studentCode, String subjectCode);
+    public List<ExamStudent> findByExamIdAndStudentCodeAndSubjectCode(int examId, String studentCode,
+            String subjectCode);
 
     long countByExamIdAndSubjectCodeAndStatus(int examId, String subjectCode, SubjectiveStatus... status);
 
     public ExamStudent randomStudent(Integer examId, String code);
+
+    public long countSheetCountByExamId(Integer examId);
+
+    public long countSheetCountByExamIdAndSubjectCode(int examId, String code);
+
+    public Set<String> findSubjectUnInspectedByExamId(int examId);
+
+    public List<String> findDistinctCollege(int examId);
+
+    public List<String> findDistinctSubjectCodeByCollege(int examId, String college);
+
+    public int findMinInspectCountByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    public void updateInspectCount(Integer studentId, Integer inspectCount);
 }

+ 19 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/InspectHistoryService.java

@@ -0,0 +1,19 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.InspectHistory;
+
+public interface InspectHistoryService {
+
+    InspectHistory save(InspectHistory i);
+
+    List<InspectHistory> findByStudentIdLimit3(Integer studentId);
+
+    Integer countByStudentId(Integer studentId);
+
+    void deleteByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    void deleteByStudentId(Integer studentId);
+
+}

+ 13 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/InspectedService.java

@@ -29,4 +29,17 @@ public interface InspectedService {
      */
     boolean hasApplied(ExamStudent student, Integer userId);
 
+    /**
+     * 复核
+     */
+    boolean inspect(Integer studentId, Integer userId);
+
+    /**
+     * 取消复核
+     * 
+     * @param studentId
+     * @return
+     */
+    boolean cancel(Integer studentId);
+
 }

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

@@ -1,13 +1,13 @@
 package cn.com.qmth.stmms.biz.exam.service;
 
+import java.util.Date;
+import java.util.List;
+
 import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
-import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
+import cn.com.qmth.stmms.biz.mark.model.MarkConfigItem;
 import cn.com.qmth.stmms.common.enums.MarkMode;
 import cn.com.qmth.stmms.common.enums.MarkStatus;
 
-import java.util.Date;
-import java.util.List;
-
 public interface MarkGroupService {
 
     MarkGroup save(MarkGroup markGroup);
@@ -24,7 +24,7 @@ public interface MarkGroupService {
 
     long countByExam(int examId);
 
-    void updatePicList(int examId, String subjectCode, int number, List<PictureConfigItem> picList);
+    void updatePicList(int examId, String subjectCode, int number, List<MarkConfigItem> picList);
 
     void updateBuildTime(int examId, String subjectCode, int number, Date time);
 

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

@@ -39,4 +39,11 @@ public interface MarkerService {
 
     List<Marker> findByExamAndSubjectAndUserIdAndEnable(Integer examId, String subjectCode, Integer userId,
             boolean enable);
+
+    void logoutByExamIdAndSubjectCodeAndGroupNumber(Integer examId, String subjectCode, Integer number);
+
+    void updateRejectCountById(Integer markerId);
+
+    void updateEnableByUserId(Integer userId, boolean enable);
+
 }

+ 10 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/SelectiveGroupService.java

@@ -1,6 +1,7 @@
 package cn.com.qmth.stmms.biz.exam.service;
 
 import java.util.List;
+import java.util.Map;
 
 import cn.com.qmth.stmms.biz.exam.model.SelectiveGroup;
 
@@ -14,6 +15,14 @@ public interface SelectiveGroupService {
 
     List<SelectiveGroup> findByExamIdAndSubjectCode(int examId, String code);
 
-    void deleteByExamIdAndSubjectCode(int examId, String subjectCode);
+    void deleteByExamIdAndSubjectCodeAndSelectiveIndex(int examId, String subjectCode, int selectiveIndex);
+
+    List<SelectiveGroup> findIndexByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    long countByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    Map<Integer, List<SelectiveGroup>> findGroupByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    int findMaxIndexByExamIdAndSubjectCode(int examId, String subjectCode);
 
 }

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

@@ -1,6 +1,7 @@
 package cn.com.qmth.stmms.biz.exam.service;
 
 import java.util.List;
+import java.util.Set;
 
 import cn.com.qmth.stmms.biz.exam.model.SubjectiveScore;
 import cn.com.qmth.stmms.biz.exam.query.SubjectiveScoreSearchQuery;
@@ -11,4 +12,6 @@ public interface SubjectiveScoreService {
 
     List<SubjectiveScore> findByStudentIdAndGroupNumber(Integer studentId, Integer number);
 
+    Set<Integer> findMainNumberByStudentIdAndUncalculate(Integer studentId, Boolean uncalculate);
+
 }

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

@@ -0,0 +1,59 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.AnswerCardDao;
+import cn.com.qmth.stmms.biz.exam.model.AnswerCard;
+import cn.com.qmth.stmms.biz.exam.service.AnswerCardService;
+
+@Service
+public class AnswerCardServiceImpl extends BaseQueryService<AnswerCard> implements AnswerCardService {
+
+    @Autowired
+    private AnswerCardDao cardDao;
+
+    @Override
+    public AnswerCard findByExamIdAndNumber(Integer examId, Integer number) {
+        return cardDao.findByExamIdAndNumber(examId, number);
+    }
+
+    @Override
+    public int findMaxNumberByExamId(Integer examId) {
+        List<AnswerCard> cards = this.findByExamId(examId);
+        int number = 0;
+        for (AnswerCard card : cards) {
+            if (number < card.getNumber()) {
+                number = card.getNumber();
+            }
+        }
+        return number;
+    }
+
+    @Override
+    public List<AnswerCard> findByExamId(Integer examId) {
+        return cardDao.findByExamId(examId);
+    }
+
+    @Transactional
+    @Override
+    public void save(AnswerCard card) {
+        this.cardDao.save(card);
+    }
+
+    @Transactional
+    @Override
+    public void delete(AnswerCard card) {
+        this.cardDao.delete(card);
+    }
+
+    @Override
+    public AnswerCard findByExamIdAndSubjectCode(Integer examId, String subjectCode) {
+        List<AnswerCard> cards = cardDao.findByExamIdAndSubjectCode(examId, subjectCode);
+        return cards.isEmpty() ? null : cards.get(0);
+    }
+}

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

@@ -34,7 +34,7 @@ public class CheckStudentServiceImpl extends BaseQueryService<CheckStudent> impl
     }
 
     @Override
-    public List<CheckStudent> findByExamIdAndIsCheckedAndType(int examId, boolean checked, CheckType type) {
+    public List<CheckStudent> findByExamIdAndCheckedAndType(int examId, boolean checked, CheckType type) {
         return checkStudentDao.findByExamIdAndCheckedAndType(examId, checked, type);
     }
 
@@ -91,4 +91,15 @@ public class CheckStudentServiceImpl extends BaseQueryService<CheckStudent> impl
         return checkStudentDao.countByExamIdAndSubjectCodeAndChecked(examId, subjectCode, checked);
     }
 
+    @Override
+    public List<String> findCheckSubjectCode(int examId) {
+        return checkStudentDao.findCheckSubjectCodeAndCheckedAndType(examId, false, CheckType.MANUAL);
+    }
+
+    @Override
+    public List<CheckStudent> findByExamIdAndSubjectCodeAndCheckedAndType(int examId, String subjectCode,
+            boolean checked, CheckType type) {
+        return checkStudentDao.findByExamIdAndSubjectCodeAndCheckedAndType(examId, subjectCode, checked, type);
+    }
+
 }

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

@@ -3,11 +3,15 @@ package cn.com.qmth.stmms.biz.exam.service.impl;
 import cn.com.qmth.stmms.biz.common.BaseQueryService;
 import cn.com.qmth.stmms.biz.exam.dao.ExamQuestionDao;
 import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.SelectiveGroup;
 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.SelectiveGroupService;
 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 cn.com.qmth.stmms.common.utils.BigDecimalUtils;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Sort;
@@ -20,6 +24,7 @@ import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
+
 import java.math.BigDecimal;
 import java.util.*;
 
@@ -32,6 +37,9 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
     @Autowired
     private ExamService examService;
 
+    @Autowired
+    private SelectiveGroupService selectiveGroupService;
+
     @Transactional
     @Override
     public ExamQuestion save(ExamQuestion question) {
@@ -100,38 +108,36 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
     @Override
     public List<ExamQuestion> findByExamAndSubjectAndObjectiveGroupByNumber(Integer examId, String subjectCode,
             boolean objective) {
-        return questionSort(
-                questionDao.findByExamIdAndSubjectCodeAndObjectiveGroupByNumber(examId, subjectCode, objective));
+        return questionSort(questionDao.findByExamIdAndSubjectCodeAndObjectiveGroupByNumber(examId, subjectCode,
+                objective));
     }
 
     @Override
     public List<ExamQuestion> findByExamAndSubjectAndObjectiveAndPaperType(Integer examId, String subjectCode,
             boolean objective, String paperType) {
-        return questionSort(questionDao
-                .findByExamIdAndSubjectCodeAndObjectiveAndPaperType(examId, subjectCode, objective, paperType,
-                        new Sort(Direction.ASC, "mainNumber", "subNumber")));
+        return questionSort(questionDao.findByExamIdAndSubjectCodeAndObjectiveAndPaperType(examId, subjectCode,
+                objective, paperType, new Sort(Direction.ASC, "mainNumber", "subNumber")));
     }
 
     @Override
     public List<ExamQuestion> findByExamAndSubjectAndObjectiveAndGroupNumber(Integer examId, String subjectCode,
             boolean objective, Integer groupNumber) {
-        return questionSort(questionDao
-                .findByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(examId, subjectCode, objective, groupNumber));
+        return questionSort(questionDao.findByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(examId, subjectCode,
+                objective, groupNumber));
     }
 
     @Override
-    public List<ExamQuestion> findByExamAndSubjectAndObjectiveAndGroupNumberNotEqual(Integer examId, String subjectCode,
-            boolean objective, Integer groupNumber) {
-        return questionSort(questionDao
-                .findByExamIdAndSubjectCodeAndObjectiveAndGroupNumberNotEqual(examId, subjectCode, objective,
-                        groupNumber));
+    public List<ExamQuestion> findByExamAndSubjectAndObjectiveAndGroupNumberNotEqual(Integer examId,
+            String subjectCode, boolean objective, Integer groupNumber) {
+        return questionSort(questionDao.findByExamIdAndSubjectCodeAndObjectiveAndGroupNumberNotEqual(examId,
+                subjectCode, objective, groupNumber));
     }
 
     @Override
     public List<ExamQuestion> findByExamAndSubjectAndObjectiveAndMainNumber(Integer examId, String subjectCode,
             boolean objective, Integer mainNumber) {
-        return questionSort(questionDao
-                .findByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective, mainNumber));
+        return questionSort(questionDao.findByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode,
+                objective, mainNumber));
     }
 
     @Override
@@ -154,8 +160,8 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
     @Override
     public long countByExamAndSubjectAndObjectiveAndMainNumber(Integer examId, String subjectCode, boolean objective,
             Integer mainNumber) {
-        return questionDao
-                .countByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective, mainNumber);
+        return questionDao.countByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective,
+                mainNumber);
     }
 
     private Specification<ExamQuestion> buildSpecification(final ExamQuestionSearchQuery query) {
@@ -190,9 +196,8 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
                 if (query.getMainNumber() != null) {
                     predicates.add(cb.equal(root.get("mainNumber"), query.getMainNumber()));
                 }
-                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()]));
             }
         };
     }
@@ -211,17 +216,15 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
     @Override
     public long countByExamAndSubjectAndObjectiveAndMainNumberAndPaperType(Integer examId, String subjectCode,
             boolean objective, Integer mainNumber, String paperType) {
-        return questionDao
-                .countByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective, mainNumber,
-                        paperType);
+        return questionDao.countByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective,
+                mainNumber, paperType);
     }
 
     @Override
     public long countByExamAndSubjectAndObjectiveAndMainNumberAndSubNumber(Integer examId, String subjectCode,
             boolean objective, Integer mainNumber, String subNumber) {
-        return questionDao
-                .countByExamIdAndSubjectCodeAndObjectiveAndMainNumberAndSubNumber(examId, subjectCode, objective,
-                        mainNumber, subNumber);
+        return questionDao.countByExamIdAndSubjectCodeAndObjectiveAndMainNumberAndSubNumber(examId, subjectCode,
+                objective, mainNumber, subNumber);
     }
 
     @Transactional
@@ -242,23 +245,20 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
     @Override
     public ExamQuestion findByExamAndSubjectAndObjectiveAndMainNumberAndSubNumber(Integer examId, String subjectCode,
             boolean objective, Integer mainNumber, String subNumber) {
-        return questionDao
-                .findByExamIdAndSubjectCodeAndObjectiveAndMainNumberAndSubNumber(examId, subjectCode, objective,
-                        mainNumber, subNumber);
+        return questionDao.findByExamIdAndSubjectCodeAndObjectiveAndMainNumberAndSubNumber(examId, subjectCode,
+                objective, mainNumber, subNumber);
     }
 
     @Override
-    public List<ExamQuestion> findMainByExamAndSubjectAndObjective(Integer examId, String subjectCode,
-            boolean objective) {
+    public List<ExamQuestion> findMainByExamAndSubjectAndObjective(Integer examId, String subjectCode, boolean objective) {
         List<ExamQuestion> list = new ArrayList<ExamQuestion>();
         Set<Integer> mainNumbers = new LinkedHashSet<>();
         List<ExamQuestion> all = questionDao.findByExamIdAndSubjectCodeAndObjective(examId, subjectCode, objective);
         for (ExamQuestion q : all) {
             if (!mainNumbers.contains(q.getMainNumber())) {
                 mainNumbers.add(q.getMainNumber());
-                List<ExamQuestion> questions = questionDao
-                        .findByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective,
-                                q.getMainNumber());
+                List<ExamQuestion> questions = questionDao.findByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId,
+                        subjectCode, objective, q.getMainNumber());
                 BigDecimal totalScore = BigDecimal.ZERO;
                 for (ExamQuestion examQuestion : questions) {
                     totalScore = totalScore.add(BigDecimal.valueOf(examQuestion.getTotalScore()));
@@ -272,8 +272,41 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
 
     @Override
     public double sumTotalScore(int examId, String subjectCode, boolean objective) {
-        Double score = questionDao.sumTotalScore(examId, subjectCode, objective);
-        return score != null ? score.doubleValue() : 0d;
+        if (objective) {
+            Double score = questionDao.sumTotalScore(examId, subjectCode, objective);
+            return score != null ? score.doubleValue() : 0d;
+        } else {
+            List<SelectiveGroup> selectiveGroups = selectiveGroupService
+                    .findByExamIdAndSubjectCode(examId, subjectCode);
+            if (!selectiveGroups.isEmpty()) {
+                double totalScore = 0;
+                Map<Integer, SelectiveGroup> map = new HashMap<Integer, SelectiveGroup>();
+                for (SelectiveGroup selectiveGroup : selectiveGroups) {
+                    map.put(selectiveGroup.getMainNumber(), selectiveGroup);
+                }
+                List<ExamQuestion> questions = this.findByExamAndSubjectAndObjective(examId, subjectCode, false);
+                for (ExamQuestion examQuestion : questions) {
+                    if (map.containsKey(examQuestion.getMainNumber())) {
+                        examQuestion.setSelective(true);
+                        examQuestion.setSelectiveIndex(map.get(examQuestion.getMainNumber()).getSelectiveIndex());
+                    } else {
+                        // 非选做题总分
+                        totalScore = BigDecimalUtils.add(totalScore, examQuestion.getTotalScore());
+                    }
+                }
+                List<SelectiveGroup> indexGroup = selectiveGroupService.findIndexByExamIdAndSubjectCode(examId,
+                        subjectCode);
+                for (SelectiveGroup selectiveGroup : indexGroup) {
+                    // 选做题分组总分
+                    totalScore = BigDecimalUtils.add(totalScore,
+                            selectiveGroup.getPartScore() * selectiveGroup.getSelectiveCount());
+                }
+                return totalScore;
+            } else {
+                Double score = questionDao.sumTotalScore(examId, subjectCode, objective);
+                return score != null ? score.doubleValue() : 0d;
+            }
+        }
     }
 
     @Override
@@ -299,4 +332,10 @@ public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> impl
         questionDao.resetByExamIdAndSubjectCodeAndObjectiveAndGroupNumber(examId, subjectCode, objective, groupNumber);
     }
 
+    @Override
+    public double sumTotalScoreByGroupNumber(int examId, String subjectCode, boolean objective, Integer groupNumber) {
+        Double score = questionDao.sumTotalScoreByGroupNumber(examId, subjectCode, objective, groupNumber);
+        return score != null ? score.doubleValue() : 0d;
+    }
+
 }

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

@@ -1,52 +1,11 @@
 package cn.com.qmth.stmms.biz.exam.service.impl;
 
-import java.math.BigDecimal;
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.persistence.criteria.CriteriaBuilder;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Expression;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.math.RandomUtils;
-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.exam.dao.ExamStudentDao;
-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;
-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.*;
 import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
-import cn.com.qmth.stmms.biz.exam.service.CheckStudentService;
-import cn.com.qmth.stmms.biz.exam.service.ExamPackageService;
-import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
-import cn.com.qmth.stmms.biz.exam.service.ExamService;
-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.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.PictureConfigItem;
+import cn.com.qmth.stmms.biz.exam.service.*;
+import cn.com.qmth.stmms.biz.mark.model.*;
 import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
 import cn.com.qmth.stmms.biz.mark.service.MarkSpecialTagService;
 import cn.com.qmth.stmms.biz.mark.service.MarkTrackService;
@@ -55,7 +14,20 @@ import cn.com.qmth.stmms.biz.utils.PictureConfigTransform;
 import cn.com.qmth.stmms.biz.utils.PictureTag;
 import cn.com.qmth.stmms.biz.utils.ScoreItem;
 import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
-import cn.com.qmth.stmms.common.utils.BigDecimalUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.RandomUtils;
+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 javax.persistence.criteria.*;
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.*;
 
 @Service
 public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implements ExamStudentService {
@@ -90,6 +62,9 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
     @Autowired
     private CheckStudentService checkStudentService;
 
+    @Autowired
+    private AnswerCardService cardService;
+
     public static final String LOGINNAME_SPLITE = "-";
 
     public static final String USER_PASSWORD = "123456";
@@ -255,8 +230,14 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
 
     public ExamStudentSearchQuery findByQuery(final ExamStudentSearchQuery query) {
         checkQuery(query);
+        if (query.getSheetCount() != null) {
+            query.setSheetCount(query.getSheetCount() * 2);
+        }
         Page<ExamStudent> result = studentDao.findAll(buildSpecification(query), query);
         fillResult(result, query);
+        if (query.getSheetCount() != null) {
+            query.setSheetCount(query.getSheetCount() / 2);
+        }
         return query;
     }
 
@@ -402,7 +383,14 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
         student.setUploadTime(new Date());
         return studentDao.updateScanInfo(student.getId(), student.getSheetCount(), student.getSliceCount(),
                 student.getAnswers(), student.getBatchCode(), student.getPaperType(), student.isAbsent(),
-                student.getUploadTime(), student.getObjectiveScore(), student.getObjectiveScoreList()) > 0;
+                student.getUploadTime(), student.getObjectiveScore(), student.getObjectiveScoreList(),
+                student.getCardNumber()) > 0;
+    }
+
+    @Override
+    @Transactional
+    public boolean resetScanInfo(ExamStudent student) {
+        return studentDao.resetScanInfo(student.getId(), student.getPaperType()) > 0;
     }
 
     @Override
@@ -628,6 +616,16 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
                         predicates.add(cb.or(sub));
                     }
                 }
+                if (StringUtils.isNotBlank(query.getExamSiteIn())) {
+                    String[] list = query.getExamSiteIn().split(",");
+                    if (list.length > 0) {
+                        Predicate[] sub = new Predicate[list.length];
+                        for (int i = 0; i < list.length; i++) {
+                            sub[i] = cb.equal(root.get("examSite"), list[i]);
+                        }
+                        predicates.add(cb.or(sub));
+                    }
+                }
                 if (StringUtils.isNotBlank(query.getSubjectCodeNotIn())) {
                     String[] list = query.getSubjectCodeNotIn().split(",");
                     if (list.length > 0) {
@@ -648,6 +646,16 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
                         predicates.add(cb.and(sub));
                     }
                 }
+                if (StringUtils.isNotBlank(query.getExamSiteNotIn())) {
+                    String[] list = query.getExamSiteNotIn().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("examSite"), list[i]);
+                        }
+                        predicates.add(cb.and(sub));
+                    }
+                }
                 if (StringUtils.isNotBlank(query.getPaperType())) {
                     predicates.add(cb.equal(root.get("paperType"), query.getPaperType()));
                 }
@@ -663,6 +671,15 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
                 if (query.getInspectorId() != null) {
                     predicates.add(cb.equal(root.get("inspectorId"), query.getInspectorId()));
                 }
+                if (StringUtils.isNotBlank(query.getExamSite())) {
+                    predicates.add(cb.equal(root.get("examSite"), query.getExamSite()));
+                }
+                if (StringUtils.isNotBlank(query.getExamRoom())) {
+                    predicates.add(cb.equal(root.get("examRoom"), query.getExamRoom()));
+                }
+                if (query.getSheetCount() != null) {
+                    predicates.add(cb.equal(root.get("sheetCount"), query.getSheetCount()));
+                }
                 return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                         .size()]));
             }
@@ -815,8 +832,8 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
             sliceConfig = exam.getSliceConfigList();
         }
         if (!sliceConfig.isEmpty()) {
-            List<PictureTag> tags = PictureConfigTransform.process(sliceConfig, getSliceTags(student, withGroupScore))
-                    .get(index);
+            List<PictureTag> tags = PictureConfigTransform.process(sliceConfig,
+                    getSliceTags(student, withGroupScore, sliceConfig)).get(index);
             if (tags != null) {
                 list.addAll(tags);
             }
@@ -832,13 +849,22 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
         Map<MarkGroup, List<OriginTag>> tagMap = new HashMap<MarkGroup, List<OriginTag>>();
         Exam exam = examService.findById(student.getExamId());
         ExamSubject subject = subjectService.find(student.getExamId(), student.getSubjectCode());
-        List<PictureConfigItem> sliceConfig = subject.getSliceConfigList();
+        List<PictureConfigItem> sliceConfig = new ArrayList<PictureConfigItem>();
+        if (student.getCardNumber() != null) {
+            AnswerCard card = cardService.findByExamIdAndNumber(student.getExamId(), student.getCardNumber());
+            if (card != null) {
+                sliceConfig = card.getSliceConfigList();
+            }
+        }
+        if (sliceConfig.isEmpty()) {
+            sliceConfig = subject.getSliceConfigList();
+        }
         if (sliceConfig.isEmpty()) {
             sliceConfig = exam.getSliceConfigList();
         }
         if (!sliceConfig.isEmpty()) {
             // 有裁切图配置时才需要获取原始评卷标记信息
-            tagMap = getSliceTags(student, withGroupScore);
+            tagMap = getSliceTags(student, withGroupScore, sliceConfig);
         }
         Map<Integer, List<PictureTag>> map = PictureConfigTransform.process(sliceConfig, tagMap);
         // List<PictureTag> list = map.get(1);
@@ -854,14 +880,15 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
      * 根据考生获取所有评卷分组的评卷标记内容
      */
     @Override
-    public Map<MarkGroup, List<OriginTag>> getSliceTags(ExamStudent student, boolean withGroupScore) {
+    public Map<MarkGroup, List<OriginTag>> getSliceTags(ExamStudent student, boolean withGroupScore,
+            List<PictureConfigItem> sliceConfig) {
         Map<MarkGroup, List<OriginTag>> tagMap = new HashMap<MarkGroup, List<OriginTag>>();
         List<ExamQuestion> questions = questionService.findByExamAndSubjectAndObjective(student.getExamId(),
                 student.getSubjectCode(), false);
         List<ScoreItem> scoreList = student.getScoreList(false);
         List<MarkGroup> markGroups = groupService.findByExamAndSubject(student.getExamId(), student.getSubjectCode());
         for (MarkGroup group : markGroups) {
-            tagMap.put(group, buildOriginTags(student, group, questions, scoreList, withGroupScore));
+            tagMap.put(group, buildOriginTags(student, group, questions, scoreList, withGroupScore, sliceConfig));
         }
         return tagMap;
     }
@@ -934,7 +961,7 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
      * @return
      */
     private List<OriginTag> buildOriginTags(ExamStudent student, MarkGroup group, List<ExamQuestion> questions,
-            List<ScoreItem> scoreList, boolean withGroupScore) {
+            List<ScoreItem> scoreList, boolean withGroupScore, List<PictureConfigItem> sliceConfig) {
         if (scoreList.size() == 0) {
             return new LinkedList<>();
         }
@@ -955,14 +982,23 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
         List<OriginTag> originTags = new LinkedList<>();
         // 首先添加本大题总得分
         if (withGroupScore) {
-            List<PictureConfigItem> configList = group.getPictureConfigList();
+            List<MarkConfigItem> configList = group.getPictureConfigList();
             if (configList.isEmpty()) {
                 // 未设置评卷区域,则自动取第一张裁切图的固定位置
                 originTags.add(new OriginTag(format.format(score), 1, 10, 10));
             } else {
                 // 取第一个显示区域相对裁切图的位置
-                PictureConfigItem config = configList.get(0);
-                originTags.add(new OriginTag(format.format(score), config.getI(), config.getX(), config.getY()));
+                MarkConfigItem config = configList.get(0);
+                OriginTag tag = new OriginTag(format.format(score), config.getI(), config.getX(), config.getY());
+                // 兼容比例模式,且元素在裁切坐标内
+                if (config.getX() <= 1 && config.getY() <= 1 && config.getI() <= sliceConfig.size()
+                        && sliceConfig.get(config.getI() - 1).getW() > 0
+                        && sliceConfig.get(config.getI() - 1).getH() > 0) {
+                    tag = new OriginTag(format.format(score), config.getI(), config.getX()
+                            * sliceConfig.get(config.getI() - 1).getW(), config.getY()
+                            * sliceConfig.get(config.getI() - 1).getH());
+                }
+                originTags.add(tag);
             }
         }
         // 检测应该使用哪个评卷任务的轨迹记录
@@ -1066,4 +1102,43 @@ public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implem
         return list.get(RandomUtils.nextInt(list.size()));
 
     }
+
+    @Override
+    public long countSheetCountByExamId(Integer examId) {
+        Long count = studentDao.sumSheetCountByExamId(examId);
+        return count == null ? 0 : count;
+    }
+
+    @Override
+    public long countSheetCountByExamIdAndSubjectCode(int examId, String code) {
+        Long count = studentDao.sumSheetCountByExamIdAndSubjectCode(examId, code);
+        return count == null ? 0 : count;
+    }
+
+    @Override
+    public Set<String> findSubjectUnInspectedByExamId(int examId) {
+        return studentDao.findSubjectUnInspectedByExamId(examId, SubjectiveStatus.MARKED);
+    }
+
+    @Override
+    public List<String> findDistinctCollege(int examId) {
+        return studentDao.findDistinctCollege(examId);
+    }
+
+    @Override
+    public List<String> findDistinctSubjectCodeByCollege(int examId, String college) {
+        return studentDao.findDistinctSubjectCodeByCollege(examId, college);
+    }
+
+    @Override
+    public int findMinInspectCountByExamIdAndSubjectCode(int examId, String subjectCode) {
+        Integer count = studentDao.findMinInspectCountByExamIdAndSubjectCode(examId, subjectCode);
+        return count == null ? 0 : count;
+    }
+
+    @Transactional
+    @Override
+    public void updateInspectCount(Integer studentId, Integer inspectCount) {
+        studentDao.updateInspectCount(studentId, inspectCount);
+    }
 }

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

@@ -0,0 +1,57 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.InspectHistoryDao;
+import cn.com.qmth.stmms.biz.exam.model.InspectHistory;
+import cn.com.qmth.stmms.biz.exam.service.InspectHistoryService;
+import cn.com.qmth.stmms.biz.user.dao.UserDao;
+import cn.com.qmth.stmms.biz.user.model.User;
+
+@Service("inspectHistoryService")
+public class InspectHistoryServiceImpl extends BaseQueryService<InspectHistory> implements InspectHistoryService {
+
+    @Autowired
+    private InspectHistoryDao inspectHistoryDao;
+
+    @Autowired
+    private UserDao userDao;
+
+    @Override
+    public InspectHistory save(InspectHistory i) {
+        return inspectHistoryDao.saveAndFlush(i);
+    }
+
+    @Override
+    public List<InspectHistory> findByStudentIdLimit3(Integer studentId) {
+        List<InspectHistory> list = inspectHistoryDao.findByStudentIdLimit3(studentId, 3);
+        for (InspectHistory inspectHistory : list) {
+            User user = userDao.findOne(inspectHistory.getInspectorId());
+            inspectHistory.setInspectorName(user.getLoginName() + "/" + user.getName());
+        }
+        return list;
+    }
+
+    @Override
+    public Integer countByStudentId(Integer studentId) {
+        return inspectHistoryDao.countByStudentId(studentId);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamIdAndSubjectCode(int examId, String subjectCode) {
+        inspectHistoryDao.deleteByExamIdAndSubjectCode(examId, subjectCode);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByStudentId(Integer studentId) {
+        inspectHistoryDao.deleteByStudentId(studentId);
+    }
+
+}

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

@@ -1,6 +1,7 @@
 package cn.com.qmth.stmms.biz.exam.service.impl;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 
 import javax.persistence.EntityManager;
@@ -10,13 +11,16 @@ import javax.persistence.Query;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import cn.com.qmth.stmms.biz.common.BaseQueryService;
 import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.exam.model.InspectHistory;
 import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
 import cn.com.qmth.stmms.biz.exam.model.SelectiveGroup;
 import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
 import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
+import cn.com.qmth.stmms.biz.exam.service.InspectHistoryService;
 import cn.com.qmth.stmms.biz.exam.service.InspectedService;
 import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
 import cn.com.qmth.stmms.biz.exam.service.SelectiveGroupService;
@@ -44,6 +48,9 @@ public class InspectedServiceImpl extends BaseQueryService<ExamStudent> implemen
     @Autowired
     private SelectiveGroupService selectiveGroupService;
 
+    @Autowired
+    private InspectHistoryService inspectHistoryService;
+
     @SuppressWarnings("unchecked")
     @Override
     public List<ExamStudent> findByQuery(ExamStudentSearchQuery query, SubjectiveStatus status, Integer mainNumber,
@@ -77,7 +84,10 @@ public class InspectedServiceImpl extends BaseQueryService<ExamStudent> implemen
             whereSql.append(" and s.exam_id = :examId");
         }
         if (StringUtils.isNotBlank(query.getSubjectCode())) {
-            whereSql.append(" and s.subject_code = :subjectCode");
+            whereSql.append(" and s.subject_code = :subjectCode ");
+        }
+        if (StringUtils.isNotBlank(query.getSubjectCodeIn())) {
+            whereSql.append(" and s.subject_code in (:subjectCodeIn) ");
         }
         if (status != null) {
             whereSql.append(" and s.subjective_status = :status");
@@ -121,7 +131,12 @@ public class InspectedServiceImpl extends BaseQueryService<ExamStudent> implemen
         // 选做题多选做
         if (selectiveStatus != null && SelectiveStatus.MUTI_SELECTIVE.equals(selectiveStatus) && !groups.isEmpty()
                 && !selectiveGroups.isEmpty()) {
-            whereSql.append(" and (select count(distinct ss.group_number) from eb_subjective_score ss where ss.student_id = s.id and ss.group_number in (:groupNumbers) and ss.group_score = -1 )< :unSelectiveCount ");
+            whereSql.append(" and exists (select ss.student_id from eb_selective_student ss where ss.student_id = s.id and ss.muti_selective=1)");
+        }
+        // 选做题少选做
+        if (selectiveStatus != null && SelectiveStatus.LESS_SELECTIVE.equals(selectiveStatus) && !groups.isEmpty()
+                && !selectiveGroups.isEmpty()) {
+            whereSql.append(" and exists (select ss.student_id from eb_selective_student ss where ss.student_id = s.id and ss.less_selective=1) ");
         }
         dataSql.append(whereSql);
         StringBuilder orderSql = new StringBuilder(" order by s.inspect_time desc ");
@@ -137,6 +152,14 @@ public class InspectedServiceImpl extends BaseQueryService<ExamStudent> implemen
         if (StringUtils.isNotBlank(query.getSubjectCode())) {
             dataQuery.setParameter("subjectCode", query.getSubjectCode());
         }
+        if (StringUtils.isNotBlank(query.getSubjectCodeIn())) {
+            String[] subjectCodeIn = query.getSubjectCodeIn().split(",");
+            List<String> in = new ArrayList<String>();
+            for (String code : subjectCodeIn) {
+                in.add(code);
+            }
+            dataQuery.setParameter("subjectCodeIn", in);
+        }
         if (status != null) {
             dataQuery.setParameter("status", status.toString());
         }
@@ -162,14 +185,12 @@ public class InspectedServiceImpl extends BaseQueryService<ExamStudent> implemen
             dataQuery.setParameter("secretNumber", query.getSecretNumber());
         }
         if (selectiveStatus != null && !groups.isEmpty() && !selectiveGroups.isEmpty()) {
-            List<Integer> groupNumbers = new ArrayList<Integer>();
-            for (int i = 0; i < groups.size(); i++) {
-                groupNumbers.add(groups.get(i).getNumber());
-            }
-            dataQuery.setParameter("groupNumbers", groupNumbers);
-            if (SelectiveStatus.MUTI_SELECTIVE.equals(selectiveStatus)) {
-                int unSelectiveCount = selectiveGroups.size() - selectiveGroups.get(0).getSelectiveCount();
-                dataQuery.setParameter("unSelectiveCount", unSelectiveCount);
+            if (selectiveStatus == SelectiveStatus.UN_SELECTIVE) {
+                List<Integer> groupNumbers = new ArrayList<Integer>();
+                for (int i = 0; i < groups.size(); i++) {
+                    groupNumbers.add(groups.get(i).getNumber());
+                }
+                dataQuery.setParameter("groupNumbers", groupNumbers);
             }
         }
         return dataQuery;
@@ -225,4 +246,37 @@ public class InspectedServiceImpl extends BaseQueryService<ExamStudent> implemen
     private String getKey(ExamStudent student) {
         return student.getExamId() + "_" + student.getSubjectCode();
     }
+
+    @Transactional
+    @Override
+    public boolean inspect(Integer studentId, Integer userId) {
+        ExamStudent student = studentService.findById(studentId);
+        if (this.hasApplied(student, userId) && SubjectiveStatus.MARKED.equals(student.getSubjectiveStatus())) {
+            Date now = new Date();
+            studentService.updateSubjectiveStatusAndTimeAndInspectorId(studentId, SubjectiveStatus.INSPECTED, now,
+                    userId);
+            InspectHistory i = new InspectHistory();
+            i.setExamId(student.getExamId());
+            i.setStudentId(studentId);
+            i.setSubjectCode(student.getSubjectCode());
+            i.setInspectorId(userId);
+            i.setInspectTime(now);
+            inspectHistoryService.save(i);
+            studentService.updateInspectCount(studentId, inspectHistoryService.countByStudentId(studentId));
+            this.releaseByStudent(student);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean cancel(Integer studentId) {
+        ExamStudent student = studentService.findById(studentId);
+        if (student.getSubjectiveStatus().equals(SubjectiveStatus.INSPECTED)) {
+            studentService.updateSubjectiveStatusAndTimeAndInspectorId(student.getId(), SubjectiveStatus.MARKED, null,
+                    null);
+            return true;
+        }
+        return false;
+    }
 }

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

@@ -1,22 +1,22 @@
 package cn.com.qmth.stmms.biz.exam.service.impl;
 
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
 import cn.com.qmth.stmms.biz.common.BaseQueryService;
 import cn.com.qmth.stmms.biz.exam.dao.MarkGroupDao;
 import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
 import cn.com.qmth.stmms.biz.exam.model.MarkGroupPK;
 import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
-import cn.com.qmth.stmms.biz.mark.model.PictureConfigItem;
+import cn.com.qmth.stmms.biz.mark.model.MarkConfigItem;
 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;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.Date;
-import java.util.List;
-
 @Service("markGroupService")
 public class MarkGroupServiceImpl extends BaseQueryService<MarkGroup> implements MarkGroupService {
 
@@ -37,13 +37,13 @@ public class MarkGroupServiceImpl extends BaseQueryService<MarkGroup> implements
 
     @Transactional
     @Override
-    public void updatePicList(int examId, String subjectCode, int number, List<PictureConfigItem> configList) {
+    public void updatePicList(int examId, String subjectCode, int number, List<MarkConfigItem> configList) {
         groupDao.updatePicList(
                 examId,
                 subjectCode,
                 number,
                 configList != null && configList.size() > 0 ? StringUtils.join(configList,
-                        PictureConfigItem.DB_ITEM_JOINER) : "");
+                        MarkConfigItem.DB_ITEM_JOINER) : "");
     }
 
     @Transactional

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

@@ -1,33 +1,39 @@
 package cn.com.qmth.stmms.biz.exam.service.impl;
 
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
 import cn.com.qmth.stmms.biz.common.BaseQueryService;
 import cn.com.qmth.stmms.biz.exam.dao.MarkerDao;
+import cn.com.qmth.stmms.biz.exam.model.Exam;
 import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
 import cn.com.qmth.stmms.biz.exam.model.Marker;
 import cn.com.qmth.stmms.biz.exam.query.MarkerSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.ExamService;
 import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
 import cn.com.qmth.stmms.biz.exam.service.MarkerService;
 import cn.com.qmth.stmms.biz.mark.dao.MarkLibraryDao;
+import cn.com.qmth.stmms.biz.user.dao.UserDao;
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.biz.user.service.UserService;
+import cn.com.qmth.stmms.biz.user.service.query.UserSearchQuery;
 import cn.com.qmth.stmms.common.enums.LibraryStatus;
 import cn.com.qmth.stmms.common.enums.MarkStatus;
 
-import org.apache.commons.lang.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.jpa.domain.Specification;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.persistence.criteria.CriteriaBuilder;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
 @Service("markerService")
 public class MarkerServiceImpl extends BaseQueryService<Marker> implements MarkerService {
 
@@ -40,6 +46,15 @@ public class MarkerServiceImpl extends BaseQueryService<Marker> implements Marke
     @Autowired
     private MarkGroupService groupService;
 
+    @Autowired
+    private UserDao userDao;
+
+    @Autowired
+    private UserService userService;
+
+    @Autowired
+    private ExamService examService;
+
     @Transactional
     @Override
     public Marker save(Marker marker) {
@@ -127,8 +142,24 @@ public class MarkerServiceImpl extends BaseQueryService<Marker> implements Marke
                 if (query.getGroupNumber() != null) {
                     predicates.add(cb.equal(root.get("groupNumber"), query.getGroupNumber()));
                 }
-                if (query.getUserId() != null) {
-                    predicates.add(cb.equal(root.get("userId"), query.getUserId()));
+                if (StringUtils.isNotBlank(query.getLoginName()) || StringUtils.isNotBlank(query.getName())) {
+                    UserSearchQuery uQuery = new UserSearchQuery();
+                    uQuery.setLoginName(query.getLoginName());
+                    uQuery.setName(query.getName());
+                    if (query.getExamId() != null) {
+                        Exam exam = examService.findById(query.getExamId());
+                        uQuery.setSchoolId(exam.getSchoolId());
+                    }
+                    List<User> users = userService.findByQuery(uQuery).getResult();
+                    if (!users.isEmpty()) {
+                        List<Integer> list = new ArrayList<Integer>();
+                        for (User user : users) {
+                            list.add(user.getId());
+                        }
+                        predicates.add(root.get("userId").in(list));
+                    } else {
+                        predicates.add(cb.equal(root.get("userId"), 0));
+                    }
                 }
                 return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                         .size()]));
@@ -189,4 +220,36 @@ public class MarkerServiceImpl extends BaseQueryService<Marker> implements Marke
             boolean enable) {
         return markerDao.findByExamIdAndSubjectCodeAndUserIdAndEnable(examId, subjectCode, userId, enable);
     }
+
+    @Transactional
+    @Override
+    public void logoutByExamIdAndSubjectCodeAndGroupNumber(Integer examId, String subjectCode, Integer number) {
+        List<Marker> markers = this.findByExamAndSubjectAndGroup(examId, subjectCode, number);
+        List<User> list = new ArrayList<User>();
+        for (Marker marker : markers) {
+            User user = userDao.findOne(marker.getUserId());
+            user.refreshAccessToken();
+            list.add(user);
+        }
+        if (!list.isEmpty()) {
+            userDao.save(list);
+        }
+    }
+
+    @Override
+    public void updateRejectCountById(Integer markerId) {
+        Marker marker = markerDao.findOne(markerId);
+        int rejectCount = 1;
+        if (marker.getRejectCount() != null) {
+            rejectCount = marker.getRejectCount() + 1;
+        }
+        markerDao.updateRejectCountById(markerId, rejectCount);
+
+    }
+
+    @Transactional
+    @Override
+    public void updateEnableByUserId(Integer userId, boolean enable) {
+        markerDao.updateEnableByUserId(userId, enable);
+    }
 }

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

@@ -1,14 +1,22 @@
 package cn.com.qmth.stmms.biz.exam.service.impl;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
+import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import cn.com.qmth.stmms.biz.common.BaseQueryService;
 import cn.com.qmth.stmms.biz.exam.dao.SelectiveGroupDao;
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
 import cn.com.qmth.stmms.biz.exam.model.SelectiveGroup;
+import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
 import cn.com.qmth.stmms.biz.exam.service.SelectiveGroupService;
 
 @Service("selectiveGroupService")
@@ -17,6 +25,9 @@ public class SelectiveGroupServiceImpl extends BaseQueryService<SelectiveGroup>
     @Autowired
     private SelectiveGroupDao selectiveGroupDao;
 
+    @Autowired
+    private ExamQuestionService questionService;
+
     @Transactional
     @Override
     public SelectiveGroup save(SelectiveGroup group) {
@@ -41,8 +52,77 @@ public class SelectiveGroupServiceImpl extends BaseQueryService<SelectiveGroup>
 
     @Transactional
     @Override
-    public void deleteByExamIdAndSubjectCode(int examId, String subjectCode) {
-        selectiveGroupDao.deleteByExamIdAndSubjectCode(examId, subjectCode);
+    public void deleteByExamIdAndSubjectCodeAndSelectiveIndex(int examId, String subjectCode, int selectiveIndex) {
+        selectiveGroupDao.deleteByExamIdAndSubjectCodeAndSelectiveIndex(examId, subjectCode, selectiveIndex);
     }
 
+    @Override
+    public List<SelectiveGroup> findIndexByExamIdAndSubjectCode(int examId, String subjectCode) {
+        Map<Integer, List<SelectiveGroup>> map = this.findGroupByExamIdAndSubjectCode(examId, subjectCode);
+        List<ExamQuestion> questionList = questionService.findMainByExamAndSubjectAndObjective(examId, subjectCode,
+                false);
+        Map<Integer, String> mainTileMap = new HashMap<Integer, String>();
+        Map<Integer, Double> mainScoreMap = new HashMap<Integer, Double>();
+        for (ExamQuestion question : questionList) {
+            mainTileMap.put(question.getMainNumber(), question.getMainTitle());
+            mainScoreMap.put(question.getMainNumber(), question.getTotalScore());
+        }
+        List<SelectiveGroup> result = new ArrayList<SelectiveGroup>();
+        for (Integer key : map.keySet()) {
+            List<SelectiveGroup> indexGroup = map.get(key);
+            Set<String> mainTitles = new LinkedHashSet<>();
+            double partScore = 0;
+            int selectivePart = 0;
+            for (SelectiveGroup selectiveGroup : indexGroup) {
+                // 显示分组下所有题目名称
+                mainTitles.add(mainTileMap.get(selectiveGroup.getMainNumber()));
+                // 显示最大的part
+                if (selectivePart < selectiveGroup.getSelectivePart()) {
+                    selectivePart = selectiveGroup.getSelectivePart();
+                }
+                // 计算分组一个part的分数
+                if (selectiveGroup.getSelectivePart() == 1) {
+                    partScore = partScore + mainScoreMap.get(selectiveGroup.getMainNumber());
+                }
+            }
+            SelectiveGroup group = indexGroup.get(0);
+            group.setSelectivePart(selectivePart);
+            group.setTitle(StringUtils.join(mainTitles, ","));
+            group.setPartScore(partScore);
+            result.add(group);
+        }
+        return result;
+    }
+
+    @Override
+    public long countByExamIdAndSubjectCode(int examId, String subjectCode) {
+        return selectiveGroupDao.countByPkExamIdAndPkSubjectCode(examId, subjectCode);
+    }
+
+    @Override
+    public Map<Integer, List<SelectiveGroup>> findGroupByExamIdAndSubjectCode(int examId, String subjectCode) {
+        List<SelectiveGroup> list = selectiveGroupDao.findByExamIdAndSubjectCode(examId, subjectCode);
+        Map<Integer, List<SelectiveGroup>> map = new HashMap<Integer, List<SelectiveGroup>>();
+        for (SelectiveGroup selectiveGroup : list) {
+            List<SelectiveGroup> indexGroup = map.get(selectiveGroup.getSelectiveIndex());
+            if (indexGroup == null) {
+                indexGroup = new ArrayList<SelectiveGroup>();
+            }
+            indexGroup.add(selectiveGroup);
+            map.put(selectiveGroup.getSelectiveIndex(), indexGroup);
+        }
+        return map;
+    }
+
+    @Override
+    public int findMaxIndexByExamIdAndSubjectCode(int examId, String subjectCode) {
+        List<SelectiveGroup> groups = selectiveGroupDao.findByExamIdAndSubjectCode(examId, subjectCode);
+        int number = 0;
+        for (SelectiveGroup group : groups) {
+            if (number < group.getSelectiveIndex()) {
+                number = group.getSelectiveIndex();
+            }
+        }
+        return number;
+    }
 }

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

@@ -1,24 +1,28 @@
 package cn.com.qmth.stmms.biz.exam.service.impl;
 
-import cn.com.qmth.stmms.biz.common.BaseQueryService;
-import cn.com.qmth.stmms.biz.exam.dao.SubjectiveScoreDao;
-import cn.com.qmth.stmms.biz.exam.model.SubjectiveScore;
-import cn.com.qmth.stmms.biz.exam.query.SubjectiveScoreSearchQuery;
-import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
-import cn.com.qmth.stmms.biz.exam.service.SubjectiveScoreService;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
 import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 
-import javax.persistence.criteria.CriteriaBuilder;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.SubjectiveScoreDao;
+import cn.com.qmth.stmms.biz.exam.model.SubjectiveScore;
+import cn.com.qmth.stmms.biz.exam.query.SubjectiveScoreSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
+import cn.com.qmth.stmms.biz.exam.service.SubjectiveScoreService;
 
 @Service
 public class SubjectiveScoreServiceImpl extends BaseQueryService<SubjectiveScore> implements SubjectiveScoreService {
@@ -81,21 +85,20 @@ public class SubjectiveScoreServiceImpl extends BaseQueryService<SubjectiveScore
                 // predicates.add(predicate);
                 // }
                 if (query.getMainStartScore() != null) {
-                    Predicate predicate = cb
-                            .greaterThanOrEqualTo(root.get("mainScore").as(Double.class), query.getMainStartScore());
+                    Predicate predicate = cb.greaterThanOrEqualTo(root.get("mainScore").as(Double.class),
+                            query.getMainStartScore());
                     predicates.add(predicate);
                 }
                 if (query.getMainEndScore() != null) {
-                    Predicate predicate = cb
-                            .lessThanOrEqualTo(root.get("mainScore").as(Double.class), query.getMainEndScore());
+                    Predicate predicate = cb.lessThanOrEqualTo(root.get("mainScore").as(Double.class),
+                            query.getMainEndScore());
                     predicates.add(predicate);
                 }
                 if (query.getScore() != null) {
                     predicates.add(cb.equal(root.get("score"), query.getScore()));
                 }
-                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()]));
             }
         };
     }
@@ -106,4 +109,14 @@ public class SubjectiveScoreServiceImpl extends BaseQueryService<SubjectiveScore
         list.sort(null);
         return list;
     }
+
+    @Override
+    public Set<Integer> findMainNumberByStudentIdAndUncalculate(Integer studentId, Boolean uncalculate) {
+        Set<Integer> mainNumbers = new HashSet<Integer>();
+        List<SubjectiveScore> list = scoreDao.findByStudentIdAndUncalculate(studentId, uncalculate);
+        for (SubjectiveScore subjectiveScore : list) {
+            mainNumbers.add(subjectiveScore.getMainNumber());
+        }
+        return mainNumbers;
+    }
 }

+ 2 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/enums/FileType.java

@@ -7,7 +7,8 @@ public enum FileType {
 
     SHEET("原图", "sheet/%d/%s/%s-%d.%s"), SLICE("裁切图", "slice/%d/%s/%s-%d.%s"), JSON("作答内容", "json/%d/%s/%s.%s"), PACKAGE(
             "签到表", "package/%d/%s/%d.%s"), PAPER("试卷", "paper/%d/%s.%s"), ANSWER("标答", "answer/%d/%s.%s"), CARD("题卡",
-            "card/%d/%s.%s"), EXCHANGE("文件", "exchange/%s");
+            "card/%d/%s.%s"), EXCHANGE("文件", "exchange/%s"), ANSWER_CARD("题卡", "card/answer/%d/%s.%s"), REPORT("报表",
+            "report/%d/%s/%s.%s");
 
     private String name;
 

+ 1 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/enums/FormatType.java

@@ -5,7 +5,7 @@ package cn.com.qmth.stmms.biz.file.enums;
  */
 public enum FormatType {
 
-    JPG, JSON, PDF, ZIP;
+    JPG, JSON, PDF, ZIP, XLSX;
 
     public String getExtName() {
         return toString().toLowerCase();

+ 13 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/service/FileService.java

@@ -35,6 +35,9 @@ public interface FileService {
 
     void uploadExchange(InputStream ins, String md5, String name) throws Exception;
 
+    void uploadReport(InputStream ins, String md5, int examId, String subjectCode, String name, FormatType type)
+            throws Exception;
+
     String getSheetUri(int examId, String examNumber, int index);
 
     List<String> getSheetUris(int examId, String examNumber, int start, int end);
@@ -67,4 +70,14 @@ public interface FileService {
 
     byte[] downloadJson(int examId, String secretNumber) throws Exception;
 
+    void uploadAnswerCard(InputStream inputStream, String md5, int examId, int number) throws Exception;
+
+    String getAnswerCardUri(int examId, int number);
+
+    String getReportUri(int examId, String subjectName, String reportTitle, FormatType type);
+
+    byte[] downloadReport(int examId, String subjectName, String reportTitle, FormatType type) throws Exception;
+
+    boolean reportExist(int examId, String subjectName, String reportTitle, FormatType type);
+
 }

+ 32 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/file/service/impl/FileServiceImpl.java

@@ -297,6 +297,37 @@ public class FileServiceImpl implements FileService, InitializingBean, Disposabl
         return FileType.EXCHANGE.getPath(name);
     }
 
+    @Override
+    public void uploadAnswerCard(InputStream ins, String md5, int examId, int number) throws Exception {
+        store.write(getAnswerCardUri(examId, number), ins, md5);
+    }
+
+    @Override
+    public String getAnswerCardUri(int examId, int number) {
+        return FileType.ANSWER_CARD.getPath(examId, number, FormatType.JSON.getExtName());
+    }
+
+    @Override
+    public void uploadReport(InputStream ins, String md5, int examId, String subjectCode, String name, FormatType type)
+            throws Exception {
+        store.write(getReportUri(examId, subjectCode, name, type), ins, md5);
+    }
+
+    @Override
+    public String getReportUri(int examId, String subjectName, String reportTitle, FormatType type) {
+        return FileType.REPORT.getPath(examId, subjectName, reportTitle, type.getExtName());
+    }
+
+    @Override
+    public byte[] downloadReport(int examId, String subjectName, String reportTitle, FormatType type) throws Exception {
+        return store.read(getReportUri(examId, subjectName, reportTitle, type));
+    }
+
+    @Override
+    public boolean reportExist(int examId, String subjectName, String reportTitle, FormatType type) {
+        return store.exist(getReportUri(examId, subjectName, reportTitle, type));
+    }
+
     public static void main(String[] args) throws Exception {
         FileServiceImpl service = new FileServiceImpl();
         // service.fileServerString = "123";
@@ -313,4 +344,5 @@ public class FileServiceImpl implements FileService, InitializingBean, Disposabl
         service.downloadSheet(1, "16110003", 1);
         System.out.println("success");
     }
+
 }

+ 16 - 7
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkLibraryDao.java

@@ -85,9 +85,9 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
     void resetByMarkerId(Integer markerId, LibraryStatus status, LibraryStatus... notInStatus);
 
     @Modifying(clearAutomatically = true)
-    @Query("update MarkLibrary m set m.status=?3, m.markerId=?2, m.markerTime=null, m.markerScore=null, m.markerScoreList=null, m.markerSpent=null, "
-            + "m.headerId=null , m.headerTime=null , m.headerScore=null , m.headerScoreList=null where m.id=?1 and m.status in (?4)")
-    int resetById(Integer id, Integer markerId, LibraryStatus newStatus, LibraryStatus... previousStatus);
+    @Query("update MarkLibrary m set m.status=?4, m.markerId=?2, m.rejectReason=?3, m.markerTime=null, m.markerScore=null, m.markerScoreList=null, m.markerSpent=null, "
+            + "m.headerId=null , m.headerTime=null , m.headerScore=null , m.headerScoreList=null where m.id=?1 and m.status in (?5)")
+    int resetById(Integer id, Integer markerId, String reason, LibraryStatus newStatus, LibraryStatus... previousStatus);
 
     @Query("select f.markerId, count(f) as markerCount from MarkLibrary f where f.examId=?1 and f.status in (?2) group by f.markerId")
     List<Object[]> countMarkerAndStatus(Integer examId, LibraryStatus... status);
@@ -124,15 +124,15 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
 
     @Modifying(clearAutomatically = true)
     @Query("update MarkLibrary l set l.status=?2, l.markerId=?3, l.markerScore=?4, l.markerScoreList=?5, l.markerTime=?6, "
-            + "l.markerSpent=?7 where l.id=?1 and l.status in (?8) and (l.markerId=null or l.markerId=?3)")
+            + "l.markerSpent=?7 ,l.rejectReason=?8 where l.id=?1 and l.status in (?9) and (l.markerId=null or l.markerId=?3)")
     int updateMarkerResult(Integer id, LibraryStatus newStatus, Integer markerId, Double markerScore,
-            String markerScoreList, Date markerTime, Integer spent, LibraryStatus... previousStatus);
+            String markerScoreList, Date markerTime, Integer spent, String resson, LibraryStatus... previousStatus);
 
-    @Query("select m.markerScore ,count(m) from MarkLibrary m where m.examId=?1 and m.subjectCode=?2 and m.groupNumber=?3 and m.markerId=?4 and m.status in (?5) group by m.markerScore ")
+    @Query("select m.markerScore ,count(m) from MarkLibrary m where m.examId=?1 and m.subjectCode=?2 and m.groupNumber=?3 and m.markerId=?4 and m.markerScore != -1 and m.status in (?5)  group by m.markerScore ")
     List<Object[]> findScoreCount(int examId, String subjectCode, Integer groupNumber, Integer markerId,
             LibraryStatus... status);
 
-    @Query("select m.markerScore from MarkLibrary m where m.examId=?1 and m.subjectCode=?2 and m.groupNumber=?3 and m.status in (?4) group by m.markerScore ")
+    @Query("select m.markerScore from MarkLibrary m where m.examId=?1 and m.subjectCode=?2 and m.groupNumber=?3 and m.markerScore !=-1 and m.status in (?4) group by m.markerScore ")
     List<Double> findScore(int examId, String subjectCode, Integer groupNumber, LibraryStatus... status);
 
     @Modifying
@@ -154,4 +154,13 @@ public interface MarkLibraryDao extends JpaRepository<MarkLibrary, Integer>, Jpa
     @Query("select count(l1) from MarkLibrary l1 where l1.examId=?1 and l1.subjectCode=?2 and l1.groupNumber=?3 "
             + "and exists (select mc.id from MarkerClass mc, ExamStudent s where l1.studentId=s.id and mc.userId=?4 and s.className=mc.className)")
     long countFilterClass(Integer examId, String subjectCode, Integer groupNumber, Integer userId);
+
+    @Modifying(clearAutomatically = true)
+    @Query("update MarkLibrary l set l.unansweredCount=?2 where l.id=?1")
+    void updateUnansweredCount(Integer id, int unansweredCount);
+
+    @Query("select count(l1) from MarkLibrary l1 where l1.examId=?1 and l1.subjectCode=?2 and l1.groupNumber=?3 and l1.status in (?5) "
+            + "and exists (select mc.id from MarkerClass mc, ExamStudent s where l1.studentId=s.id and mc.userId=?4 and s.className=mc.className)")
+    long countMarkedFilterClass(Integer examId, String subjectCode, Integer groupNumber, Integer userId,
+            LibraryStatus... status);
 }

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

@@ -37,4 +37,7 @@ public interface MarkTrackDao extends JpaRepository<MarkTrack, MarkTrackPK>, Jpa
     @Query("delete from MarkTrack t where t.pk.libraryId=?1 and t.pk.questionNumber=?2")
     void deleteByLibraryIdAndQuestionNumber(Integer id, String questionNumber);
 
+    @Query("select count(t) from MarkTrack t where t.studentId=?1 and t.pk.questionNumber=?2 and t.unanswered =?3")
+    int countByStudentIdAndQuestionNumberAndUnanswered(Integer studentId, String questionNumber, boolean unanswered);
+
 }

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

@@ -1,28 +1,19 @@
 package cn.com.qmth.stmms.biz.mark.dao;
 
-import cn.com.qmth.stmms.biz.mark.model.ProblemHistory;
-import cn.com.qmth.stmms.common.enums.HistoryStatus;
-import org.springframework.data.domain.Pageable;
+import java.util.Date;
+import java.util.List;
+
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
+import cn.com.qmth.stmms.biz.mark.model.ProblemHistory;
+import cn.com.qmth.stmms.common.enums.HistoryStatus;
 
 public interface ProblemHistoryDao extends JpaRepository<ProblemHistory, Integer>,
         JpaSpecificationExecutor<ProblemHistory> {
 
-    List<ProblemHistory> findByExamIdAndSubjectCode(Integer examId, String subjectCode, Pageable page);
-
-    List<ProblemHistory> findByExamIdAndSubjectCodeAndStatus(Integer examId, String subjectCode, HistoryStatus status,
-            Pageable page);
-
-    List<ProblemHistory> findByExamIdAndSubjectCodeAndStatusIn(Integer examId, String subjectCode,
-            Set<HistoryStatus> statusSet, Pageable page);
-
     @Modifying
     @Query("delete ProblemHistory m where m.studentId=?1")
     void deleteByStudentId(Integer studentId);

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

@@ -44,12 +44,18 @@ public interface TrialLibraryDao extends JpaRepository<TrialLibrary, Integer>, J
     @Query("delete TrialLibrary m where m.studentId=?1")
     void deleteByStudentId(Integer studentId);
 
+    @Query("select l from TrialLibrary l where l.examId=?1 and l.subjectCode=?2 and l.groupNumber=?3 "
+            + "and l.markerId=?4 and l.markerScore!=-1  ")
     List<TrialLibrary> findByExamIdAndSubjectCodeAndGroupNumberAndMarkerId(Integer examId, String subjectCode,
             Integer groupNumber, Integer markerId, Pageable page);
 
+    @Query("select l from TrialLibrary l where l.examId=?1 and l.subjectCode=?2 and l.groupNumber=?3 "
+            + "and l.markerId=?4 and l.secretNumber=?5 and l.markerScore!=-1  ")
     List<TrialLibrary> findByExamIdAndSubjectCodeAndGroupNumberAndMarkerIdAndSecretNumber(Integer examId,
             String subjectCode, Integer groupNumber, Integer markerId, String secretNumber, Pageable query);
 
+    @Query("select l from TrialLibrary l where l.examId=?1 and l.subjectCode=?2 and l.groupNumber=?3 "
+            + "and l.markerId=?4 and l.markerScore=?5 and l.markerScore!=-1  ")
     List<TrialLibrary> findByExamIdAndSubjectCodeAndGroupNumberAndMarkerIdAndMarkerScore(Integer examId,
             String subjectCode, Integer groupNumber, Integer markerId, Double markerScore, Pageable query);
 

+ 3 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/TrialTrackDao.java

@@ -36,4 +36,7 @@ public interface TrialTrackDao extends JpaRepository<TrialTrack, TrialTrackPK>,
     @Query("delete from TrialTrack t where t.examId=?1 and t.subjectCode=?2 and t.groupNumber=?3")
     void deleteByExamIdAndSubjectCodeAndGroupNumber(Integer examId, String subjectCode, Integer groupNumber);
 
+    @Query("select count(t) from TrialTrack t where t.studentId=?1 and t.pk.questionNumber=?2 and t.unanswered =?3")
+    Integer countByStudentIdAndQuestionNumberAndUnanswered(Integer studentId, String questionNumber, boolean unanswered);
+
 }

+ 128 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkConfigItem.java

@@ -0,0 +1,128 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * 单个评卷区设置模型
+ */
+public class MarkConfigItem {
+
+    // 数据库中多个单元紧凑保存的拼接符,兼容旧版本只保存图片序号的模式
+    public static final String DB_ITEM_JOINER = ",";
+
+    // 数据库中单个单元紧凑保存的拼接符,兼容旧版本只保存图片序号的模式
+    public static final String DB_FIELD_JOINER = ":";
+
+    // 裁切去所属的图片序号,从1开始
+    private int i;
+
+    // 裁切区左上角X坐标
+    private double x;
+
+    // 裁切区左上角Y坐标
+    private double y;
+
+    // 裁切区宽度
+    private double w;
+
+    // 裁切区高度
+    private double h;
+
+    public MarkConfigItem() {
+
+    }
+
+    public MarkConfigItem(String text) {
+        text = StringUtils.trimToEmpty(text);
+        String[] values = StringUtils.split(text, DB_FIELD_JOINER);
+        try {
+            i = Integer.parseInt(values[0]);
+            if (values.length > 1) {
+                x = Double.parseDouble(values[1]);
+            }
+            if (values.length > 2) {
+                y = Double.parseDouble(values[2]);
+            }
+            if (values.length > 3) {
+                w = Double.parseDouble(values[3]);
+            }
+            if (values.length > 4) {
+                h = Double.parseDouble(values[4]);
+            }
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Invalid PictureConfigItem init text:" + text);
+        }
+    }
+
+    public int getI() {
+        return i;
+    }
+
+    public void setI(int i) {
+        this.i = i;
+    }
+
+    public double getX() {
+        return x;
+    }
+
+    public void setX(double x) {
+        this.x = x;
+    }
+
+    public double getY() {
+        return y;
+    }
+
+    public void setY(double y) {
+        this.y = y;
+    }
+
+    public double getW() {
+        return w;
+    }
+
+    public void setW(double w) {
+        this.w = w;
+    }
+
+    public double getH() {
+        return h;
+    }
+
+    public void setH(double h) {
+        this.h = h;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(i).append(DB_FIELD_JOINER);
+        sb.append(x).append(DB_FIELD_JOINER);
+        sb.append(y).append(DB_FIELD_JOINER);
+        sb.append(w).append(DB_FIELD_JOINER);
+        sb.append(h);
+        return sb.toString();
+    }
+
+    public static List<MarkConfigItem> parse(String text) {
+        List<MarkConfigItem> list = new LinkedList<MarkConfigItem>();
+        text = StringUtils.trimToEmpty(text);
+        String[] values = StringUtils.split(text, DB_ITEM_JOINER);
+        for (String value : values) {
+            try {
+                MarkConfigItem item = new MarkConfigItem(value);
+                if (item != null && item.i > 0) {
+                    list.add(item);
+                }
+            } catch (Exception e) {
+                continue;
+            }
+        }
+        return list;
+    }
+
+}

+ 25 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkLibrary.java

@@ -123,6 +123,15 @@ public class MarkLibrary implements Serializable {
     @Column(name = "header_score_list")
     private String headerScoreList;
 
+    /**
+     * 未作答的步骤数量
+     */
+    @Column(name = "unanswered_count", nullable = true)
+    private Integer unansweredCount;
+
+    @Column(name = "reject_reason", nullable = true)
+    private String rejectReason;
+
     @Transient
     private String markerLoginName;
 
@@ -308,4 +317,20 @@ public class MarkLibrary implements Serializable {
         this.markerLoginName = markerLoginName;
     }
 
+    public Integer getUnansweredCount() {
+        return unansweredCount;
+    }
+
+    public void setUnansweredCount(Integer unansweredCount) {
+        this.unansweredCount = unansweredCount;
+    }
+
+    public String getRejectReason() {
+        return rejectReason;
+    }
+
+    public void setRejectReason(String rejectReason) {
+        this.rejectReason = rejectReason;
+    }
+
 }

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

@@ -188,12 +188,17 @@ public class MarkResult {
     }
 
     public List<TrialTrack> getTrackList(TrialLibrary library) {
+        int unansweredCount = 0;
         List<TrialTrack> list = new LinkedList<>();
         if (trackList != null) {
             for (TrackDTO dto : trackList) {
                 list.add(dto.transform(library));
+                if (dto.isUnanswered()) {
+                    unansweredCount++;
+                }
             }
         }
+        library.setUnansweredCount(unansweredCount);
         return list;
     }
 

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

@@ -26,6 +26,10 @@ public class MarkStepDTO implements Serializable {
 
     private double minScore;
 
+    private boolean uncalculate;
+
+    private Integer selectiveIndex;
+
     private List<TrackDTO> trackList = new ArrayList<TrackDTO>();
 
     public int getMainNumber() {
@@ -112,4 +116,20 @@ public class MarkStepDTO implements Serializable {
         this.score = score;
     }
 
+    public boolean isUncalculate() {
+        return uncalculate;
+    }
+
+    public void setUncalculate(boolean uncalculate) {
+        this.uncalculate = uncalculate;
+    }
+
+    public Integer getSelectiveIndex() {
+        return selectiveIndex;
+    }
+
+    public void setSelectiveIndex(Integer selectiveIndex) {
+        this.selectiveIndex = selectiveIndex;
+    }
+
 }

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

@@ -68,6 +68,12 @@ public class MarkTrack {
     @Column(name = "offset_y", nullable = false)
     private Integer offsetY;
 
+    /**
+     * 是否未作答
+     */
+    @Column(name = "unanswered", nullable = false)
+    private boolean unanswered;
+
     public MarkTrack() {
         this.pk = new MarkTrackPK();
     }
@@ -183,4 +189,13 @@ public class MarkTrack {
     public void setOffsetY(Integer offsetY) {
         this.offsetY = offsetY;
     }
+
+    public boolean isUnanswered() {
+        return unanswered;
+    }
+
+    public void setUnanswered(boolean unanswered) {
+        this.unanswered = unanswered;
+    }
+
 }

+ 16 - 3
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/Task.java

@@ -53,7 +53,7 @@ public class Task implements Serializable {
     /**
      * 题卡图片拼接配置
      */
-    private List<PictureConfigItem> sliceConfig;
+    private List<MarkConfigItem> sliceConfig;
 
     /**
      * 多媒体地址
@@ -105,6 +105,11 @@ public class Task implements Serializable {
      */
     private boolean isRejected;
 
+    /**
+     * 打回原因
+     */
+    private String rejectReason;
+
     /**
      * 评卷员登录名
      */
@@ -184,11 +189,11 @@ public class Task implements Serializable {
         this.sliceUrls = sliceUrls;
     }
 
-    public List<PictureConfigItem> getSliceConfig() {
+    public List<MarkConfigItem> getSliceConfig() {
         return sliceConfig;
     }
 
-    public void setSliceConfig(List<PictureConfigItem> sliceConfig) {
+    public void setSliceConfig(List<MarkConfigItem> sliceConfig) {
         this.sliceConfig = sliceConfig;
     }
 
@@ -296,4 +301,12 @@ public class Task implements Serializable {
         this.message = message;
     }
 
+    public String getRejectReason() {
+        return rejectReason;
+    }
+
+    public void setRejectReason(String rejectReason) {
+        this.rejectReason = rejectReason;
+    }
+
 }

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

@@ -31,6 +31,8 @@ public class TrackDTO implements Serializable {
 
     private int offsetY;
 
+    private boolean unanswered;
+
     public TrackDTO() {
 
     }
@@ -47,6 +49,7 @@ public class TrackDTO implements Serializable {
         setOffsetIndex(track.getOffsetIndex());
         setOffsetX(track.getOffsetX());
         setOffsetY(track.getOffsetY());
+        setUnanswered(track.isUnanswered());
     }
 
     public TrackDTO(TrialTrack track) {
@@ -60,6 +63,7 @@ public class TrackDTO implements Serializable {
         setOffsetIndex(track.getOffsetIndex());
         setOffsetX(track.getOffsetX());
         setOffsetY(track.getOffsetY());
+        setUnanswered(track.isUnanswered());
     }
 
     public MarkTrack transform(MarkLibrary library, Marker marker) {
@@ -78,6 +82,7 @@ public class TrackDTO implements Serializable {
         track.setOffsetIndex(getOffsetIndex());
         track.setOffsetX(getOffsetX());
         track.setOffsetY(getOffsetY());
+        track.setUnanswered(isUnanswered());
         return track;
     }
 
@@ -98,6 +103,7 @@ public class TrackDTO implements Serializable {
         track.setOffsetIndex(getOffsetIndex());
         track.setOffsetX(getOffsetX());
         track.setOffsetY(getOffsetY());
+        track.setUnanswered(isUnanswered());
         return track;
     }
 
@@ -173,4 +179,12 @@ public class TrackDTO implements Serializable {
         this.offsetY = offsetY;
     }
 
+    public boolean isUnanswered() {
+        return unanswered;
+    }
+
+    public void setUnanswered(boolean unanswered) {
+        this.unanswered = unanswered;
+    }
+
 }

+ 14 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/TrialLibrary.java

@@ -88,6 +88,12 @@ public class TrialLibrary implements Serializable {
     @Column(name = "marker_score_list")
     private String markerScoreList;
 
+    /**
+     * 未作答的步骤数量
+     */
+    @Column(name = "unanswered_count", nullable = true)
+    private Integer unansweredCount;
+
     @Transient
     private String markerLoginName;
 
@@ -204,4 +210,12 @@ public class TrialLibrary implements Serializable {
         this.markerLoginName = markerLoginName;
     }
 
+    public Integer getUnansweredCount() {
+        return unansweredCount;
+    }
+
+    public void setUnansweredCount(Integer unansweredCount) {
+        this.unansweredCount = unansweredCount;
+    }
+
 }

+ 14 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/TrialTrack.java

@@ -65,6 +65,12 @@ public class TrialTrack {
     @Column(name = "offset_y", nullable = false)
     private Integer offsetY;
 
+    /**
+     * 是否未作答
+     */
+    @Column(name = "unanswered", nullable = false)
+    private boolean unanswered;
+
     public TrialTrack() {
         this.pk = new TrialTrackPK();
     }
@@ -180,4 +186,12 @@ public class TrialTrack {
     public void setOffsetY(Integer offsetY) {
         this.offsetY = offsetY;
     }
+
+    public boolean isUnanswered() {
+        return unanswered;
+    }
+
+    public void setUnanswered(boolean unanswered) {
+        this.unanswered = unanswered;
+    }
 }

+ 31 - 21
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/query/MarkLibrarySearchQuery.java

@@ -27,13 +27,13 @@ public class MarkLibrarySearchQuery extends BaseQuery<MarkLibrary> {
 
     private int markerId;
 
-    private int groupNumber;
+    private Integer groupNumber;
 
     private Double markerScore;
 
-    private Double startScroe;
+    private Double startScore;
 
-    private Double endScroe;
+    private Double endScore;
 
     private boolean unselective;
 
@@ -41,6 +41,8 @@ public class MarkLibrarySearchQuery extends BaseQuery<MarkLibrary> {
 
     private Integer headerId;
 
+    private String rejectReason;
+
     public MarkLibrarySearchQuery() {
         super();
         this.statusSet = new HashSet<>();
@@ -118,11 +120,11 @@ public class MarkLibrarySearchQuery extends BaseQuery<MarkLibrary> {
         this.campusId = campusId;
     }
 
-    public int getGroupNumber() {
+    public Integer getGroupNumber() {
         return groupNumber;
     }
 
-    public void setGroupNumber(int groupNumber) {
+    public void setGroupNumber(Integer groupNumber) {
         this.groupNumber = groupNumber;
     }
 
@@ -146,22 +148,6 @@ public class MarkLibrarySearchQuery extends BaseQuery<MarkLibrary> {
         this.markerScore = markerScore;
     }
 
-    public Double getStartScroe() {
-        return startScroe;
-    }
-
-    public void setStartScroe(Double startScroe) {
-        this.startScroe = startScroe;
-    }
-
-    public Double getEndScroe() {
-        return endScroe;
-    }
-
-    public void setEndScroe(Double endScroe) {
-        this.endScroe = endScroe;
-    }
-
     public boolean isUnselective() {
         return unselective;
     }
@@ -186,4 +172,28 @@ public class MarkLibrarySearchQuery extends BaseQuery<MarkLibrary> {
         this.headerId = headerId;
     }
 
+    public Double getStartScore() {
+        return startScore;
+    }
+
+    public void setStartScore(Double startScore) {
+        this.startScore = startScore;
+    }
+
+    public Double getEndScore() {
+        return endScore;
+    }
+
+    public void setEndScore(Double endScore) {
+        this.endScore = endScore;
+    }
+
+    public String getRejectReason() {
+        return rejectReason;
+    }
+
+    public void setRejectReason(String rejectReason) {
+        this.rejectReason = rejectReason;
+    }
+
 }

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

@@ -108,7 +108,7 @@ public class MarkLibraryServiceImpl extends BaseQueryService<MarkLibrary> implem
                 if (query.getCampusId() > 0) {
                     predicates.add(cb.equal(root.get("campusId"), query.getCampusId()));
                 }
-                if (query.getGroupNumber() > 0) {
+                if (query.getGroupNumber() != null) {
                     predicates.add(cb.equal(root.get("groupNumber"), query.getGroupNumber()));
                 }
                 if (StringUtils.isNotBlank(query.getExamNumber())) {
@@ -133,17 +133,17 @@ public class MarkLibraryServiceImpl extends BaseQueryService<MarkLibrary> implem
                 if (query.getMarkerScore() != null) {
                     predicates.add(cb.equal(root.get("markerScore"), query.getMarkerScore()));
                 }
-                if (query.getStartScroe() != null) {
-                    Predicate predicate1 = cb.ge(root.get("markerScore"), query.getStartScroe());
+                if (query.getStartScore() != null) {
+                    Predicate predicate1 = cb.ge(root.get("markerScore"), query.getStartScore());
                     predicates.add(predicate1);
                 }
-                if (query.getEndScroe() != null) {
-                    Predicate predicate2 = cb.le(root.get("markerScore"), query.getEndScroe());
+                if (query.getEndScore() != null) {
+                    Predicate predicate2 = cb.le(root.get("markerScore"), query.getEndScore());
                     predicates.add(predicate2);
                 }
-                if (query.getMarkerScore() != null && query.getStartScroe() != null) {
-                    Predicate predicate1 = cb.ge(root.get("markerScore"), query.getStartScroe());
-                    Predicate predicate2 = cb.le(root.get("markerScore"), query.getEndScroe());
+                if (query.getMarkerScore() != null && query.getStartScore() != null) {
+                    Predicate predicate1 = cb.ge(root.get("markerScore"), query.getStartScore());
+                    Predicate predicate2 = cb.le(root.get("markerScore"), query.getEndScore());
                     predicates.add(cb.and(predicate1, predicate2));
                 }
                 if (query.isUnselective()) {
@@ -156,11 +156,15 @@ public class MarkLibraryServiceImpl extends BaseQueryService<MarkLibrary> implem
                             query.getQuestionScore() + ",%");
                     Predicate predicate2 = cb.like(root.get("markerScoreList").as(String.class),
                             "%," + query.getQuestionScore());
-                    predicates.add(cb.or(predicate1, predicate2));
+                    Predicate predicate3 = cb.equal(root.get("markerScoreList"), query.getQuestionScore());
+                    predicates.add(cb.or(predicate1, predicate2, predicate3));
                 }
                 if (query.getHeaderId() != null) {
                     predicates.add(cb.equal(root.get("headerId"), query.getHeaderId()));
                 }
+                if (StringUtils.isNotBlank(query.getRejectReason())) {
+                    predicates.add(cb.like(root.get("rejectReason").as(String.class), query.getRejectReason() + ":%"));
+                }
                 return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
                         .size()]));
             }
@@ -239,4 +243,10 @@ public class MarkLibraryServiceImpl extends BaseQueryService<MarkLibrary> implem
         return libraryDao.countFilterClass(examId, subjectCode, groupNumber, userId);
     }
 
+    @Override
+    public long countMarkedByExamAndSubjectAndGroupAndFilterClass(Integer examId, String subjectCode,
+            Integer groupNumber, Integer userId, LibraryStatus... status) {
+        return libraryDao.countMarkedFilterClass(examId, subjectCode, groupNumber, userId, status);
+    }
+
 }

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 409 - 204
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkServiceImpl.java


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

@@ -1,8 +1,11 @@
 package cn.com.qmth.stmms.biz.mark.service.Impl;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
@@ -15,12 +18,15 @@ 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.SelectiveGroup;
 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.exam.service.SelectiveGroupService;
+import cn.com.qmth.stmms.biz.exam.service.SubjectiveScoreService;
 import cn.com.qmth.stmms.biz.file.service.FileService;
 import cn.com.qmth.stmms.biz.mark.model.ArbitrateHistory;
 import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
@@ -94,6 +100,12 @@ public class TaskServiceImpl implements TaskService {
     @Autowired
     private ExamService examService;
 
+    @Autowired
+    private SubjectiveScoreService scoreService;
+
+    @Autowired
+    private SelectiveGroupService selectiveGroupService;
+
     @Override
     public List<Task> findByQuery(MarkLibrarySearchQuery query) {
         List<Task> list = new LinkedList<Task>();
@@ -193,6 +205,7 @@ public class TaskServiceImpl implements TaskService {
         task.setMarkerTime(library.getMarkerTime());
         if (library.getStatus() == LibraryStatus.REJECTED) {
             task.setRejected(true);
+            task.setRejectReason(library.getRejectReason());
         }
         if (library.getStatus() == LibraryStatus.MARKED || library.getStatus() == LibraryStatus.INSPECTED) {
             task.setMarkerScore(library.getMarkerScore());
@@ -313,6 +326,8 @@ public class TaskServiceImpl implements TaskService {
         step.setMaxScore(question.getTotalScore());
         step.setMinScore(0d);
         step.setIntervalScore(question.getIntervalScore());
+        step.setUncalculate(false);
+        step.setSelectiveIndex(question.getSelectiveIndex());
         return step;
     }
 
@@ -409,12 +424,25 @@ public class TaskServiceImpl implements TaskService {
         List<MarkStepDTO> list = new LinkedList<MarkStepDTO>();
         List<ExamQuestion> sList = questionService.findByExamAndSubjectAndObjective(student.getExamId(),
                 student.getSubjectCode(), false);
+        Set<Integer> mainList = scoreService.findMainNumberByStudentIdAndUncalculate(student.getId(), true);
+        List<SelectiveGroup> selectiveGroups = selectiveGroupService.findByExamIdAndSubjectCode(student.getExamId(),
+                student.getSubjectCode());
+        Map<Integer, SelectiveGroup> map = new HashMap<Integer, SelectiveGroup>();
+        for (SelectiveGroup selectiveGroup : selectiveGroups) {
+            map.put(selectiveGroup.getMainNumber(), selectiveGroup);
+        }
         List<ScoreItem> sItems = student.getScoreList(false);
         for (int i = 0; i < sList.size(); i++) {
             ExamQuestion question = sList.get(i);
+            if (map.containsKey(question.getMainNumber())) {
+                question.setSelectiveIndex(map.get(question.getMainNumber()).getSelectiveIndex());
+            }
             MarkStepDTO step = buildStep(question);
             if (!sItems.isEmpty() && sItems.size() == sList.size()) {
                 step.setScore(sItems.get(i).getScore());
+                if (mainList.contains(step.getMainNumber())) {
+                    step.setUncalculate(true);
+                }
             }
             // 增加阅卷轨迹列表获取
             if (trialGroupCount > 0) {

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

@@ -156,4 +156,9 @@ public class TrialServiceImpl extends BaseQueryService<TrialLibrary> implements
     public List<TrialTag> findTagByStudentId(Integer studentId) {
         return tagDao.findByStudentIdOrderByIdAsc(studentId);
     }
+
+    @Override
+    public long countMarkedLibrary(Integer examId, String subjectCode, Integer groupNumber) {
+        return libraryDao.countMarked(examId, subjectCode, groupNumber);
+    }
 }

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

@@ -49,4 +49,7 @@ public interface MarkLibraryService {
     long countByExamAndSubjectAndGroupAndFilterClass(Integer examId, String subjectCode, Integer groupNumber,
             Integer userId);
 
+    long countMarkedByExamAndSubjectAndGroupAndFilterClass(Integer examId, String subjectCode, Integer groupNumber,
+            Integer userId, LibraryStatus... status);
+
 }

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

@@ -133,7 +133,7 @@ public interface MarkService {
      * @param library
      * @return
      */
-    boolean rejectLibrary(MarkLibrary library, Integer userId, boolean isRest);
+    boolean rejectLibrary(MarkLibrary library, Integer userId, String reason, boolean isRest);
 
     /**
      * 更新某个大题已评任务数量
@@ -237,7 +237,8 @@ public interface MarkService {
      * @param library
      * @return
      */
-    boolean backStudentByGroup(ExamStudent student, Integer groupNumber, Integer userId);
+    // boolean backStudentByGroup(ExamStudent student, Integer groupNumber,
+    // Integer userId);
 
     /**
      * 管理员/组长打回某个学生的指定题目
@@ -245,9 +246,10 @@ public interface MarkService {
      * @param student
      * @param questionList
      * @param userId
+     * @param resson
      * @return
      */
-    boolean rejectedStudent(ExamStudent student, MarkStepDTO[] questionList, Integer userId);
+    boolean rejectedStudent(ExamStudent student, MarkStepDTO[] questionList, Integer userId, String reason);
 
     /**
      * 删除某个小题
@@ -264,5 +266,5 @@ public interface MarkService {
      * @param userId
      * @return
      */
-    boolean rejectLibrary(MarkLibrary library, MarkStepDTO[] questionList, Integer userId);
+    boolean rejectLibrary(MarkLibrary library, MarkStepDTO[] questionList, Integer userId, String reason);
 }

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

@@ -36,4 +36,6 @@ public interface TrialService {
     List<TrialLibrary> findHistory(Integer examId, String subjectCode, Integer groupNumber, Integer markerId,
             String secretNumber, int pageNumber, int pageSize, Sort querySort);
 
+    long countMarkedLibrary(Integer examId, String subjectCode, Integer groupNumber);
+
 }

+ 23 - 7
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectClass.java

@@ -106,6 +106,20 @@ public class ReportSubjectClass implements Serializable {
     @Column(name = "avg_score")
     private Double avgScore;
 
+    /**
+     * 报考人数
+     */
+    @ExcelField(title = "报考人数", align = 2, sort = 110)
+    @Column(name = "total_count")
+    private Integer totalCount;
+
+    /**
+     * 有效人数
+     */
+    @ExcelField(title = "有效人数", align = 2, sort = 120)
+    @Column(name = "reality_count")
+    private Integer realityCount;
+
     /**
      * 差异系数
      */
@@ -145,15 +159,9 @@ public class ReportSubjectClass implements Serializable {
     /**
      * 一分一段分段统计
      */
-    @Column(name = "score_range", nullable = true,columnDefinition = "text")
+    @Column(name = "score_range", nullable = true, columnDefinition = "text")
     private String scoreRange;
 
-    /**
-     * 有效人数
-     */
-    @Column(name = "reality_count")
-    private Integer realityCount;
-
     public Integer getId() {
         return id;
     }
@@ -314,4 +322,12 @@ public class ReportSubjectClass implements Serializable {
         this.realityCount = realityCount;
     }
 
+    public Integer getTotalCount() {
+        return totalCount;
+    }
+
+    public void setTotalCount(Integer totalCount) {
+        this.totalCount = totalCount;
+    }
+
 }

+ 30 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectCollege.java

@@ -106,6 +106,20 @@ public class ReportSubjectCollege implements Serializable {
     @Column(name = "excellent_count")
     private Integer excellentCount;
 
+    /**
+     * 报考人数
+     */
+    @ExcelField(title = "报考人数", align = 2, sort = 110)
+    @Column(name = "total_count")
+    private Integer totalCount;
+
+    /**
+     * 有效人数
+     */
+    @ExcelField(title = "有效人数", align = 2, sort = 120)
+    @Column(name = "reality_count")
+    private Integer realityCount;
+
     public Integer getId() {
         return id;
     }
@@ -202,4 +216,20 @@ public class ReportSubjectCollege implements Serializable {
         this.excellentCount = excellentCount;
     }
 
+    public Integer getTotalCount() {
+        return totalCount;
+    }
+
+    public void setTotalCount(Integer totalCount) {
+        this.totalCount = totalCount;
+    }
+
+    public Integer getRealityCount() {
+        return realityCount;
+    }
+
+    public void setRealityCount(Integer realityCount) {
+        this.realityCount = realityCount;
+    }
+
 }

+ 34 - 15
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/report/model/ReportSubjectTeacher.java

@@ -57,69 +57,76 @@ public class ReportSubjectTeacher implements Serializable {
     @Column(name = "teacher_name")
     private String teacherName;
 
-    /**
-     * 有效人数
-     */
-    @ExcelField(title = "有效人数", align = 2, sort = 40)
-    @Column(name = "reality_count")
-    private int realityCount;
-
     /**
      * 最高分
      */
-    @ExcelField(title = "最高分", align = 2, sort = 50)
+    @ExcelField(title = "最高分", align = 2, sort = 40)
     @Column(name = "max_score")
     private Double maxScore;
 
     /**
      * 最低分
      */
-    @ExcelField(title = "最低分", align = 2, sort = 60)
+    @ExcelField(title = "最低分", align = 2, sort = 50)
     @Column(name = "min_score")
     private Double minScore;
 
     /**
      * 及格人数
      */
-    @ExcelField(title = "及格人数", align = 2, sort = 70)
+    @ExcelField(title = "及格人数", align = 2, sort = 60)
     @Column(name = "pass_count")
     private int passCount;
 
     /**
      * 及格率
      */
-    @ExcelField(title = "及格率", align = 2, sort = 80)
+    @ExcelField(title = "及格率", align = 2, sort = 70)
     @Column(name = "pass_rate")
     private Double passRate;
 
     /**
      * 优秀数
      */
-    @ExcelField(title = "优秀人数", align = 2, sort = 90)
+    @ExcelField(title = "优秀人数", align = 2, sort = 80)
     @Column(name = "excellent_count")
     private int excellentCount;
 
     /**
      * 优秀率
      */
-    @ExcelField(title = "优秀率", align = 2, sort = 100)
+    @ExcelField(title = "优秀率", align = 2, sort = 90)
     @Column(name = "excellent_rate")
     private Double excellentRate;
 
     /**
      * 平均分
      */
-    @ExcelField(title = "平均分", align = 2, sort = 110)
+    @ExcelField(title = "平均分", align = 2, sort = 100)
     @Column(name = "avg_score")
     private Double avgScore;
 
     /**
      * 平均相对分
      */
-    @ExcelField(title = "平均相对分", align = 2, sort = 120)
+    @ExcelField(title = "平均相对分", align = 2, sort = 110)
     @Column(name = "relative_avg_score")
     private Double relativeAvgScore;
 
+    /**
+     * 报考人数
+     */
+    @ExcelField(title = "报考人数", align = 2, sort = 120)
+    @Column(name = "total_count")
+    private Integer totalCount;
+
+    /**
+     * 有效人数
+     */
+    @ExcelField(title = "有效人数", align = 2, sort = 130)
+    @Column(name = "reality_count")
+    private Integer realityCount;
+
     public Integer getId() {
         return id;
     }
@@ -232,4 +239,16 @@ public class ReportSubjectTeacher implements Serializable {
         this.relativeAvgScore = relativeAvgScore;
     }
 
+    public Integer getTotalCount() {
+        return totalCount;
+    }
+
+    public void setTotalCount(Integer totalCount) {
+        this.totalCount = totalCount;
+    }
+
+    public void setRealityCount(Integer realityCount) {
+        this.realityCount = realityCount;
+    }
+
 }

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

@@ -8,6 +8,7 @@ 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.BaseCalculatorUnit;
+import cn.com.qmth.stmms.biz.report.utils.unit.BaseCounter;
 import cn.com.qmth.stmms.biz.utils.SpringContextHolder;
 
 public class SubjectClassModule extends SubjectModule implements Module {
@@ -28,6 +29,7 @@ public class SubjectClassModule extends SubjectModule implements Module {
                 String subjectCode = s[0];
                 String className = s[1];
                 BaseCalculatorUnit unit = units.get(key);
+                BaseCounter counter = counters.get(key);
                 ReportSubjectClass r = new ReportSubjectClass();
                 r.setExamId(this.context.getExamId());
                 r.setSubjectCode(subjectCode);
@@ -43,7 +45,8 @@ public class SubjectClassModule extends SubjectModule implements Module {
                 r.setCoefficient(unit.coefficient);
                 r.setDifficulty(unit.difficulty);
                 r.setStdev(unit.stdev);
-                r.setRealityCount(this.counters.get(key).realityCount);
+                r.setTotalCount(counter.totalCount);
+                r.setRealityCount(counter.realityCount);
                 service.save(r);
             }
         }

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

@@ -8,6 +8,7 @@ import cn.com.qmth.stmms.biz.report.service.ReportSubjectCollegeService;
 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.BaseCalculatorUnit;
+import cn.com.qmth.stmms.biz.report.utils.unit.BaseCounter;
 import cn.com.qmth.stmms.biz.utils.SpringContextHolder;
 
 public class SubjectCollegeModule extends SubjectModule implements Module {
@@ -28,6 +29,7 @@ public class SubjectCollegeModule extends SubjectModule implements Module {
                 String subjectCode = s[0];
                 String collegeName = s[1];
                 BaseCalculatorUnit unit = units.get(key);
+                BaseCounter counter = counters.get(key);
                 ReportSubjectCollege r = new ReportSubjectCollege();
                 r.setExamId(this.context.getExamId());
                 r.setSubjectCode(subjectCode);
@@ -40,6 +42,8 @@ public class SubjectCollegeModule extends SubjectModule implements Module {
                 r.setPassRate(unit.passRate);
                 r.setExcellentCount(unit.excellentCount);
                 r.setExcellentRate(unit.excellentRate);
+                r.setTotalCount(counter.totalCount);
+                r.setRealityCount(counter.realityCount);
                 service.save(r);
             }
         }

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

@@ -104,16 +104,17 @@ public class SubjectModule implements Module {
         BaseCalculatorUnit unit = units.get(key);
         if (unit == null) {
             unit = new BaseCalculatorUnit();
-            unit.passScore = context.getPassScore();
-            unit.excellentScore = context.getExcellentScore();
-
             String keys[] = key.split("\t");
             ExamSubject subject = context.getSubject(keys[0]);
+
+            unit.passScore = subject.getTotalScore() * context.getPassScore() * 0.01;
+            unit.excellentScore = subject.getTotalScore() * context.getExcellentScore() * 0.01;
+
             if (subject != null && subject.getPassScore() != null) {
-                unit.passScore = subject.getPassScore();
+                unit.passScore = subject.getTotalScore() * subject.getPassScore() * 0.01;
             }
             if (subject != null && subject.getExcellentScore() != null) {
-                unit.excellentScore = subject.getExcellentScore();
+                unit.excellentScore = subject.getTotalScore() * subject.getExcellentScore() * 0.01;
             }
             units.put(key, unit);
         }

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

@@ -37,6 +37,7 @@ public class SubjectTeacherModule extends SubjectModule implements Module {
                 subject.setSubjectName(context.getSubject(subjectCode).getName());
                 subject.setTeacherName(teacherName);
                 subject.setRealityCount(counter.realityCount);
+                subject.setTotalCount(counter.totalCount);
                 subject.setPassCount(unit.passCount);
                 subject.setExcellentCount(unit.excellentCount);
                 subject.setMaxScore(unit.maxScore);

+ 6 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/dao/UserDao.java

@@ -1,6 +1,9 @@
 package cn.com.qmth.stmms.biz.user.dao;
 
+import java.util.List;
+
 import cn.com.qmth.stmms.biz.user.model.User;
+
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.PagingAndSortingRepository;
@@ -13,4 +16,7 @@ public interface UserDao extends PagingAndSortingRepository<User, Integer>, JpaS
 
     @Query(value = "select u from User u where u.id=(select m.userId from Marker m where m.id=?1)")
     User findByMarkerId(Integer markerId);
+
+    @Query(value = "select u from User u where u.loginName like ?1" + "%")
+    List<User> findStartWithLoginName(String loginName);
 }

+ 62 - 4
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/model/User.java

@@ -1,13 +1,23 @@
 package cn.com.qmth.stmms.biz.user.model;
 
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import cn.com.qmth.stmms.common.annotation.ExcelField;
 import cn.com.qmth.stmms.common.enums.Role;
 import cn.com.qmth.stmms.common.enums.UserSource;
 import cn.com.qmth.stmms.common.utils.AccessControlUtils;
 
-import javax.persistence.*;
-import java.io.Serializable;
-import java.util.Date;
-
 @Entity
 @Table(name = "b_user")
 public class User implements Serializable {
@@ -26,12 +36,14 @@ public class User implements Serializable {
     /**
      * 登录名
      */
+    @ExcelField(title = "登录名", align = 2, sort = 10)
     @Column(name = "login_name", length = 64, nullable = false)
     private String loginName;
 
     /**
      * 名称
      */
+    @ExcelField(title = "名称", align = 2, sort = 20)
     @Column(name = "name", length = 64, nullable = false)
     private String name;
 
@@ -103,6 +115,19 @@ public class User implements Serializable {
     @Column(name = "access_token_refresh_time", nullable = true)
     private Date accessTokenRefreshTime;
 
+    @Column(name = "scan_token", length = 64, nullable = true)
+    private String scanToken;
+
+    @Column(name = "scan_token_invalid_time", nullable = true)
+    private Date scanTokenInvalidTime;
+
+    @Column(name = "description", length = 128, nullable = true)
+    private String description;
+
+    @ExcelField(title = "角色", align = 2, sort = 30)
+    @Transient
+    private String roleName;
+
     public Integer getId() {
         return id;
     }
@@ -223,4 +248,37 @@ public class User implements Serializable {
     public String getAccount() {
         return source == UserSource.INTERNAL ? loginName : relatedAccount;
     }
+
+    public String getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
+
+    public String getScanToken() {
+        return scanToken;
+    }
+
+    public Date getScanTokenInvalidTime() {
+        return scanTokenInvalidTime;
+    }
+
+    public void refreshScanToken() {
+        this.scanToken = AccessControlUtils.randomString();
+        Calendar rightNow = Calendar.getInstance();
+        rightNow.setTime(new Date());
+        rightNow.add(Calendar.DAY_OF_YEAR, +2);
+        this.scanTokenInvalidTime = rightNow.getTime();
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
 }

+ 10 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/service/UserService.java

@@ -1,5 +1,7 @@
 package cn.com.qmth.stmms.biz.user.service;
 
+import java.util.Set;
+
 import cn.com.qmth.stmms.biz.user.model.User;
 import cn.com.qmth.stmms.biz.user.service.query.UserSearchQuery;
 import cn.com.qmth.stmms.common.enums.Role;
@@ -26,4 +28,12 @@ public interface UserService {
 
     User externalSaveAndUpdate(Integer schoolId, String account, String name, String password, Role role);
 
+    User findByAccount(Integer schoolId, String account);
+
+    void batchSaveMarker(int examId, Set<String> subjectCodes, Integer number, String password);
+
+    void batchSaveSubjectUser(int examId, Role role, Set<String> subjectCodes, Integer number, String password);
+
+    public int findMaxNumberByLoginNameStart(String prefix);
+
 }

+ 222 - 16
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/service/impl/UserServiceImpl.java

@@ -1,12 +1,15 @@
 package cn.com.qmth.stmms.biz.user.service.impl;
 
-import cn.com.qmth.stmms.biz.user.dao.UserDao;
-import cn.com.qmth.stmms.biz.user.model.User;
-import cn.com.qmth.stmms.biz.user.service.UserService;
-import cn.com.qmth.stmms.biz.user.service.query.UserSearchQuery;
-import cn.com.qmth.stmms.common.enums.Role;
-import cn.com.qmth.stmms.common.enums.UserSource;
-import cn.com.qmth.stmms.common.utils.EncryptUtils;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
 
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -16,14 +19,24 @@ import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.persistence.criteria.CriteriaBuilder;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
-
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
+import cn.com.qmth.stmms.biz.exam.model.Exam;
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.biz.exam.model.SubjectUser;
+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.exam.service.SubjectUserService;
+import cn.com.qmth.stmms.biz.user.dao.UserDao;
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.biz.user.service.UserService;
+import cn.com.qmth.stmms.biz.user.service.query.UserSearchQuery;
+import cn.com.qmth.stmms.common.enums.Role;
+import cn.com.qmth.stmms.common.enums.UserSource;
+import cn.com.qmth.stmms.common.utils.EncryptUtils;
 
 /**
  * 用户Service
@@ -33,9 +46,29 @@ import java.util.List;
 @Service("userService")
 public class UserServiceImpl implements UserService {
 
+    public static final String USER_PASSWORD = "123456";
+
     @Autowired
     private UserDao userDao;
 
+    @Autowired
+    private SubjectUserService subjectUserService;
+
+    @Autowired
+    private MarkerService markerService;
+
+    @Autowired
+    private ExamService examService;
+
+    @Autowired
+    private MarkGroupService groupService;
+
+    @Autowired
+    private ExamSubjectService subjectService;
+
+    @Autowired
+    private ExamStudentService studentService;
+
     @Override
     @Transactional
     public User save(User user) {
@@ -98,7 +131,7 @@ public class UserServiceImpl implements UserService {
             query.setPageNumber(1);
         }
         if (query.getPageSize() < 1) {
-            query.setPageSize(10);
+            query.setPageSize(20);
         }
 
         Page<User> result = userDao.findAll(new Specification<User>() {
@@ -196,4 +229,177 @@ public class UserServiceImpl implements UserService {
         return userDao.save(user);
     }
 
+    @Override
+    public User findByAccount(Integer schoolId, String account) {
+        return userDao.findFirstBySchoolIdAndRelatedAccount(schoolId, account);
+    }
+
+    @Transactional
+    @Override
+    public void batchSaveMarker(int examId, Set<String> subjectCodes, Integer number, String password) {
+        if (subjectCodes.size() == 0) {
+            List<ExamSubject> subjects = subjectService.list(examId);
+            for (ExamSubject subject : subjects) {
+                saveMarkerBySubject(examId, number, password, subject.getCode());
+            }
+        } else {
+            for (String subjectCode : subjectCodes) {
+                saveMarkerBySubject(examId, number, password, subjectCode);
+            }
+        }
+
+    }
+
+    private void saveMarkerBySubject(int examId, Integer number, String password, String subjectCode) {
+        Exam exam = examService.findById(examId);
+        List<MarkGroup> groups = groupService.findByExamAndSubject(examId, subjectCode);
+        for (MarkGroup group : groups) {
+            List<Marker> saveList = new ArrayList<Marker>();
+            String prefix = exam.getSchoolId() + "-" + subjectCode + "-" + group.getNumber();
+            int maxNumber = this.findMaxNumberByLoginNameStart(prefix);
+            int createNumber = 1;
+            while (saveList.size() < number) {
+                String loginName = prefix + "-" + (maxNumber + createNumber);
+                User user = userDao.findFirstByLoginName(loginName);
+                if (user == null) {
+                    user = new User();
+                    user.setLoginName(loginName);
+                    user.setName(loginName);
+                    user.setRole(Role.MARKER);
+                    user.setSource(UserSource.INTERNAL);
+                    user.setEnable(true);
+                    user.setSchoolId(exam.getSchoolId());
+                    user.setCreatedTime(new Date());
+                    if (StringUtils.isNotBlank(password)) {
+                        user.setPassword(EncryptUtils.md5(password));
+                    } else {
+                        user.setPassword(EncryptUtils.md5(USER_PASSWORD));
+                    }
+                    userDao.save(user);
+                    Marker marker = new Marker();
+                    marker.setSubjectCode(subjectCode);
+                    marker.setGroupNumber(group.getNumber());
+                    marker.setUserId(user.getId());
+                    marker.setExamId(examId);
+                    marker.setEnable(true);
+                    saveList.add(marker);
+                }
+                createNumber++;
+            }
+            markerService.batchSave(saveList);
+        }
+    }
+
+    @Transactional
+    @Override
+    public void batchSaveSubjectUser(int examId, Role role, Set<String> subjectCodes, Integer number, String password) {
+        if (subjectCodes.size() == 0) {
+            List<ExamSubject> subjects = subjectService.list(examId);
+            for (ExamSubject subject : subjects) {
+                saveSubjectUserBySubject(examId, number, role, subject.getCode(), password);
+            }
+        } else {
+            for (String subjectCode : subjectCodes) {
+                saveSubjectUserBySubject(examId, number, role, subjectCode, password);
+            }
+        }
+    }
+
+    private void saveSubjectUserBySubject(int examId, Integer number, Role role, String subjectCode, String password) {
+        Exam exam = examService.findById(examId);
+        List<SubjectUser> saveList = new ArrayList<SubjectUser>();
+        int createNumber = 1;
+        String prefix = exam.getSchoolId() + "-" + subjectCode;
+        if (role.equals(Role.INSPECTOR)) {
+            prefix = exam.getSchoolId() + "-FH-" + subjectCode;
+        }
+        int maxNumber = this.findMaxNumberByLoginNameStart(prefix);
+        while (saveList.size() < number) {
+            String loginName = prefix + "-" + (maxNumber + createNumber);
+            User user = userDao.findFirstByLoginName(loginName);
+            if (user == null) {
+                user = new User();
+                user.setLoginName(loginName);
+                user.setName(loginName);
+                if (StringUtils.isNotBlank(password)) {
+                    user.setPassword(EncryptUtils.md5(password));
+                } else {
+                    user.setPassword(EncryptUtils.md5(USER_PASSWORD));
+                }
+                user.setRole(role);
+                user.setSource(UserSource.INTERNAL);
+                user.setEnable(true);
+                user.setSchoolId(exam.getSchoolId());
+                user.setCreatedTime(new Date());
+                user = userDao.save(user);
+                SubjectUser subjectUser = new SubjectUser();
+                subjectUser.setSubjectCode(subjectCode);
+                subjectUser.setUserId(user.getId());
+                saveList.add(subjectUser);
+            }
+            createNumber++;
+        }
+        subjectUserService.batchSave(saveList);
+    }
+
+    // @Override
+    // public void batchSaveCollegeUser(int examId, Integer number) {
+    // Exam exam = examService.findById(examId);
+    // List<String> collegeList = studentService.findDistinctCollege(examId);
+    // List<SubjectUser> saveList = new ArrayList<SubjectUser>();
+    // for (String college : collegeList) {
+    // List<String> subjectList =
+    // studentService.findDistinctSubjectCodeByCollege(examId, college);
+    // for (int i = 0; i < number; i++) {
+    // String prefix = exam.getSchoolId() + "-XY-";
+    // int maxNumber = this.findMaxNumberByLoginNameStart(prefix);
+    // String loginName = prefix + "-" + (maxNumber + i + 1);
+    // User user = userDao.findFirstByLoginName(loginName);
+    // if (user == null) {
+    // user = new User();
+    // user.setLoginName(loginName);
+    // user.setName(loginName);
+    // user.setPassword(EncryptUtils.md5(USER_PASSWORD));
+    // user.setRole(Role.COLLEGE_ADMIN);
+    // user.setSource(UserSource.INTERNAL);
+    // user.setEnable(true);
+    // user.setSchoolId(exam.getSchoolId());
+    // user.setCreatedTime(new Date());
+    // userDao.save(user);
+    // }
+    // for (String subjectCode : subjectList) {
+    // SubjectUser subjectUser =
+    // subjectUserService.findBySubjectCodeAndUserId(subjectCode, user.getId());
+    // if (subjectUser == null) {
+    // subjectUser = new SubjectUser();
+    // subjectUser.setSubjectCode(subjectCode);
+    // subjectUser.setUserId(user.getId());
+    // saveList.add(subjectUser);
+    // }
+    // }
+    // subjectUserService.batchSave(saveList);
+    // }
+    // }
+    //
+    // }
+
+    @Override
+    public int findMaxNumberByLoginNameStart(String prefix) {
+        List<User> list = userDao.findStartWithLoginName(prefix);
+        int number = 0;
+        for (User user : list) {
+            try {
+                String userNumber = user.getLoginName()
+                        .substring(prefix.length() + 1, user.getLoginName().length() - 1);
+                int no = Integer.parseInt(userNumber);
+                if (number < no) {
+                    number = no;
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return number;
+    }
+
 }

+ 7 - 7
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/OriginTag.java

@@ -6,15 +6,15 @@ public class OriginTag {
 
     private int offsetIndex;
 
-    private int offsetX;
+    private double offsetX;
 
-    private int offsetY;
+    private double offsetY;
 
     public OriginTag() {
 
     }
 
-    public OriginTag(String content, int offsetIndex, int offsetX, int offsetY) {
+    public OriginTag(String content, int offsetIndex, double offsetX, double offsetY) {
         this.content = content;
         this.offsetIndex = offsetIndex;
         this.offsetX = offsetX;
@@ -37,19 +37,19 @@ public class OriginTag {
         this.offsetIndex = offsetIndex;
     }
 
-    public int getOffsetX() {
+    public double getOffsetX() {
         return offsetX;
     }
 
-    public void setOffsetX(int offsetX) {
+    public void setOffsetX(double offsetX) {
         this.offsetX = offsetX;
     }
 
-    public int getOffsetY() {
+    public double getOffsetY() {
         return offsetY;
     }
 
-    public void setOffsetY(int offsetY) {
+    public void setOffsetY(double offsetY) {
         this.offsetY = offsetY;
     }
 }

+ 20 - 13
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/PictureConfigTransform.java

@@ -19,26 +19,28 @@ public class PictureConfigTransform {
     /**
      * 转换方法
      *
-     * @param sliceConfigs - 裁切图配置
-     * @param groups       - 评卷分组与原始元素列表
+     * @param sliceConfigs
+     *            - 裁切图配置
+     * @param groups
+     *            - 评卷分组与原始元素列表
      * @return 原图序号与新的显示元素列表,序号从1开始
      */
     public static Map<Integer, List<PictureTag>> process(List<PictureConfigItem> sliceConfigs,
             Map<MarkGroup, List<OriginTag>> groups) {
         Map<Integer, List<PictureTag>> map = new HashMap<>();
-        //不判断裁切坐标是否空白,兼容新的原图遮盖模式
+        // 不判断裁切坐标是否空白,兼容新的原图遮盖模式
         int sliceCount = sliceConfigs.size();
         for (Entry<MarkGroup, List<OriginTag>> entry : groups.entrySet()) {
             // 遍历所有显示元素
             for (OriginTag tag : entry.getValue()) {
                 if (tag.getOffsetIndex() > sliceCount) {
-                    //元素所属裁切图不在裁切坐标范围内,表示裁切图直接使用的原图
+                    // 元素所属裁切图不在裁切坐标范围内,表示裁切图直接使用的原图
                     buildTag(map, tag.getContent(), tag.getOffsetIndex(), tag.getOffsetX(), tag.getOffsetY());
                 } else {
-                    //有裁切坐标时,原图坐标=元素相对坐标+裁切坐标
+                    // 有裁切坐标时,原图坐标=元素相对坐标+裁切坐标
                     PictureConfigItem config = sliceConfigs.get(tag.getOffsetIndex() - 1);
-                    buildTag(map, tag.getContent(), config.getI(), config.getX() + tag.getOffsetX(),
-                            config.getY() + tag.getOffsetY());
+                    buildTag(map, tag.getContent(), config.getI(), config.getX() + tag.getOffsetX(), config.getY()
+                            + tag.getOffsetY());
                 }
             }
         }
@@ -48,13 +50,18 @@ public class PictureConfigTransform {
     /**
      * 根据计算出的拼接块,构造新的原图显示元素
      *
-     * @param tags    - 原图显示元素集合
-     * @param content - 显示元素内容
-     * @param index   - 所属原图序号
-     * @param left    - 在原图内的左偏移
-     * @param top     - 在原图内的上偏移
+     * @param tags
+     *            - 原图显示元素集合
+     * @param content
+     *            - 显示元素内容
+     * @param index
+     *            - 所属原图序号
+     * @param left
+     *            - 在原图内的左偏移
+     * @param top
+     *            - 在原图内的上偏移
      */
-    private static void buildTag(Map<Integer, List<PictureTag>> tags, String content, int index, int left, int top) {
+    private static void buildTag(Map<Integer, List<PictureTag>> tags, String content, int index, double left, double top) {
         PictureTag tag = new PictureTag();
         tag.setContent(content);
         tag.setLeft(left);

+ 6 - 6
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/PictureTag.java

@@ -6,9 +6,9 @@ public class PictureTag {
 
     private String[] content;
 
-    private int left;
+    private double left;
 
-    private int top;
+    private double top;
 
     private int size;
 
@@ -26,19 +26,19 @@ public class PictureTag {
         }
     }
 
-    public int getLeft() {
+    public double getLeft() {
         return left;
     }
 
-    public void setLeft(int left) {
+    public void setLeft(double left) {
         this.left = left;
     }
 
-    public int getTop() {
+    public double getTop() {
         return top;
     }
 
-    public void setTop(int top) {
+    public void setTop(double top) {
         this.top = top;
     }
 

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio