YuanPan 7 年之前
當前提交
d44a5092c2
共有 100 個文件被更改,包括 7066 次插入0 次删除
  1. 2 0
      .gitignore
  2. 25 0
      README.md
  3. 155 0
      pom.xml
  4. 26 0
      stmms-ms-accesscontrol/pom.xml
  5. 51 0
      stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/LoginInterceptor.java
  6. 80 0
      stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/api/AuthApi.java
  7. 37 0
      stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/config/AccessConfig.java
  8. 30 0
      stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/config/LoginConfig.java
  9. 35 0
      stmms-ms-admin/pom.xml
  10. 130 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/ScoreApi.java
  11. 122 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/StudentApi.java
  12. 91 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/UserApi.java
  13. 148 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/WorkApi.java
  14. 27 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/assembler/MarkUserAssembler.java
  15. 37 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/assembler/ScoreAssembler.java
  16. 85 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/assembler/WorkOverviewAssembler.java
  17. 75 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/MarkUserDTO.java
  18. 51 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/PaperCounter.java
  19. 24 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/ScoreCheckDTO.java
  20. 79 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/ScoreDTO.java
  21. 46 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/ScoreItem.java
  22. 86 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/StudentDTO.java
  23. 91 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/SubjectOverview.java
  24. 115 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/WorkOverview.java
  25. 52 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/exporter/ScoreExporter.java
  26. 47 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/exporter/UserExporter.java
  27. 46 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/exporter/WorkExporter.java
  28. 49 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/importer/StudentImporter.java
  29. 222 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/service/DataUploadService.java
  30. 58 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/service/WorkService.java
  31. 40 0
      stmms-ms-collect/pom.xml
  32. 164 0
      stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/api/CollectApi.java
  33. 59 0
      stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/api/ImageApi.java
  34. 81 0
      stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/dto/CollectStuDTO.java
  35. 52 0
      stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/dto/CollectSubjectDTO.java
  36. 47 0
      stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/dto/LoginDTO.java
  37. 38 0
      stmms-ms-commons/pom.xml
  38. 58 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/config/ImageCompressionConfig.java
  39. 46 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/config/ImageServerConfig.java
  40. 60 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/config/SystemConfig.java
  41. 60 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ColumnSetting.java
  42. 48 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelError.java
  43. 34 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelProperty.java
  44. 89 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelReader.java
  45. 7 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelReaderHandle.java
  46. 70 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelUtils.java
  47. 187 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelWriter.java
  48. 34 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExportUtils.java
  49. 63 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/image/ImageCompression.java
  50. 104 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/specification/PagingAndSortingDTO.java
  51. 74 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/specification/PagingAndSortingSpecification.java
  52. 16 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/specification/QuerySpecification.java
  53. 51 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/web/PageableDTO.java
  54. 24 0
      stmms-ms-commons/src/test/java/cn/com/qmth/stmms/ms/commons/image/ImageThumberTest.java
  55. 29 0
      stmms-ms-core/pom.xml
  56. 87 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/ExamQuestion.java
  57. 166 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Level.java
  58. 141 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/MarkLog.java
  59. 25 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/MarkStage.java
  60. 95 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/MarkSubject.java
  61. 325 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Paper.java
  62. 124 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Student.java
  63. 98 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Work.java
  64. 193 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/task/MarkTask.java
  65. 24 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/task/TaskStatus.java
  66. 124 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/AbstractUser.java
  67. 14 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/Admin.java
  68. 20 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/MarkRight.java
  69. 94 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/MarkUser.java
  70. 79 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/MarkerGroup.java
  71. 18 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/Role.java
  72. 25 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/ExamQuestionRepo.java
  73. 16 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/LevelRepo.java
  74. 12 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkLogRepo.java
  75. 11 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkSubjectRepo.java
  76. 90 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkTaskRepo.java
  77. 25 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkUserRepo.java
  78. 15 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkerGroupRepo.java
  79. 114 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/PaperRepo.java
  80. 22 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/StudentRepo.java
  81. 12 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/WorkRepo.java
  82. 95 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/specification/StudentSpecification.java
  83. 21 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/vo/Subject.java
  84. 32 0
      stmms-ms-log/pom.xml
  85. 125 0
      stmms-ms-log/src/main/java/cn/com/qmth/stmms/ms/log/MarkLogAop.java
  86. 46 0
      stmms-ms-log/src/main/resources/logback-spring.xml
  87. 55 0
      stmms-ms-main/pom.xml
  88. 18 0
      stmms-ms-main/src/main/java/cn/com/qmth/stmms/ms/Application.java
  89. 52 0
      stmms-ms-main/src/main/resources/application.properties
  90. 29 0
      stmms-ms-marking/pom.xml
  91. 35 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/ExamQuestionApi.java
  92. 146 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/MakrerApi.java
  93. 219 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/MarkSubjectApi.java
  94. 119 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/MarkTaskApi.java
  95. 230 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/PaperApi.java
  96. 34 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/LevelStatAssembler.java
  97. 48 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/MarkTaskAssembler.java
  98. 37 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/MarkerAssembler.java
  99. 54 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/PaperAssembler.java
  100. 45 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/QuestionStatAssembler.java

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/.idea
+/logs

+ 25 - 0
README.md

@@ -0,0 +1,25 @@
+#stmms-ms
+
+##core模块
+> 核心。domain、repository
+
+##admin模块
+> 管理模块,包括评卷工作管理、档位设定、用户管理、考生管理等
+
+##marking模块
+> 评卷模块,包括评卷科目阶段控制、分档及打分业务相关功能
+
+##accesscontrol模块
+> 访问控制,用户登录
+
+##commons模块
+> 公共模块,工具类等
+
+##log模块
+> 系统日志
+
+##collect模块
+> 采集后台管理
+
+##main模块
+> 应用入口及配置。打包可执行jar

+ 155 - 0
pom.xml

@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>cn.com.qmth</groupId>
+    <artifactId>stmms-ms-parent</artifactId>
+    <version>${project.version}</version>
+    <modules>
+        <module>stmms-ms-core</module>
+        <module>stmms-ms-main</module>
+        <module>stmms-ms-log</module>
+        <module>stmms-ms-marking</module>
+        <module>stmms-ms-admin</module>
+        <module>stmms-ms-commons</module>
+        <module>stmms-ms-accesscontrol</module>
+        <module>stmms-ms-collect</module>
+    </modules>
+    <packaging>pom</packaging>
+    <name>stmms-ms</name>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>1.4.0.RELEASE</version>
+    </parent>
+
+
+
+
+    <properties>
+        <!-- non-dependencies -->
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.version>2.4.0</project.version>
+        <java.version>1.8</java.version>
+        <thymeleaf.version>3.0.0.RELEASE</thymeleaf.version>
+        <thymeleaf-layout-dialect.version>2.0.0</thymeleaf-layout-dialect.version>
+        <mysql.version>5.1.21</mysql.version>
+        <poi.version>3.8</poi.version>
+        <!--反射工具类 -->
+        <reflectasm.version>1.11.3</reflectasm.version>
+        <!-- 图片压缩 -->
+        <thumbnailator.version>0.4.8</thumbnailator.version>
+        <!-- maven plugins -->
+        <maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
+        <maven-compiler-plugin.version>3.3</maven-compiler-plugin.version>
+    </properties>
+
+    <dependencyManagement>
+
+        <dependencies>
+        <!--modules -->
+            <dependency>
+                <groupId>cn.com.qmth</groupId>
+                <artifactId>stmms-ms-core</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.com.qmth</groupId>
+                <artifactId>stmms-ms-commons</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.com.qmth</groupId>
+                <artifactId>stmms-ms-accesscontrol</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.com.qmth</groupId>
+                <artifactId>stmms-ms-admin</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.com.qmth</groupId>
+                <artifactId>stmms-ms-marking</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.com.qmth</groupId>
+                <artifactId>stmms-ms-log</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>mysql</groupId>
+                <artifactId>mysql-connector-java</artifactId>
+                <version>${mysql.version}</version>
+            </dependency>
+
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>${poi.version}</version>
+        </dependency>
+            <!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
+            <dependency>
+                <groupId>net.sf.json-lib</groupId>
+                <artifactId>json-lib</artifactId>
+                <version>2.4</version>
+            </dependency>
+        <dependency>
+            <groupId>com.esotericsoftware</groupId>
+            <artifactId>reflectasm</artifactId>
+            <version>${reflectasm.version}</version>
+        </dependency>
+            <dependency>
+                <groupId>net.coobird</groupId>
+                <artifactId>thumbnailator</artifactId>
+                <version>${thumbnailator.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+            </plugin>
+
+        </plugins>
+
+        <pluginManagement>
+            <plugins>
+
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>${maven-surefire-plugin.version}</version>
+                    <configuration>
+                        <testFailureIgnore>true</testFailureIgnore>
+                    </configuration>
+                </plugin>
+
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>${maven-compiler-plugin.version}</version>
+                    <configuration>
+                        <source>1.8</source>
+                        <target>1.8</target>
+                        <compilerArgument>-proc:none</compilerArgument>
+                    </configuration>
+                </plugin>
+
+            </plugins>
+        </pluginManagement>
+    </build>
+
+</project>

+ 26 - 0
stmms-ms-accesscontrol/pom.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>stmms-ms-parent</artifactId>
+        <groupId>cn.com.qmth</groupId>
+        <version>${project.version}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>stmms-ms-accesscontrol</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-core</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>

+ 51 - 0
stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/LoginInterceptor.java

@@ -0,0 +1,51 @@
+package cn.com.qmth.stmms.ms.accesscontrol;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import cn.com.qmth.stmms.ms.accesscontrol.config.LoginConfig;
+import cn.com.qmth.stmms.ms.core.domain.user.AbstractUser;
+import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
+
+public class LoginInterceptor extends HandlerInterceptorAdapter {
+	
+    @Autowired
+    private MarkUserRepo markUserRepo;
+    
+    @Autowired
+    private LoginConfig loginConfig;
+
+	@Override
+	public boolean preHandle(HttpServletRequest request,
+			HttpServletResponse response, Object handler) throws Exception {
+		String token = (String) request.getSession().getAttribute("token");
+		if (token != null) {
+			String loginName = token.substring(14);
+			if(loginConfig.getLoginName().equals(loginName)){
+				return true;
+			}
+			AbstractUser user = markUserRepo.findByLoginName(loginName);
+			String sessionId = request.getSession().getId();
+			if(user.getSessionId().equalsIgnoreCase(sessionId)){
+				return true;
+			}
+		}
+		response.sendError(HttpStatus.UNAUTHORIZED.value(), "没有登录或会话超时");
+		return false;
+	}
+
+	public void postHandle(HttpServletRequest request,
+			HttpServletResponse response) throws Exception {
+
+	}
+
+	public void afterCompletion(HttpServletRequest request,
+			HttpServletResponse response, Object handler, Exception ex)
+			throws Exception {
+
+	}
+}

+ 80 - 0
stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/api/AuthApi.java

@@ -0,0 +1,80 @@
+package cn.com.qmth.stmms.ms.accesscontrol.api;
+
+import cn.com.qmth.stmms.ms.accesscontrol.config.LoginConfig;
+import cn.com.qmth.stmms.ms.core.domain.Work;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.domain.user.Role;
+import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
+
+import cn.com.qmth.stmms.ms.core.repository.WorkRepo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import java.util.Date;
+
+/**
+ * Created by zhengmin on 2016/11/1.
+ */
+@RestController
+public class AuthApi {
+
+    @Autowired
+    private LoginConfig loginConfig;
+
+    @Autowired
+    private MarkUserRepo markUserRepo;
+
+    @Autowired
+    private WorkRepo workRepo;
+
+    @RequestMapping(value = "login",method = RequestMethod.POST)
+    public MarkUser login(@RequestBody MarkUser user, HttpServletRequest request) {
+        MarkUser domain = null;
+        if(loginConfig.getLoginName().equals(user.getLoginName()) &&
+                loginConfig.getPassword().equals(user.getPassword())){
+            domain = new MarkUser(loginConfig.getLoginName(), loginConfig.getPassword(),null,null,"系统管理员", Role.ADMIN);
+        }else{
+            Work activeWork = workRepo.findByActiveTrue();
+            String loginName = activeWork.getId() + "-" + user.getLoginName();
+            domain = markUserRepo.findByLoginName(loginName);
+	        if (domain == null) {
+	            throw new RuntimeException("用户不存在");
+	        }
+	        if (!user.getPassword().equals(domain.getPassword())) {
+	            throw new RuntimeException("用户或密码错误");
+	        }
+	        if (!domain.isEnabled()) {
+	            throw new RuntimeException("用户被禁用");
+	        }
+	        domain.setSessionId(request.getSession().getId());
+	        markUserRepo.save(domain);
+        }
+        HttpSession session = request.getSession();
+        String token = (String) request.getSession().getAttribute("token");
+        if(!StringUtils.isEmpty(token)){
+        	session.setAttribute("token", null);
+        }
+        session.setAttribute("token", new Date().getTime() + "#" + domain.getLoginName());
+        return domain;
+    }
+
+    @RequestMapping(value = "/logout",method = RequestMethod.DELETE)
+    public void logout(HttpServletRequest request){
+        HttpSession session = request.getSession();
+        session.setAttribute("token", null);
+    }
+
+    @RequestMapping(value = "/{domain}/password", method = RequestMethod.PATCH)
+    public void pwd(@PathVariable MarkUser domain, @RequestBody MarkUser markUser) {
+        if(markUser.getPassword() == null || markUser.getPassword().length() < 6){
+            throw new RuntimeException("密码长度不能小于6位");
+        }
+        domain.setPassword(markUser.getPassword());
+        domain.setPwChangedCount(markUser.getPwChangedCount()+1);
+        markUserRepo.save(domain);
+    }
+}

+ 37 - 0
stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/config/AccessConfig.java

@@ -0,0 +1,37 @@
+package cn.com.qmth.stmms.ms.accesscontrol.config;
+
+import cn.com.qmth.stmms.ms.accesscontrol.LoginInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+/**
+ * Created by zhengmin on 2017/3/2.
+ */
+@Configuration
+@Profile(value = "prod")
+public class AccessConfig extends WebMvcConfigurerAdapter {
+
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        registry.addMapping("/**").allowedOrigins("*").allowCredentials(false)
+                .allowedMethods("PUT", "DELETE", "GET", "POST", "PATCH").allowedHeaders("Cache-Control", "Pragma",
+                "Origin", "Authorization", "Content-Type", "X-Requested-With")
+                .maxAge(9999999999999999L);
+        // .exposedHeaders("header1", "header2")
+    }
+
+    @Bean
+    public LoginInterceptor loginInterceptor() {
+        return new LoginInterceptor();
+    }
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor( loginInterceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/admin/users/login",
+                "/api/user/login","/api/exam/students","/api/upload/student/*","/api/file/ms-slice/**","/api/subject/collect-config");
+    }
+}

+ 30 - 0
stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/config/LoginConfig.java

@@ -0,0 +1,30 @@
+package cn.com.qmth.stmms.ms.accesscontrol.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "app.admin")
+public class LoginConfig {
+
+	private String loginName;
+
+	private String password;
+
+	public String getLoginName() {
+		return loginName;
+	}
+
+	public void setLoginName(String loginName) {
+		this.loginName = loginName;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+}

+ 35 - 0
stmms-ms-admin/pom.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>stmms-ms-parent</artifactId>
+        <groupId>cn.com.qmth</groupId>
+        <version>${project.version}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>stmms-ms-admin</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-marking</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-commons</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 130 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/ScoreApi.java

@@ -0,0 +1,130 @@
+package cn.com.qmth.stmms.ms.admin.api;
+
+import cn.com.qmth.stmms.ms.admin.assembler.ScoreAssembler;
+import cn.com.qmth.stmms.ms.admin.dto.ScoreCheckDTO;
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.domain.Student;
+import cn.com.qmth.stmms.ms.core.domain.Work;
+import cn.com.qmth.stmms.ms.core.domain.task.MarkTask;
+import cn.com.qmth.stmms.ms.core.repository.MarkTaskRepo;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+import cn.com.qmth.stmms.ms.core.repository.StudentRepo;
+import cn.com.qmth.stmms.ms.core.repository.WorkRepo;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+import org.apache.catalina.connector.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 成绩处理api
+ * Created by zhengmin on 2017/1/6.
+ */
+@RestController
+@RequestMapping("api/score")
+public class ScoreApi {
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @Autowired
+    private MarkTaskRepo markTaskRepo;
+
+    @Autowired
+    private StudentRepo studentRepo;
+
+    @Autowired
+    private WorkRepo workRepo;
+
+    @Autowired
+    private ScoreAssembler scoreAssembler;
+
+    /**
+     * 查询
+     * @param workId 评卷工作id
+     * @param examNumber 准考证号
+     * @return
+     */
+    @RequestMapping(value = "search/byExamNumber",method = RequestMethod.GET)
+    public ScoreCheckDTO getByExamNumber(@RequestParam Long workId,
+                                         @RequestParam String examNumber){
+        Student student = studentRepo.findByWorkIdAndExamNumber(workId,examNumber);
+        List<Paper> papers = paperRepo.findByWorkIdAndExamNumber(workId,examNumber);
+        return scoreAssembler.toDTO(student,papers);
+    }
+
+    /**
+     * 查询任务两科成绩高于hs,另外一颗低于ls
+     * @param workId 评卷工作id
+     * @param hs 高分
+     * @param ls 低分
+     * @return
+     */
+    @RequestMapping(value = "search/byRange",method = RequestMethod.GET)
+    public ResponseEntity getByScoreRange(@RequestParam Long workId,
+                                          @RequestParam Double hs,
+                                          @RequestParam Double ls){
+        List<ScoreCheckDTO> scoreDTOs = new ArrayList<>();
+        List<Paper> papers = paperRepo.findByScoreRange(hs,ls);
+        Map<String,List<Paper>> group = papers.stream().collect(Collectors.groupingBy(Paper::getExamNumber));
+        group.forEach((k,v) -> {
+            long ct = v.stream().mapToDouble(Paper::getScore).filter(s -> s >= hs).count();
+            if(v.size() == 3 && ct == 2) {
+                Student student = studentRepo.findByWorkIdAndExamNumber(workId, k);
+                scoreDTOs.add(scoreAssembler.toDTO(student,v));
+            }
+        });
+        return ResponseEntity.ok(scoreDTOs);
+    }
+
+    /**
+     * 更新分数
+     * @param paperId 试卷id
+     * @param body 分数
+     * @return
+     */
+    @RequestMapping(value = "update/{paperId}",method = RequestMethod.PUT)
+    public ResponseEntity updateScore(@PathVariable Long paperId, @RequestBody ModelMap body){
+        Paper paper = paperRepo.findOne(paperId);
+        if(paper == null || body.get("score") == null){
+            return new ResponseEntity(HttpStatus.OK);
+        }
+        Double score = Double.valueOf(body.get("score").toString());
+        if(score >= 0 && score <= 100){
+            paper.setScore(score);
+            paperRepo.save(paper);
+        }
+        return new ResponseEntity(HttpStatus.OK);
+    }
+
+    @RequestMapping(value = "merge/{subject}",method = RequestMethod.GET)
+    public ResponseEntity merge(@PathVariable Subject subject){
+        Work activedWork = workRepo.findByActiveTrue();
+        List<Paper> papers = paperRepo.findByWorkIdAndSubject(activedWork.getId(),subject);
+        Iterator<Paper> paperIterator = papers.iterator();
+        long count = 0;
+        while (paperIterator.hasNext()){
+            Paper paper = paperIterator.next();
+            List<MarkTask> markTasks = markTaskRepo.findByPaperIdAndStage(paper.getId(),MarkStage.SCORE);
+            long leftCount = markTasks.stream().filter(i -> i.getResult() == null).count();
+            if(leftCount == 0){
+                OptionalDouble finalScore = markTasks.stream().map(m -> m.getResult())
+                        .mapToInt(Integer::valueOf).average();
+                double fs = Math.round(finalScore.orElse(0));
+                paper.setScore(fs);
+                paperRepo.save(paper);
+                count++;
+            }
+            if(count%500 == 0){
+                System.out.println(subject.toString() + ":" +count);
+            }
+        }
+        return ResponseEntity.ok(null);
+    }
+}

+ 122 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/StudentApi.java

@@ -0,0 +1,122 @@
+package cn.com.qmth.stmms.ms.admin.api;
+
+import java.io.IOException;
+
+import cn.com.qmth.stmms.ms.admin.service.DataUploadService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import cn.com.qmth.stmms.ms.commons.utils.specification.PagingAndSortingDTO;
+import cn.com.qmth.stmms.ms.core.domain.Student;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+import cn.com.qmth.stmms.ms.core.repository.StudentRepo;
+import cn.com.qmth.stmms.ms.core.specification.StudentSpecification;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+/**
+ * 考生数据api
+ */
+@RestController
+@RequestMapping("api/students")
+public class StudentApi {
+
+    @Autowired
+    private DataUploadService dataUploadService;
+
+    @Autowired
+    private StudentRepo studentRepo;
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    /**
+     * 考生列表
+     * @param params
+     * @return
+     */
+    @RequestMapping(method = RequestMethod.GET)
+    public PagingAndSortingDTO list(StudentSpecification params) {
+        Page<Student> result = studentRepo.findAll(params.getSpecification(), params.getPageRequest());
+        return new PagingAndSortingDTO(result.getNumber(), result.getSize(), result.getTotalPages(),
+                result.getTotalElements(), result.getContent());
+    }
+
+    /**
+     * 单个考生
+     * @param domain 考生id
+     * @return
+     */
+    @RequestMapping(value = "{domain}", method = RequestMethod.GET)
+    public Student getOne(@PathVariable Student domain) {
+        return domain;
+    }
+
+    /**
+     * 删除
+     * @param domain
+     */
+    @RequestMapping(value = "{domain}", method = RequestMethod.DELETE)
+    public void remove(@PathVariable Student domain) {
+    	Long isExist = paperRepo.countByWorkIdAndExamNumber(domain.getWorkId(), domain.getExamNumber());
+        if (isExist > 0) {
+            throw new RuntimeException("该考生已上传,无法修改");
+        }
+        studentRepo.delete(domain);
+    }
+
+    /**
+     * 修改信息
+     * @param domain
+     * @param student
+     */
+    @RequestMapping(value = "{domain}", method = RequestMethod.PUT)
+    public void update(@PathVariable Student domain, @RequestBody Student student) {
+        Long isExist = paperRepo.countByWorkIdAndExamNumber(domain.getWorkId(), domain.getExamNumber());
+        if (isExist > 0) {
+            throw new RuntimeException("该考生已上传,无法删除");
+        }
+        domain.setName(student.getName());
+        domain.setExamRoom(student.getExamRoom());
+        domain.setAreaCode(student.getAreaCode());
+        studentRepo.save(domain);
+    }
+
+    /**
+     * 新增
+     * @param domain
+     * @return
+     */
+    @RequestMapping(method = RequestMethod.POST)
+    public Student create(@RequestBody Student domain) {
+        return studentRepo.save(domain);
+    }
+
+    /**
+     * 清空所有
+     * @param workId 评卷工作id
+     */
+    @RequestMapping(method = RequestMethod.DELETE)
+    public void clear(@RequestParam Long workId) {
+        dataUploadService.clearStudents(workId);
+    }
+
+    /**
+     * 新增
+     * @param studentId
+     * @param subject
+     * @param isManual
+     * @param file
+     * @throws IOException
+     */
+    @RequestMapping(value = "{studentId}", method = RequestMethod.POST)
+    public void addPaper(@PathVariable Long studentId,
+						 @RequestParam Subject subject,
+						 @RequestParam(required = false) boolean isManual,
+						 @RequestParam MultipartFile file)
+            throws IOException {
+        dataUploadService.uploadPaper(studentId, subject, file.getInputStream(),isManual);
+    }
+
+}

+ 91 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/UserApi.java

@@ -0,0 +1,91 @@
+package cn.com.qmth.stmms.ms.admin.api;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import cn.com.qmth.stmms.ms.core.domain.user.MarkRight;
+import cn.com.qmth.stmms.ms.core.repository.MarkTaskRepo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.MarkSubject;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.domain.user.Role;
+import cn.com.qmth.stmms.ms.core.repository.MarkSubjectRepo;
+import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+/**
+ * 
+ * @Description: 用户api
+ * @author ting.yin
+ * @date 2016年10月24日
+ */
+@RestController
+@RequestMapping("api/admin/users")
+public class UserApi {
+
+	@Autowired
+	private MarkUserRepo markUserRepo;
+
+    @Autowired
+    private MarkSubjectRepo markSubjectRepo;
+
+	@Autowired
+	private MarkTaskRepo markTaskRepo;
+	
+	@RequestMapping(value = "{userId}", method = RequestMethod.DELETE)
+	public void remove(@PathVariable Long userId) {
+		long count = markTaskRepo.countByMarkerId(userId);
+		if(count > 0){
+			throw new RuntimeException("已分配任务,不允许删除");
+		}
+		markUserRepo.delete(userId);
+	}
+
+	@RequestMapping(value = "{domain}", method = RequestMethod.PUT)
+	public void update(@PathVariable MarkUser domain,@RequestBody MarkUser user){
+		domain.setName(user.getName());
+		domain.setMarkRight(user.getMarkRight());
+		markUserRepo.save(domain);
+	}
+
+	@RequestMapping(method = RequestMethod.POST)
+	public void create(@RequestBody MarkUser user) {
+		MarkSubject markSubject = markSubjectRepo.findOne(user.getWorkId() + "-" + user.getSubject().toString());
+		if(markSubject == null){
+            throw new RuntimeException("该科目不存在");
+        }
+		if(user.getRole() == Role.MARKER && user.getMarkRight() == MarkRight.ALLOW_LEVELING && !markSubject.getStage().equals(MarkStage.INIT)){
+			throw new RuntimeException("请进入分档阶段前创建");
+		}
+		MarkUser markUser = markUserRepo.findByLoginName(user.getWorkId()+"-"+user.getLoginName());
+		if(markUser != null){
+            throw new RuntimeException("该登录名已经存在");
+        }
+		user.setLoginName(user.getWorkId()+"-"+user.getLoginName());
+		markUserRepo.save(user);
+	}
+
+    @RequestMapping(method = RequestMethod.GET)
+    public List<MarkUser> list(@RequestParam Long workId,
+							   @RequestParam Subject subject,
+							   @RequestParam(required = false ) Role role){
+    	if(role!= null){
+    		return markUserRepo.findByWorkIdAndRole(workId,role).stream().filter( u -> u.getSubject() == subject)
+					.collect(Collectors.toList());
+    	}else{
+    		return markUserRepo.findByWorkId(workId).stream().filter( u -> u.getSubject() == subject)
+					.collect(Collectors.toList());
+    	}
+    }
+	
+
+	
+}

+ 148 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/WorkApi.java

@@ -0,0 +1,148 @@
+package cn.com.qmth.stmms.ms.admin.api;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.ms.admin.assembler.WorkOverviewAssembler;
+import cn.com.qmth.stmms.ms.admin.dto.WorkOverview;
+import cn.com.qmth.stmms.ms.core.repository.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import cn.com.qmth.stmms.ms.admin.service.WorkService;
+import cn.com.qmth.stmms.ms.core.domain.Level;
+import cn.com.qmth.stmms.ms.core.domain.Work;
+
+/**
+ * 评卷工作api
+ * Created by zhengmin on 2016/10/14.
+ */
+@RestController
+@RequestMapping("api/admin/works")
+public class WorkApi {
+
+    @Autowired
+    private WorkRepo workRepo;
+
+    @Autowired
+    private LevelRepo levelRepo;
+    
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @Autowired
+    private MarkUserRepo markUserRepo;
+
+    @Autowired
+    private ExamQuestionRepo questionRepo;
+    
+    @Autowired
+    private WorkService workService;
+
+    @Autowired
+    private StudentRepo studentRepo;
+
+    @Autowired
+    private WorkOverviewAssembler workOverviewAssembler;
+
+    /**
+     * 列表
+     * @return
+     */
+    @RequestMapping(method = RequestMethod.GET)
+    public List<Work> list(){
+        return workRepo.findAll();
+    }
+
+    /**
+     * 单个信息
+     * @param work
+     * @return
+     */
+    @RequestMapping(value = "{work}",method = RequestMethod.GET)
+    public Work getOne(@PathVariable Work work){
+        return work;
+    }
+
+    /**
+     * 新增
+     * @param work
+     */
+	@RequestMapping(method = RequestMethod.POST)
+	public void create(@RequestBody Work work) {
+        workService.save(work);
+	}
+
+    /**
+     * 修改
+     * @param workId
+     * @param work
+     * @return
+     */
+    @RequestMapping(value = "{workId}",method = RequestMethod.PUT)
+    public Work update(@PathVariable Long workId, @RequestBody Work work){
+        return workRepo.save(work);
+    }
+
+    /**
+     * 激活为当前,采集和评卷用户登录影响
+     * @param workId
+     */
+    @RequestMapping(value = "{workId}",method = RequestMethod.PATCH)
+    public void active(@PathVariable Long workId){
+        List<Work> works = workRepo.findAll();
+        for (Work w : works){
+            w.setActive(false);
+            if(w.getId().equals(workId)){
+                w.setActive(true);
+            }
+        }
+        workRepo.save(works);
+    }
+
+    /**
+     * 删除
+     * @param workId
+     */
+    @RequestMapping(value = "{workId}",method = RequestMethod.DELETE)
+    public void remove(@PathVariable Long workId){
+    	workService.delete(workId);
+    }
+
+    //////////////////////    levels
+
+    /**
+     * 档位设定列表
+     * @param workId
+     * @return
+     */
+    @RequestMapping(value = "{workId}/levels",method = RequestMethod.GET)
+    public List<Level> list(@PathVariable Long workId){
+        return levelRepo.findByWorkId(workId);
+    }
+
+    /**
+     * 删除档位
+     * @param workId
+     * @param levelId
+     */
+    @RequestMapping(value = "{workId}/levels/{levelId}",method = RequestMethod.DELETE)
+    public void deleteLevel(@PathVariable Long workId,@PathVariable Long levelId){
+        levelRepo.delete(levelId);
+    }
+    //////////////////////   overview
+
+    /**
+     * 总览,各统计数据
+     * @param work
+     * @return
+     */
+    @RequestMapping(value = "{work}/overview",method = RequestMethod.GET)
+    public WorkOverview overview(@PathVariable Work work){
+        return workOverviewAssembler.toDTO(work);
+    }
+
+}

+ 27 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/assembler/MarkUserAssembler.java

@@ -0,0 +1,27 @@
+package cn.com.qmth.stmms.ms.admin.assembler;
+
+import cn.com.qmth.stmms.ms.admin.dto.MarkUserDTO;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created by zhengmin on 2016/11/18.
+ */
+@Component
+public class MarkUserAssembler {
+
+    public MarkUserDTO toDTO(MarkUser markUser){
+        MarkUserDTO markUserDTO = null;
+        if(markUser != null){
+            markUserDTO = new MarkUserDTO();
+            markUserDTO.setLoginName(markUser.getLoginName());
+            markUserDTO.setName(markUser.getName());
+            markUserDTO.setPassword(markUser.getPassword());
+            markUserDTO.setSubjectName(markUser.getSubject().getName());
+            markUserDTO.setRoleName(markUser.getRole().getName());
+            String markRight = markUser.getMarkRight() == null?"":markUser.getMarkRight().getName();
+            markUserDTO.setMarkRightName(markRight);
+        }
+        return markUserDTO;
+    }
+}

+ 37 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/assembler/ScoreAssembler.java

@@ -0,0 +1,37 @@
+package cn.com.qmth.stmms.ms.admin.assembler;
+
+import cn.com.qmth.stmms.ms.admin.dto.ScoreCheckDTO;
+import cn.com.qmth.stmms.ms.admin.dto.ScoreItem;
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.domain.Student;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2017/1/6.
+ */
+@Component
+public class ScoreAssembler {
+
+    public ScoreCheckDTO toDTO(Student student, List<Paper> papers){
+        ScoreCheckDTO scoreDTO = null;
+        if(student != null){
+            scoreDTO = new ScoreCheckDTO();
+            scoreDTO.setName(student.getName());
+            scoreDTO.setId(student.getId());
+            scoreDTO.setAreaName(student.getAreaName());
+            scoreDTO.setExamRoom(student.getExamRoom());
+            scoreDTO.setExamNumber(student.getExamNumber());
+            for(Paper p : papers){
+                ScoreItem scoreItem = new ScoreItem();
+                scoreItem.setPaperId(p.getId());
+                scoreItem.setSubjectName(p.getSubject().getName());
+                scoreItem.setScore(p.getScore());
+                scoreItem.setSubject(p.getSubject());
+                scoreDTO.getScoreItems().add(scoreItem);
+            }
+        }
+        return scoreDTO;
+    }
+}

+ 85 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/assembler/WorkOverviewAssembler.java

@@ -0,0 +1,85 @@
+package cn.com.qmth.stmms.ms.admin.assembler;
+
+import cn.com.qmth.stmms.ms.admin.dto.SubjectOverview;
+import cn.com.qmth.stmms.ms.admin.dto.WorkOverview;
+import cn.com.qmth.stmms.ms.core.domain.Student;
+import cn.com.qmth.stmms.ms.core.domain.Work;
+import cn.com.qmth.stmms.ms.core.domain.user.Role;
+import cn.com.qmth.stmms.ms.core.repository.ExamQuestionRepo;
+import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+import cn.com.qmth.stmms.ms.core.repository.StudentRepo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by zhengmin on 2016/11/21.
+ */
+@Component
+public class WorkOverviewAssembler {
+
+    @Autowired
+    private StudentRepo studentRepo;
+
+    @Autowired
+    private ExamQuestionRepo examQuestionRepo;
+
+    @Autowired
+    private MarkUserRepo markUserRepo;
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    public WorkOverview toDTO(Work work){
+        WorkOverview workOverview = null;
+        if(work != null){
+            workOverview = new WorkOverview();
+            workOverview.setWorkName(work.getName());
+            workOverview.setPaperCount(paperRepo.countByWorkId(work.getId()));
+            workOverview.setMarkerCount(markUserRepo.countByWorkIdAndRole(work.getId(), Role.MARKER));
+            workOverview.setQuestionCount(examQuestionRepo.countByWorkId(work.getId()));
+
+            List<Student> students = studentRepo.findByWorkId(work.getId());
+            workOverview.setStuTotalCount(students.stream().count());
+            workOverview.setStuAbsentCount(students.stream().filter(s -> s.isAbsent()).count());
+            workOverview.setStuUploadedCount(workOverview.getStuTotalCount() - workOverview.getStuAbsentCount());
+
+            ////// subject overview assemble
+
+            List<SubjectOverview> subjectOverviews = new ArrayList<>();
+            work.getSubjects().forEach(s -> {
+                SubjectOverview so = new SubjectOverview();
+                so.setWorkId(s.getWorkId());
+                so.setSubjectId(s.getId());
+                so.setSubjectName(s.getName());
+                so.setSubject(s.getSubject().toString());
+                so.setMarkStage(s.getStage());
+                subjectOverviews.add(so);
+            });
+            Map<String,Long> subjectMap = new HashMap<>();
+            for(SubjectOverview  so : subjectOverviews){
+                subjectMap.put(so.getSubject(),0L);
+            }
+            for(Student student : students){
+                String[] uploadStatus = student.getUploadStatus().split(",");
+                for(String s : uploadStatus){
+                    if("1".equals(s.split(":")[1])){
+                        long c = subjectMap.get(s.split(":")[0]);
+                        subjectMap.put(s.split(":")[0],++c);
+                    }
+                }
+            }
+            for(SubjectOverview  so : subjectOverviews){
+                so.setUploadedCount(subjectMap.get(so.getSubject()));
+                so.setLeftCount(workOverview.getStuTotalCount() - workOverview.getStuAbsentCount()-so.getUploadedCount());
+            }
+            workOverview.setSubjectOverviews(subjectOverviews);
+        }
+        return workOverview;
+    }
+}

+ 75 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/MarkUserDTO.java

@@ -0,0 +1,75 @@
+package cn.com.qmth.stmms.ms.admin.dto;
+
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExcelProperty;
+
+import java.io.Serializable;
+
+/**
+ * Created by zhengmin on 2016/11/18.
+ */
+public class MarkUserDTO implements Serializable{
+
+    private static final long serialVersionUID = 4156352259187548181L;
+
+    @ExcelProperty(name = "登录名", index = 0 ,type = 1)
+    private String loginName;
+    @ExcelProperty(name = "姓名", index = 1 ,type = 1)
+    private String name;
+    @ExcelProperty(name = "密码", index = 2 ,type = 1)
+    private String password;
+    @ExcelProperty(name = "科目", index = 3 ,type = 1)
+    private String subjectName;
+    @ExcelProperty(name = "角色", index = 4 ,type = 1)
+    private String roleName;
+    @ExcelProperty(name = "权限", index = 5 ,type = 1)
+    private String markRightName;
+
+    public String getLoginName() {
+        return loginName;
+    }
+
+    public void setLoginName(String loginName) {
+        this.loginName = loginName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+
+    public String getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
+
+	public String getMarkRightName() {
+		return markRightName;
+	}
+
+	public void setMarkRightName(String markRightName) {
+		this.markRightName = markRightName;
+	}
+    
+}

+ 51 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/PaperCounter.java

@@ -0,0 +1,51 @@
+package cn.com.qmth.stmms.ms.admin.dto;
+
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExcelProperty;
+
+/**
+ * Created by zhengmin on 2017/1/10.
+ */
+public class PaperCounter {
+
+    @ExcelProperty(name = "考区名",index = 1,width = 50,type = 1)
+    private String areaName;
+    @ExcelProperty(name = "考区代码",index = 0,type = 1)
+    private String areaCode;
+    @ExcelProperty(name = "科目名",index = 2,type = 1)
+    private String questionName;
+    @ExcelProperty(name = "试卷数量",index = 3,type = 1)
+    private long paperCount;
+
+
+    public String getAreaName() {
+        return areaName;
+    }
+
+    public void setAreaName(String areaName) {
+        this.areaName = areaName;
+    }
+
+    public String getAreaCode() {
+        return areaCode;
+    }
+
+    public void setAreaCode(String areaCode) {
+        this.areaCode = areaCode;
+    }
+
+    public long getPaperCount() {
+        return paperCount;
+    }
+
+    public void setPaperCount(long paperCount) {
+        this.paperCount = paperCount;
+    }
+
+    public String getQuestionName() {
+        return questionName;
+    }
+
+    public void setQuestionName(String questionName) {
+        this.questionName = questionName;
+    }
+}

+ 24 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/ScoreCheckDTO.java

@@ -0,0 +1,24 @@
+package cn.com.qmth.stmms.ms.admin.dto;
+
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 成绩复核
+ * Created by zhengmin on 2017/1/6.
+ */
+public class ScoreCheckDTO extends StudentDTO{
+
+    private List<ScoreItem> scoreItems = new ArrayList<>();
+
+    public List<ScoreItem> getScoreItems() {
+        return scoreItems;
+    }
+
+    public void setScoreItems(List<ScoreItem> scoreItems) {
+        this.scoreItems = scoreItems;
+    }
+}
+

+ 79 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/ScoreDTO.java

@@ -0,0 +1,79 @@
+package cn.com.qmth.stmms.ms.admin.dto;
+
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExcelProperty;
+
+/**
+ * Created by zhengmin on 2017/1/18.
+ */
+public class ScoreDTO {
+
+    @ExcelProperty(name = "准考证号",index = 0,type = 1)
+    private String examNumber;
+    @ExcelProperty(name = "姓名",index = 1,type = 1)
+    private String studentName;
+    @ExcelProperty(name = "考区",width = 80,index = 2,type = 1)
+    private String areaName;
+    @ExcelProperty(name = "速写",index = 3,type = 1)
+    private String sx;
+    @ExcelProperty(name = "色彩",index = 4,type = 1)
+    private String sc;
+    @ExcelProperty(name = "素描",index = 5,type = 1)
+    private String sm;
+    private String scoreList;
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getStudentName() {
+        return studentName;
+    }
+
+    public void setStudentName(String studentName) {
+        this.studentName = studentName;
+    }
+
+    public String getAreaName() {
+        return areaName;
+    }
+
+    public void setAreaName(String areaName) {
+        this.areaName = areaName;
+    }
+
+    public String getSx() {
+        return sx;
+    }
+
+    public void setSx(String sx) {
+        this.sx = sx;
+    }
+
+    public String getSc() {
+        return sc;
+    }
+
+    public void setSc(String sc) {
+        this.sc = sc;
+    }
+
+    public String getSm() {
+        return sm;
+    }
+
+    public void setSm(String sm) {
+        this.sm = sm;
+    }
+
+    public String getScoreList() {
+        return scoreList;
+    }
+
+    public void setScoreList(String scoreList) {
+        this.scoreList = scoreList;
+    }
+}

+ 46 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/ScoreItem.java

@@ -0,0 +1,46 @@
+package cn.com.qmth.stmms.ms.admin.dto;
+
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+/**
+ * Created by zhengmin on 2017/1/6.
+ */
+public class ScoreItem {
+
+    private Subject subject;
+    private String subjectName;
+    private Double score;
+    private Long paperId;
+
+    public Subject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(Subject subject) {
+        this.subject = subject;
+    }
+
+    public Double getScore() {
+        return score;
+    }
+
+    public void setScore(Double score) {
+        this.score = score;
+    }
+
+    public Long getPaperId() {
+        return paperId;
+    }
+
+    public void setPaperId(Long paperId) {
+        this.paperId = paperId;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+}

+ 86 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/StudentDTO.java

@@ -0,0 +1,86 @@
+package cn.com.qmth.stmms.ms.admin.dto;
+
+import java.io.Serializable;
+
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExcelProperty;
+
+public class StudentDTO implements Serializable {
+
+    private static final long serialVersionUID = -4556126416794102992L;
+
+    private Long id;
+
+    @ExcelProperty(index = 1, name = "准考证号", type = 2)
+    private String examNumber;
+
+    @ExcelProperty(index = 2, name = "姓名", type = 2)
+    private String name;
+
+    @ExcelProperty(index = 3, name = "考区名称", type = 2)
+    private String areaName;
+
+    @ExcelProperty(index = 4, name = "考区代码", type = 2)
+    private String areaCode;
+
+    @ExcelProperty(index = 5, name = "考场", type = 2)
+    private String examRoom;
+
+    private Long workId;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getAreaCode() {
+        return areaCode;
+    }
+
+    public void setAreaCode(String areaCode) {
+        this.areaCode = areaCode;
+    }
+
+    public Long getWorkId() {
+        return workId;
+    }
+
+    public void setWorkId(Long workId) {
+        this.workId = workId;
+    }
+
+    public String getAreaName() {
+        return areaName;
+    }
+
+    public void setAreaName(String areaName) {
+        this.areaName = areaName;
+    }
+
+    public String getExamRoom() {
+        return examRoom;
+    }
+
+    public void setExamRoom(String examRoom) {
+        this.examRoom = examRoom;
+    }
+
+}

+ 91 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/SubjectOverview.java

@@ -0,0 +1,91 @@
+package cn.com.qmth.stmms.ms.admin.dto;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+
+import java.io.Serializable;
+
+/**
+ * Created by zhengmin on 2016/11/22.
+ */
+public class SubjectOverview implements Serializable {
+
+
+    private static final long serialVersionUID = -7288090404587137615L;
+
+    private Long workId;
+
+    private String subjectId;
+
+    private String subjectName;
+
+    private String subject;
+
+    private MarkStage markStage;
+
+    /**
+     * 已上传试卷数
+     */
+    private long uploadedCount;
+
+    /**
+     * 剩余试卷数
+     */
+    private long leftCount;
+
+    public String getSubjectId() {
+        return subjectId;
+    }
+
+    public void setSubjectId(String subjectId) {
+        this.subjectId = subjectId;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+
+    public MarkStage getMarkStage() {
+        return markStage;
+    }
+
+    public void setMarkStage(MarkStage markStage) {
+        this.markStage = markStage;
+    }
+
+    public long getUploadedCount() {
+        return uploadedCount;
+    }
+
+    public void setUploadedCount(long uploadedCount) {
+        this.uploadedCount = uploadedCount;
+    }
+
+    public long getLeftCount() {
+        return leftCount;
+    }
+
+    public void setLeftCount(long leftCount) {
+        this.leftCount = leftCount;
+    }
+
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    public Long getWorkId() {
+        return workId;
+    }
+
+    public void setWorkId(Long workId) {
+        this.workId = workId;
+    }
+}

+ 115 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/dto/WorkOverview.java

@@ -0,0 +1,115 @@
+package cn.com.qmth.stmms.ms.admin.dto;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 评卷工作总览
+ * Created by zhengmin on 2016/11/21.
+ */
+public class WorkOverview implements Serializable{
+
+
+    private static final long serialVersionUID = -5958886079362318462L;
+
+    private String workName;
+
+    /**
+     * 考生总数
+     */
+    private long stuTotalCount;
+
+    /**
+     * 缺考数
+     */
+    private long stuAbsentCount;
+
+    /**
+     * 实考人数
+     */
+    private long stuUploadedCount;
+
+    /**
+     * 已上传试卷总数
+     */
+    private long paperCount;
+
+    /**
+     * 评卷员总人数
+     */
+    private long markerCount;
+
+    /**
+     * 试题总数
+     */
+    private long questionCount;
+
+    private List<SubjectOverview> subjectOverviews = new ArrayList<>();
+
+    public String getWorkName() {
+        return workName;
+    }
+
+    public void setWorkName(String workName) {
+        this.workName = workName;
+    }
+
+    public long getStuTotalCount() {
+        return stuTotalCount;
+    }
+
+    public void setStuTotalCount(long stuTotalCount) {
+        this.stuTotalCount = stuTotalCount;
+    }
+
+    public long getStuAbsentCount() {
+        return stuAbsentCount;
+    }
+
+    public void setStuAbsentCount(long stuAbsentCount) {
+        this.stuAbsentCount = stuAbsentCount;
+    }
+
+    public long getPaperCount() {
+        return paperCount;
+    }
+
+    public void setPaperCount(long paperCount) {
+        this.paperCount = paperCount;
+    }
+
+    public long getMarkerCount() {
+        return markerCount;
+    }
+
+    public void setMarkerCount(long markerCount) {
+        this.markerCount = markerCount;
+    }
+
+    public long getQuestionCount() {
+        return questionCount;
+    }
+
+    public void setQuestionCount(long questionCount) {
+        this.questionCount = questionCount;
+    }
+
+    public List<SubjectOverview> getSubjectOverviews() {
+        return subjectOverviews;
+    }
+
+    public void setSubjectOverviews(List<SubjectOverview> subjectOverviews) {
+        this.subjectOverviews = subjectOverviews;
+    }
+
+    public long getStuUploadedCount() {
+        return stuUploadedCount;
+    }
+
+    public void setStuUploadedCount(long stuUploadedCount) {
+        this.stuUploadedCount = stuUploadedCount;
+    }
+}
+
+

+ 52 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/exporter/ScoreExporter.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.stmms.ms.admin.exporter;
+
+import cn.com.qmth.stmms.ms.admin.dto.ScoreDTO;
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExportUtils;
+import cn.com.qmth.stmms.ms.core.repository.ExamQuestionRepo;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2017/1/18.
+ */
+@RestController
+@RequestMapping("export/score")
+public class ScoreExporter {
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @Autowired
+    private ExamQuestionRepo examQuestionRepo;
+
+    @RequestMapping(method = RequestMethod.GET)
+    public void export(@RequestParam Long workId, HttpServletResponse response){
+        List<ScoreDTO> scoreDTOs = new ArrayList<>();
+        List<Object[]> objects = paperRepo.findScores(workId);
+        objects.forEach(o -> {
+            Long questionId = Long.valueOf(o[2].toString());
+            String areaName = examQuestionRepo.findOne(questionId).getAreaName();
+            ScoreDTO scoreDTO = new ScoreDTO();
+            scoreDTO.setExamNumber(o[0].toString());
+            scoreDTO.setStudentName(o[1].toString());
+            String scoreList = String.valueOf(o[3]);
+            if(scoreList != null && scoreList.split(",").length == 3){
+                scoreDTO.setSc(scoreList.split(",")[0]);
+                scoreDTO.setSm(scoreList.split(",")[1]);
+                scoreDTO.setSx(scoreList.split(",")[2]);
+            }
+            scoreDTO.setAreaName(areaName);
+            scoreDTOs.add(scoreDTO);
+        });
+        String fileName = "成绩总表";
+        ExportUtils.exportEXCEL(fileName,ScoreDTO.class,scoreDTOs,response);
+    }
+}

+ 47 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/exporter/UserExporter.java

@@ -0,0 +1,47 @@
+package cn.com.qmth.stmms.ms.admin.exporter;
+
+import cn.com.qmth.stmms.ms.admin.assembler.MarkUserAssembler;
+import cn.com.qmth.stmms.ms.admin.dto.MarkUserDTO;
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExportUtils;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+/**
+ * 导出用户信息
+ * Created by zhengmin on 2016/11/18.
+ */
+@RestController
+@RequestMapping("export/users")
+public class UserExporter {
+
+    @Autowired
+    private MarkUserRepo markUserRepo;
+
+    @Autowired
+    private MarkUserAssembler markUserAssembler;
+
+    @RequestMapping(method = RequestMethod.GET)
+    public void export(@RequestParam Long workId, @RequestParam(required = false) Subject subject,HttpServletResponse response){
+        List<MarkUserDTO> markUserDTOs = new ArrayList<>();
+        Stream<MarkUser> markUserStream = markUserRepo.findByWorkId(workId).stream();
+        if(subject != null){
+            markUserStream = markUserStream.filter(u -> u.getSubject() == subject);
+        }
+        markUserStream.forEach(u -> {
+            markUserDTOs.add(markUserAssembler.toDTO(u));
+        });
+        String fileName = "用户列表";
+        ExportUtils.exportEXCEL(fileName,MarkUserDTO.class,markUserDTOs,response);
+    }
+}

+ 46 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/exporter/WorkExporter.java

@@ -0,0 +1,46 @@
+package cn.com.qmth.stmms.ms.admin.exporter;
+
+import cn.com.qmth.stmms.ms.admin.dto.MarkUserDTO;
+import cn.com.qmth.stmms.ms.admin.dto.PaperCounter;
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExportUtils;
+import cn.com.qmth.stmms.ms.core.domain.Work;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2017/1/10.
+ */
+@RestController
+@RequestMapping("export/works")
+public class WorkExporter {
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @RequestMapping(value = "{work}/papercount",method = RequestMethod.GET)
+    public void countGropuByQuestion(@PathVariable Work work, HttpServletResponse response){
+        if(work != null) {
+            List<PaperCounter> paperCounters = new ArrayList<>();
+            List<Object[]> result = paperRepo.countGroupByQuestion(work.getId());
+            result.forEach(i -> {
+                PaperCounter paperCounter = new PaperCounter();
+                paperCounter.setAreaName(String.valueOf(i[1]));
+                paperCounter.setAreaCode(String.valueOf(i[0]));
+                paperCounter.setQuestionName(String.valueOf(i[2]));
+                paperCounter.setPaperCount(Long.parseLong(String.valueOf(i[3])));
+                paperCounters.add(paperCounter);
+            });
+            String fileName = "各省各科试卷数量";
+            ExportUtils.exportEXCEL(fileName,PaperCounter.class,paperCounters,response);
+        }
+    }
+}

+ 49 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/importer/StudentImporter.java

@@ -0,0 +1,49 @@
+package cn.com.qmth.stmms.ms.admin.importer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import cn.com.qmth.stmms.ms.admin.dto.StudentDTO;
+import cn.com.qmth.stmms.ms.admin.service.DataUploadService;
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExcelError;
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExportUtils;
+
+@RestController
+@RequestMapping("import/students")
+public class StudentImporter {
+
+    @Autowired
+    private DataUploadService dataUploadService;
+
+    @RequestMapping(method = RequestMethod.POST)
+    public List<ExcelError> batchAll(@RequestParam Long workId,
+            @RequestParam(required = false, defaultValue = "false") boolean isAbsent, @RequestParam MultipartFile file)
+            throws IOException {
+        return dataUploadService.uploadStudents(workId, isAbsent, file.getInputStream());
+    }
+    
+    @RequestMapping(method = RequestMethod.GET)
+    public void download(HttpServletResponse response){
+    	List<StudentDTO> studentDTOs =new ArrayList<StudentDTO>();
+    	StudentDTO dto = new StudentDTO();
+
+        dto.setExamNumber("5360001");
+        dto.setName("张三");
+        dto.setAreaName("云南艺术学院");
+        dto.setAreaCode("16");
+        dto.setExamRoom("第5考场");
+
+    	studentDTOs.add(dto);
+    	ExportUtils.exportEXCEL("考生导入模板",StudentDTO.class,studentDTOs,response);
+    }
+}

+ 222 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/service/DataUploadService.java

@@ -0,0 +1,222 @@
+package cn.com.qmth.stmms.ms.admin.service;
+
+import cn.com.qmth.stmms.ms.admin.dto.StudentDTO;
+import cn.com.qmth.stmms.ms.commons.config.ImageCompressionConfig;
+import cn.com.qmth.stmms.ms.commons.config.SystemConfig;
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExcelError;
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExcelReader;
+import cn.com.qmth.stmms.ms.commons.utils.excel.ExcelReaderHandle;
+import cn.com.qmth.stmms.ms.commons.utils.image.ImageCompression;
+import cn.com.qmth.stmms.ms.core.domain.ExamQuestion;
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.domain.Student;
+import cn.com.qmth.stmms.ms.core.repository.ExamQuestionRepo;
+import cn.com.qmth.stmms.ms.core.repository.MarkTaskRepo;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+import cn.com.qmth.stmms.ms.core.repository.StudentRepo;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.imageio.ImageIO;
+
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 数据上传服务 Created by zhengmin on 2016/11/18.
+ */
+@Service
+public class DataUploadService {
+
+    @Autowired
+    private StudentRepo studentRepo;
+
+    @Autowired
+    private ExamQuestionRepo examQuestionRepo;
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @Autowired
+    private SystemConfig systemConfig;
+
+    @Autowired
+    private ImageCompressionConfig compressionConfig;
+    
+    @Autowired
+    private MarkTaskRepo markTaskRepo;
+
+    /**
+     * 上传考生试卷数据
+     * 
+     * @param studentId
+     *            考生id
+     * @param subject
+     *            科目
+     * @param in
+     *            图片文件输入流
+     * @param isManual
+     *            是否手工绑定
+     * @throws IOException
+     */
+    @Transactional
+    public void uploadPaper(Long studentId, Subject subject, InputStream in, boolean isManual) throws IOException {
+        Student student = studentRepo.findOne(studentId);
+        String savePath = systemConfig.getImageDir() + File.separator + student.getWorkId() + File.separator + subject
+                + File.separator + student.getAreaCode();
+        File out = new File(savePath);
+        if (!out.exists()) {
+            out.mkdirs();
+        }
+        File outFile = new File(savePath + File.separator + student.getExamNumber() + ".jpg");
+        if (!outFile.exists()) {
+            outFile.createNewFile();
+        }
+        OutputStream output = new FileOutputStream(outFile);
+        byte[] buffer = new byte[in.available()];
+        in.read(buffer);
+        output.write(buffer);
+        output.close();
+
+        // 生成缩略图
+        String thumbDir = systemConfig.getThumbDir() + File.separator + student.getWorkId() + File.separator + subject
+                + File.separator + student.getAreaCode();
+        File thumb = new File(thumbDir);
+        if (!thumb.exists()) {
+            thumb.mkdirs();
+        }
+        BufferedImage bufferedImage = ImageCompression.compress(outFile, compressionConfig);
+        String thumbFileName = thumbDir + File.separator + student.getExamNumber() + ".jpg";
+        ImageIO.write(bufferedImage, "jpg", new File(thumbFileName));
+
+        Paper exist = paperRepo.findByWorkIdAndSubjectAndExamNumber(student.getWorkId(), subject,
+                student.getExamNumber());
+        if (exist != null) {
+            exist.setManual(isManual);
+            exist.setUploadedOn(new Date());
+            paperRepo.save(exist);
+        } else {
+            ExamQuestion examQuestion = examQuestionRepo.findByWorkIdAndSubjectAndAreaCode(student.getWorkId(), subject,
+                    student.getAreaCode());
+            Paper paper = new Paper(student.getWorkId(), null, subject, examQuestion, student, false);
+            paperRepo.save(paper);
+            // 更新科目上传状态
+            /**
+             * Long count =
+             * paperRepo.countByWorkIdAndExamNumber(student.getWorkId(),student.
+             * getExamNumber()); if(count == Subject.values().length){
+             * student.setUpload(true); studentRepo.save(student); }
+             */
+            synchronized (this) {
+                String uploadStatus = student.getUploadStatus();
+                String replace = subject.toString() + ":1";
+                String regx = subject.toString() + ":[0-1]";
+                String newStatus = uploadStatus.replaceFirst(regx, replace);
+                student.setUploadStatus(newStatus);
+                student.setAbsent(false);
+                studentRepo.save(student);
+            }
+        }
+    }
+
+    @Transactional
+    public List<ExcelError> uploadStudents(Long workId, boolean isAbsent, InputStream inputStream) {
+        ExcelReader excelReader = new ExcelReader(StudentDTO.class);
+        List<ExcelError> excelErrors = excelReader.reader(inputStream, new ExcelReaderHandle() {
+
+            @Override
+            public ExcelError handle(Object obj) {
+                StudentDTO dto = (StudentDTO) obj;
+
+                String examNumber = dto.getExamNumber();
+                //如果没有设置区域代码,用准考证前2位作为区域代码
+                String areaCode = null;
+                if(dto.getAreaCode() == null || dto.getAreaCode().isEmpty()){
+                    areaCode = examNumber.substring(0,2);
+                    dto.setAreaCode(areaCode);
+                }
+
+                long isExist = examQuestionRepo.countByWorkIdAndAreaCode(workId, dto.getAreaCode());
+                if (isExist == 0) {
+                    for (Subject subject : Subject.values()) {
+                        ExamQuestion question = new ExamQuestion(dto.getAreaCode(), subject, workId, dto.getAreaName());
+                        examQuestionRepo.save(question);
+                    }
+                }
+                Student student = studentRepo.findByWorkIdAndExamNumber(workId, dto.getExamNumber());
+                if (student == null && !isAbsent) {
+                    student = new Student(dto.getName(), dto.getExamNumber(), dto.getAreaName(), dto.getAreaCode(),
+                            workId, dto.getExamRoom());
+                    studentRepo.save(student);
+                }
+                else if(student != null){
+                    if (isAbsent) {
+                    	student.setAbsent(isAbsent);
+                    	student.setUploadStatus("SX:0,SC:0,SM:0");
+                    	
+                    	/**
+                    	 * 查询该考生所有paper,若paper无任务则删除,有任务就保留
+                    	 */
+                    	List<Paper> papers = paperRepo.findByWorkIdAndExamNumber(workId, student.getExamNumber());
+                    	if(!papers.isEmpty()){
+                    		for (Paper paper : papers) {
+                    			Long count = markTaskRepo.countByPaperId(paper.getId());
+                    			if(count == 0){
+                    				paperRepo.delete(paper);
+                    			}
+                    		}
+						}
+                    }else{
+                        student.setName(dto.getName());
+                        student.setAreaCode(dto.getAreaCode());
+                        student.setAreaName(dto.getAreaName());
+                        student.setExamRoom(dto.getExamRoom());
+                    }
+                    studentRepo.save(student);
+                }
+                return null;
+            }
+        });
+        return excelErrors;
+    }
+
+    /**
+     * 清空考生数据 有上传数据无法清空
+     * 
+     * @param workId
+     */
+    @Transactional
+    public void clearStudents(Long workId) {
+        Long isExist = paperRepo.countByWorkId(workId);
+        if (isExist > 0) {
+            throw new RuntimeException("有考生已上传,无法清空");
+        }
+        studentRepo.deleteByWorkId(workId);
+        examQuestionRepo.deleteByWorkId(workId);
+    }
+
+    @Transactional
+    public Paper savePaper(Student student,Subject subject,boolean isManual){
+        ExamQuestion examQuestion = examQuestionRepo.findByWorkIdAndSubjectAndAreaCode(student.getWorkId(),subject,student.getAreaCode());
+        Paper paper = paperRepo.findByWorkIdAndSubjectAndExamNumber(student.getWorkId(),subject,student.getExamNumber());
+        if(paper == null){
+            paper = new Paper(student.getWorkId(),null,subject,examQuestion,student,isManual);
+        }
+        paper.setUploadedOn(new Date());
+        paperRepo.save(paper);
+        synchronized (this) {
+            String uploadStatus = student.getUploadStatus();
+            String replace = subject.toString() + ":1";
+            String regx = subject.toString() + ":[0-1]";
+            String newStatus = uploadStatus.replaceFirst(regx, replace);
+            student.setUploadStatus(newStatus);
+            studentRepo.save(student);
+        }
+        return paper;
+    }
+}

+ 58 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/service/WorkService.java

@@ -0,0 +1,58 @@
+package cn.com.qmth.stmms.ms.admin.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkSubject;
+import cn.com.qmth.stmms.ms.core.domain.Work;
+import cn.com.qmth.stmms.ms.core.repository.MarkSubjectRepo;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+import cn.com.qmth.stmms.ms.core.repository.WorkRepo;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+/**
+ * 评卷工作服务
+ */
+@Service
+public class WorkService {
+
+	@Autowired
+	private WorkRepo workRepo;
+
+	@Autowired
+	private PaperRepo paperRepo;
+
+	@Autowired
+	private MarkSubjectRepo markSubjectRepo;
+
+	/**
+	 * 删除评卷工作
+	 * @param workId
+     */
+	@Transactional
+	public void delete(Long workId) {
+		Long paperCount = paperRepo.countByWorkId(workId);
+		if (paperCount > 0) {
+			throw new RuntimeException("该评卷工作已有数据,不能删除");
+		}
+		workRepo.delete(workId);
+
+	}
+
+	/**
+	 * 创建评卷工作
+	 * @param work
+     */
+	@Transactional
+	public void save(Work work) {
+		workRepo.save(work);
+		Subject[] subjects = Subject.values();
+		for (Subject subject : subjects) {
+			MarkSubject markSubject = new MarkSubject(subject, work.getId());
+			markSubject.setWorkId(work.getId());
+			markSubjectRepo.save(markSubject);
+		}
+	}
+
+}

+ 40 - 0
stmms-ms-collect/pom.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>stmms-ms-parent</artifactId>
+        <groupId>cn.com.qmth</groupId>
+        <version>${project.version}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>stmms-ms-collect</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-accesscontrol</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-admin</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>net.sf.json-lib</groupId>
+            <artifactId>json-lib-ext-spring</artifactId>
+            <version>1.0.2</version>
+        </dependency>
+
+    </dependencies>
+</project>

+ 164 - 0
stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/api/CollectApi.java

@@ -0,0 +1,164 @@
+package cn.com.qmth.stmms.ms.collect.api;
+
+import cn.com.qmth.stmms.ms.accesscontrol.config.LoginConfig;
+import cn.com.qmth.stmms.ms.admin.service.DataUploadService;
+import cn.com.qmth.stmms.ms.collect.dto.CollectStuDTO;
+import cn.com.qmth.stmms.ms.collect.dto.CollectSubjectDTO;
+import cn.com.qmth.stmms.ms.collect.dto.LoginDTO;
+import cn.com.qmth.stmms.ms.commons.config.ImageCompressionConfig;
+import cn.com.qmth.stmms.ms.commons.config.SystemConfig;
+import cn.com.qmth.stmms.ms.commons.utils.image.ImageCompression;
+import cn.com.qmth.stmms.ms.core.domain.MarkSubject;
+import cn.com.qmth.stmms.ms.core.domain.Student;
+import cn.com.qmth.stmms.ms.core.domain.Work;
+import cn.com.qmth.stmms.ms.core.repository.MarkSubjectRepo;
+import cn.com.qmth.stmms.ms.core.repository.StudentRepo;
+import cn.com.qmth.stmms.ms.core.repository.WorkRepo;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+import net.sf.json.JSONObject;
+import org.assertj.core.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.FileCopyUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+/**
+ * Created by dizhi on 2016/12/24.
+ */
+@RestController
+@RequestMapping("api")
+public class CollectApi {
+
+    @Autowired
+    private LoginConfig loginConfig;
+
+    @Autowired
+    private WorkRepo workRepo;
+
+    @Autowired
+    private StudentRepo studentRepo;
+
+    @Autowired
+    private MarkSubjectRepo markSubjectRepo;
+
+    @Autowired
+    private DataUploadService dataUploadService;
+
+    @Autowired
+    private SystemConfig systemConfig;
+
+    @Autowired
+    private ImageCompressionConfig compressionConfig;
+
+    @RequestMapping("user/login")
+    public LoginDTO login(@RequestParam String loginname,@RequestParam String password){
+        LoginDTO loginDTO = null;
+        if(loginname.equals(loginConfig.getLoginName()) && password.equals(loginConfig.getPassword())){
+            Work activeWork = workRepo.findByActiveTrue();
+            loginDTO = new LoginDTO();
+            loginDTO.setExamId(activeWork.getId());
+            loginDTO.setExamName(activeWork.getName());
+            List<CollectSubjectDTO> collectSubjectDTOs = new ArrayList<>();
+            activeWork.getSubjects().forEach(s -> {
+                int id = s.getSubject().ordinal()+1;
+                CollectSubjectDTO collectSubjectDTO = new CollectSubjectDTO(id,s.getName());
+                if(!Strings.isNullOrEmpty(s.getCollectConfig())){
+                    JSONObject json = JSONObject.fromObject(s.getCollectConfig());
+                    collectSubjectDTO.setCollectConfig(json);
+                }
+
+                collectSubjectDTOs.add(collectSubjectDTO);
+            });
+            loginDTO.setSubjects(collectSubjectDTOs);
+        }
+        return loginDTO;
+    }
+
+    @RequestMapping(value = "exam/students",method = RequestMethod.GET)
+    public List<CollectStuDTO> getStudents(){
+        List<CollectStuDTO> list = new ArrayList<>();
+        Work activeWork = workRepo.findByActiveTrue();
+        Consumer<Student> consumer = (s) -> {
+            CollectStuDTO collectStuDTO = new CollectStuDTO();
+            collectStuDTO.setExamId(activeWork.getId());
+            collectStuDTO.setExamNumber(s.getExamNumber());
+            collectStuDTO.setName(s.getName());
+            collectStuDTO.setSiteCode(s.getAreaName());
+            collectStuDTO.setRoomCode(s.getExamNumber());
+            list.add(collectStuDTO);
+        };
+        studentRepo.findByWorkId(activeWork.getId()).forEach(consumer);
+        return list;
+    }
+
+    @RequestMapping(value = "upload/student/{subjectId}", method = RequestMethod.POST)
+    public List<CollectStuDTO> saveStudent(HttpServletRequest request, @PathVariable Integer subjectId,
+                                 @RequestBody CollectStuDTO[] uploadStudentArray) {
+        Subject subject = Subject.values()[subjectId-1];
+        Work activeWork = workRepo.findByActiveTrue();
+        List<CollectStuDTO> list = new ArrayList<>();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
+        for(CollectStuDTO dto : uploadStudentArray){
+            Student student = studentRepo.findByWorkIdAndExamNumber(activeWork.getId(),dto.getExamNumber());
+            dataUploadService.savePaper(student,subject,dto.isManual());
+            dto.setUploadTime(sdf.format(new Date()));
+            list.add(dto);
+        }
+        return list;
+    }
+
+    @RequestMapping(value = "file/ms-slice/{workId}/{subjectId}/{fileName}", method = { RequestMethod.PUT, RequestMethod.POST })
+    public void upload(@PathVariable Long workId,@PathVariable Integer subjectId,@PathVariable String fileName,
+                       HttpServletRequest request,
+                       HttpServletResponse response) throws IOException{
+        Student student = studentRepo.findByWorkIdAndExamNumber(workId,fileName);
+        Subject subject = Subject.values()[subjectId-1];
+        String savePath = systemConfig.getImageDir() + File.separator + workId + File.separator + subject
+                + File.separator + student.getAreaCode();
+        File out = new File(savePath);
+        if (!out.exists()) {
+            out.mkdirs();
+        }
+        File outFile = new File(savePath + File.separator + student.getExamNumber() + ".jpg");
+        InputStream inputStream = request.getInputStream();
+        FileCopyUtils.copy(request.getInputStream(), new FileOutputStream(outFile));
+
+        // 生成缩略图
+        String thumbDir = systemConfig.getThumbDir() + File.separator + workId + File.separator + subject
+                + File.separator + student.getAreaCode();
+        File thumb = new File(thumbDir);
+        if (!thumb.exists()) {
+            thumb.mkdirs();
+        }
+        BufferedImage bufferedImage = ImageCompression.compress(outFile, compressionConfig);
+        String thumbFileName = thumbDir + File.separator + student.getExamNumber() + ".jpg";
+        ImageIO.write(bufferedImage, "jpg", new File(thumbFileName));
+
+
+    }
+
+    @RequestMapping(value = "subject/collect-config", method = RequestMethod.POST)
+    public boolean updateConfig(@RequestBody  CollectSubjectDTO collectSubjectDTO){
+        Subject subject = Subject.values()[collectSubjectDTO.getSubjectId()-1];
+        Work activeWork = workRepo.findByActiveTrue();
+        MarkSubject markSubject = markSubjectRepo.findOne(activeWork.getId() + "-" + subject.toString());
+        String config = Optional.ofNullable(collectSubjectDTO.getCollectConfig())
+                .map(Object::toString)
+                .map(s -> s.substring(1,s.length()-1))
+                .map(s -> s.replaceAll("\\\\","")).get();
+        markSubject.setCollectConfig(config);
+        markSubjectRepo.save(markSubject);
+        return true;
+    }
+}

+ 59 - 0
stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/api/ImageApi.java

@@ -0,0 +1,59 @@
+package cn.com.qmth.stmms.ms.collect.api;
+
+import cn.com.qmth.stmms.ms.commons.config.SystemConfig;
+import cn.com.qmth.stmms.ms.commons.utils.image.ImageCompression;
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Created by zhengmin on 2017/2/24.
+ */
+@RestController
+@RequestMapping("api/images")
+public class ImageApi {
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @Autowired
+    private SystemConfig systemConfig;
+
+    @RequestMapping(value = "{paperId}/rotate",method = RequestMethod.GET)
+    public ResponseEntity rotate(@PathVariable Long paperId,
+                                 @RequestParam int degree){
+        Paper paper = paperRepo.findOne(paperId);
+        Path thumbPath = Paths.get(systemConfig.getThumbDir(),String.valueOf(paper.getWorkId()),paper.getSubject().toString(),paper.getAreaCode(),paper.getExamNumber() + ".jpg");
+        Path imagePath = Paths.get(systemConfig.getImageDir(),String.valueOf(paper.getWorkId()),paper.getSubject().toString(),paper.getAreaCode(),paper.getExamNumber() + ".jpg");
+        try {
+            File thumbFile = thumbPath.toFile();
+            if(thumbFile.exists()) {
+                InputStream is = new FileInputStream(thumbFile);
+                BufferedImage image = ImageIO.read(is);
+                ImageCompression.rotate(thumbFile, thumbFile, degree);
+                is.close();
+            }
+            File imageFile = imagePath.toFile();
+            if(imageFile.exists()){
+                InputStream is = new FileInputStream(imageFile);
+                BufferedImage image = ImageIO.read(is);
+                ImageCompression.rotate(imageFile, imageFile, degree);
+                is.close();
+            }
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException ioe){
+            ioe.printStackTrace();
+        }
+        return new ResponseEntity(HttpStatus.OK);
+    }
+}

+ 81 - 0
stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/dto/CollectStuDTO.java

@@ -0,0 +1,81 @@
+package cn.com.qmth.stmms.ms.collect.dto;
+
+/**
+ * Created by dizhi on 2016/12/24.
+ */
+public class CollectStuDTO {
+
+    private Long examId;
+    private String examNumber;
+    private String name;
+    private String siteCode;
+    private String roomCode;
+    private boolean absent;
+
+    private boolean manual;
+    private String uploadTime;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getSiteCode() {
+        return siteCode;
+    }
+
+    public void setSiteCode(String siteCode) {
+        this.siteCode = siteCode;
+    }
+
+    public String getRoomCode() {
+        return roomCode;
+    }
+
+    public void setRoomCode(String roomCode) {
+        this.roomCode = roomCode;
+    }
+
+    public boolean isAbsent() {
+        return absent;
+    }
+
+    public void setAbsent(boolean absent) {
+        this.absent = absent;
+    }
+
+    public boolean isManual() {
+        return manual;
+    }
+
+    public void setManual(boolean manual) {
+        this.manual = manual;
+    }
+
+    public String getUploadTime() {
+        return uploadTime;
+    }
+
+    public void setUploadTime(String uploadTime) {
+        this.uploadTime = uploadTime;
+    }
+}

+ 52 - 0
stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/dto/CollectSubjectDTO.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.stmms.ms.collect.dto;
+
+/**
+ * Created by dizhi on 2016/12/24.
+ */
+public class CollectSubjectDTO {
+
+    private Integer id;
+    private String name;
+    private Integer subjectId;
+    private Object collectConfig;
+
+    public CollectSubjectDTO() {
+    }
+
+    public CollectSubjectDTO(Integer id, String name) {
+        this.id = id;
+        this.name = name;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Object getCollectConfig() {
+        return collectConfig;
+    }
+
+    public void setCollectConfig(Object collectConfig) {
+        this.collectConfig = collectConfig;
+    }
+
+    public Integer getSubjectId() {
+        return subjectId;
+    }
+
+    public void setSubjectId(Integer subjectId) {
+        this.subjectId = subjectId;
+    }
+}

+ 47 - 0
stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/dto/LoginDTO.java

@@ -0,0 +1,47 @@
+package cn.com.qmth.stmms.ms.collect.dto;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by dizhi on 2016/12/24.
+ */
+public class LoginDTO {
+
+    private String name;
+    private Long examId;
+    private String examName;
+    private List<CollectSubjectDTO> subjects = new ArrayList<>();
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getExamName() {
+        return examName;
+    }
+
+    public void setExamName(String examName) {
+        this.examName = examName;
+    }
+
+    public List<CollectSubjectDTO> getSubjects() {
+        return subjects;
+    }
+
+    public void setSubjects(List<CollectSubjectDTO> subjects) {
+        this.subjects = subjects;
+    }
+}

+ 38 - 0
stmms-ms-commons/pom.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>stmms-ms-parent</artifactId>
+        <groupId>cn.com.qmth</groupId>
+        <version>${project.version}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>stmms-ms-commons</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+        </dependency>
+        <dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-jpa</artifactId>
+		</dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>net.coobird</groupId>
+            <artifactId>thumbnailator</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>

+ 58 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/config/ImageCompressionConfig.java

@@ -0,0 +1,58 @@
+package cn.com.qmth.stmms.ms.commons.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created by zhengmin on 2017/2/27.
+ */
+@Component
+@ConfigurationProperties(prefix = "sys.config.compression")
+public class ImageCompressionConfig {
+
+    private Integer minWith = 1200;
+    private Integer minHeight = 800;
+    private Integer percent;
+    private Integer width;
+    private Integer height;
+
+    public Integer getMinWith() {
+        return minWith;
+    }
+
+    public void setMinWith(Integer minWith) {
+        this.minWith = minWith;
+    }
+
+    public Integer getMinHeight() {
+        return minHeight;
+    }
+
+    public void setMinHeight(Integer minHeight) {
+        this.minHeight = minHeight;
+    }
+
+    public Integer getPercent() {
+        return percent;
+    }
+
+    public void setPercent(Integer percent) {
+        this.percent = percent;
+    }
+
+    public Integer getWidth() {
+        return width;
+    }
+
+    public void setWidth(Integer width) {
+        this.width = width;
+    }
+
+    public Integer getHeight() {
+        return height;
+    }
+
+    public void setHeight(Integer height) {
+        this.height = height;
+    }
+}

+ 46 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/config/ImageServerConfig.java

@@ -0,0 +1,46 @@
+package cn.com.qmth.stmms.ms.commons.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Created by zhengmin on 2017/2/27.
+ */
+@Component
+@ConfigurationProperties(prefix = "sys.config.imageServer")
+public class ImageServerConfig {
+
+    private String ip;
+    private String port;
+
+    public String getIp() {
+        try {
+            if(ip == null || ip.isEmpty()) {
+               ip = InetAddress.getLocalHost().getHostAddress();
+
+            }
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public String getPort() {
+        return (port == null || port.isEmpty()) ? "3000" : port;
+    }
+
+    public void setPort(String port) {
+        this.port = port;
+    }
+
+    public String getImageServer(){
+        return "http://" + this.getIp() + ":" + this.getPort();
+    }
+}

+ 60 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/config/SystemConfig.java

@@ -0,0 +1,60 @@
+package cn.com.qmth.stmms.ms.commons.config;
+
+import org.assertj.core.internal.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Random;
+import java.util.UUID;
+
+/**
+ * 系统配置
+ * Created by zhengmin on 2016/11/18.
+ */
+@Component
+@ConfigurationProperties(prefix = "sys.config")
+public class SystemConfig {
+
+    @Autowired
+    private ImageServerConfig imageServerConfig;
+
+    /**
+     * 原图目录
+     */
+    private String imageDir;
+
+    /**
+     * 缩略图目录
+     */
+    private String thumbDir;
+
+    public String getImageDir() {
+        return imageDir;
+    }
+
+    public void setImageDir(String imageDir) {
+        this.imageDir = imageDir;
+    }
+
+    public String getThumbDir() {
+        return thumbDir;
+    }
+
+    public void setThumbDir(String thumbDir) {
+        this.thumbDir = thumbDir;
+    }
+
+    public String getThumbUrl(Long workId, String subject, String areaCode, String examNumber){
+        return imageServerConfig.getImageServer() + "/thumbs/" + String.valueOf(workId) + "/"
+                + subject + "/" + areaCode + "/" + examNumber + ".jpg?random=" + UUID.randomUUID().toString();
+    }
+
+    public String getImageUrl(Long workId,String subject,String areaCode,String examNumber){
+        return imageServerConfig.getImageServer() + "/images/" + String.valueOf(workId) + "/"
+                + subject + "/" + areaCode + "/" + examNumber + ".jpg?random=" + UUID.randomUUID().toString();
+    }
+
+}

+ 60 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ColumnSetting.java

@@ -0,0 +1,60 @@
+package cn.com.qmth.stmms.ms.commons.utils.excel;
+
+/**
+ * Created by zhengmin on 2016/6/22.
+ */
+public class ColumnSetting implements Comparable<ColumnSetting> {
+
+    private String header;
+    private String fieldName;
+    private int width;
+    private int index;
+
+    public ColumnSetting(String header,String fieldName, int width, int index) {
+        this.header = header;
+        this.fieldName = fieldName;
+        this.width = width;
+        this.index = index;
+    }
+
+    public String getHeader() {
+        return header;
+    }
+
+    public void setHeader(String header) {
+        this.header = header;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    public String getFieldName() {
+		return fieldName;
+	}
+
+	public void setFieldName(String fieldName) {
+		this.fieldName = fieldName;
+	}
+
+	@Override
+    public int compareTo(ColumnSetting columnSetting) {
+        if (index < columnSetting.getIndex())
+            return - 1 ;
+        if (index > columnSetting.getIndex())
+            return 1 ;
+        return 0 ;
+    }
+}

+ 48 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelError.java

@@ -0,0 +1,48 @@
+package cn.com.qmth.stmms.ms.commons.utils.excel;
+/**
+ * 
+ * @Description: excel导入错误
+ * @author ting.yin
+ * @date 2016年8月19日
+ */
+public class ExcelError {
+
+	/**
+	 * 错误行数
+	 */
+	private int row;
+
+	/**
+	 * 错误类型
+	 */
+	private String excelErrorType;
+
+	public ExcelError() {
+
+	}
+
+	public ExcelError(int row, String excelErrorType) {
+		this.row = row;
+		this.excelErrorType = excelErrorType;
+	}
+	
+	public ExcelError(String excelErrorType) {
+		this.excelErrorType = excelErrorType;
+	}
+	public int getRow() {
+		return row;
+	}
+
+	public void setRow(int row) {
+		this.row = row;
+	}
+
+	public String getExcelErrorType() {
+		return excelErrorType;
+	}
+
+	public void setExcelErrorType(String excelErrorType) {
+		this.excelErrorType = excelErrorType;
+	}
+
+}

+ 34 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelProperty.java

@@ -0,0 +1,34 @@
+package cn.com.qmth.stmms.ms.commons.utils.excel;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Created by zhengmin on 2016/6/22.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelProperty {
+	/**
+	 * 导出时列名
+	 */
+    String name() default "";
+    
+	/**
+	 * 导出时列宽
+	 */
+    int width() default 0;
+	/**
+	 * 排序
+	 */
+    int index();
+    /**
+     * 类型
+     * 0:导入(读excel)
+     * 1:导出(写excel)
+     * 2:导入&导出
+     */
+    int type() default 2;
+}

+ 89 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelReader.java

@@ -0,0 +1,89 @@
+package cn.com.qmth.stmms.ms.commons.utils.excel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.ss.usermodel.*;
+
+/**
+ * 
+ * @Description: 读取excel
+ * @author ting.yin
+ * @date 2016年8月19日
+ */
+public class ExcelReader extends ExcelUtils {
+
+	public ExcelReader(Class<?> dataClass) {
+		super(dataClass,true);
+	}
+
+	/**
+	 * 
+	 * @param inputStream
+	 *            输入流
+	 * @param handle
+	 *            单个对象处理器
+	 * @return 错误信息集合
+	 */
+	public List<ExcelError> reader(InputStream inputStream,
+			ExcelReaderHandle handle) {
+		List<ExcelError> excelErrors = new ArrayList<ExcelError>();
+		try {
+			Workbook wb = WorkbookFactory.create(inputStream);
+			Sheet sheet = wb.getSheetAt(0);
+			for (int i = 1; i <= sheet.getLastRowNum(); i++) {
+				Row row = sheet.getRow(i);
+				if (row == null) {
+					return excelErrors;
+				}
+				Object dto = getDataClass().newInstance();
+//				FieldAccess access = FieldAccess.get(getDataClass());
+				for (int j = 0; j < this.getColumnSettings().size(); j++) {
+					ColumnSetting columnSetting = this.getColumnSettings().get(j);
+					Cell cell = row.getCell(columnSetting.getIndex() - 1);
+					Object obj = convert(cell);
+					Field field = getDataClass().getDeclaredField(columnSetting.getFieldName());
+					field.setAccessible(true);
+					field.set(dto, obj);
+				}
+				ExcelError error = handle.handle(dto);
+				if (error != null) {
+					error.setRow(i+1);
+					excelErrors.add(error);
+				}
+			}
+		}catch (InvalidFormatException e) {
+				e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			try {
+				inputStream.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		return excelErrors;
+	}
+
+	private Object convert(Cell cell) {
+		if(cell!=null){
+			switch (cell.getCellType()) {
+			case Cell.CELL_TYPE_STRING:
+				return cell.getStringCellValue().toString();
+			case Cell.CELL_TYPE_BOOLEAN:
+				return String.valueOf(cell.getBooleanCellValue());
+			case Cell.CELL_TYPE_NUMERIC:
+				return Math.round(cell.getNumericCellValue());
+			}
+		}
+		
+		return null;
+	}
+}

+ 7 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelReaderHandle.java

@@ -0,0 +1,7 @@
+package cn.com.qmth.stmms.ms.commons.utils.excel;
+
+public interface ExcelReaderHandle {
+	
+	ExcelError handle(Object dto);
+
+}

+ 70 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelUtils.java

@@ -0,0 +1,70 @@
+package cn.com.qmth.stmms.ms.commons.utils.excel;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2016/8/17.
+ */
+@SuppressWarnings("rawtypes")
+public abstract class ExcelUtils {
+
+	private Class dataClass;
+    private List<ColumnSetting> columnSettings;
+    
+    public ExcelUtils(Class<?> dataClass , boolean isRead){
+        this.dataClass = dataClass;
+        this.columnSettings = getColumnSettings(dataClass,isRead);
+    }
+
+    public Class getDataClass() {
+        return dataClass;
+    }
+
+    public void setDataClass(Class dataClass) {
+        this.dataClass = dataClass;
+    }
+
+    public List<ColumnSetting> getColumnSettings() {
+        return columnSettings;
+    }
+
+    public void setColumnSettings(List<ColumnSetting> columnSettings) {
+        this.columnSettings = columnSettings;
+    }
+
+    /**
+     * 提取ExcelProperty注解类的字段信息
+     * @param dataClass 需要解析excel的数据类型
+     * @return
+     */
+    protected List<ColumnSetting> getColumnSettings(Class<?> dataClass, boolean isRead){
+		List<ColumnSetting> columnSettings = new ArrayList<>();
+		Field[] fileds = dataClass.getDeclaredFields();
+		for (Field field : fileds) {
+			ExcelProperty exportProperty = field.getAnnotation(ExcelProperty.class);
+			if (exportProperty != null) {
+				if (isRead) {
+					if (exportProperty.type() == 0 || exportProperty.type() == 2) {
+						ColumnSetting columnSetting = new ColumnSetting(
+								exportProperty.name(),field.getName(),exportProperty.width(),
+								exportProperty.index());
+						columnSettings.add(columnSetting);
+					}
+				}else{
+					if (exportProperty.type() == 1 || exportProperty.type() == 2) {
+						ColumnSetting columnSetting = new ColumnSetting(
+								exportProperty.name(), field.getName(),exportProperty.width(),
+								exportProperty.index());
+						columnSettings.add(columnSetting);
+					}
+				}
+			}
+		}
+		Collections.sort(columnSettings);
+		return columnSettings;
+    }
+    
+}

+ 187 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExcelWriter.java

@@ -0,0 +1,187 @@
+package cn.com.qmth.stmms.ms.commons.utils.excel;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.poi.xssf.usermodel.*;
+
+/**
+ * Created by dizhi on 2016/6/19.
+ */
+public class ExcelWriter extends ExcelUtils{
+
+
+    public ExcelWriter(Class<?> dataClass){
+        super(dataClass,false);
+    }
+
+    /**
+     * 写入excel
+     * @param sheetName sheet名称
+     * @param dataset 数据集合
+     * @param out 输出流
+     */
+    public void write(String sheetName,Collection<?> dataset, OutputStream out) {
+        // 声明一个工作薄
+        XSSFWorkbook workbook = new XSSFWorkbook();
+        // 生成一个表格
+        XSSFSheet sheet = workbook.createSheet(sheetName);
+
+        // 设置表格默认列宽度为15个字节
+        sheet.setDefaultColumnWidth((short) 15);
+        // 生成一个样式
+        XSSFCellStyle style = workbook.createCellStyle();
+        // 设置这些样式
+//        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
+//        style.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
+//        style.setBorderBottom(XSSFCellStyle.BORDER_THIN);
+//        style.setBorderLeft(XSSFCellStyle.BORDER_THIN);
+//        style.setBorderRight(XSSFCellStyle.BORDER_THIN);
+//        style.setBorderTop(XSSFCellStyle.BORDER_THIN);
+//        style.setAlignment(XSSFCellStyle.ALIGN_CENTER);
+        // 生成一个字体
+//        XSSFFont font = workbook.createFont();
+//        font.setColor(HSSFColor.VIOLET.index);
+//        font.setFontHeightInPoints((short) 12);
+//        font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
+//        // 把字体应用到当前的样式
+//        style.setFont(font);
+//        // 生成并设置另一个样式
+//        XSSFCellStyle style2 = workbook.createCellStyle();
+//        style2.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);
+//        style2.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
+//        style2.setBorderBottom(XSSFCellStyle.BORDER_THIN);
+//        style2.setBorderLeft(XSSFCellStyle.BORDER_THIN);
+//        style2.setBorderRight(XSSFCellStyle.BORDER_THIN);
+//        style2.setBorderTop(XSSFCellStyle.BORDER_THIN);
+//        style2.setAlignment(XSSFCellStyle.ALIGN_CENTER);
+//        style2.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
+//        // 生成另一个字体
+//        XSSFFont font2 = workbook.createFont();
+//        font2.setBoldweight(XSSFFont.BOLDWEIGHT_NORMAL);
+        // 把字体应用到当前的样式
+        //style2.setFont(font2);
+
+        // 声明一个画图的顶级管理器
+        //HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
+        // 定义注释的大小和位置,详见文档
+//        XSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0,
+//                0, 0, 0, (short) 4, 2, (short) 6, 5));
+//        // 设置注释内容
+//        comment.setString(new HSSFRichTextString("可以在POI中添加注释!"));
+//        // 设置注释作者,当鼠标移动到单元格上是可以在状态栏中看到该内容.
+//        comment.setAuthor("leno");
+
+        List<ColumnSetting> columnSettings = this.getColumnSettings();
+
+        // 产生表格标题行
+        XSSFRow row = sheet.createRow(0);
+        for (short i = 0; i < columnSettings.size(); i++) {
+            XSSFCell cell = row.createCell(i);
+            cell.setCellStyle(style);
+            XSSFRichTextString text = new XSSFRichTextString(columnSettings.get(i).getHeader());
+            cell.setCellValue(text);
+            if(columnSettings.get(i).getWidth() > 0){
+                sheet.setColumnWidth(i,columnSettings.get(i).getWidth()*256);
+            }
+        }
+
+        // 遍历集合数据,产生数据行
+        //Iterator<?> it = dataset.iterator();
+        int index = 0;
+        for(Object obj : dataset) {
+            index++;
+            row = sheet.createRow(index);
+            //T t = (T) it.next();
+            // 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
+            for (short i = 0; i < columnSettings.size(); i++) {
+                XSSFCell cell = row.createCell(i);
+                //cell.setCellStyle(style2);
+                String fieldName = columnSettings.get(i).getFieldName();
+
+                try {
+                	Field field=this.getDataClass().getDeclaredField(fieldName);
+                	field.setAccessible(true);
+                    Object value = field.get(obj);
+                    // 判断值的类型后进行强制类型转换
+                    String textValue = null;
+                    // if (value instanceof Integer) {
+                    // int intValue = (Integer) value;
+                    // cell.setCellValue(intValue);
+                    // } else if (value instanceof Float) {
+                    // float fValue = (Float) value;
+                    // textValue = new HSSFRichTextString(
+                    // String.valueOf(fValue));
+                    // cell.setCellValue(textValue);
+                    // } else if (value instanceof Double) {
+                    // double dValue = (Double) value;
+                    // textValue = new HSSFRichTextString(
+                    // String.valueOf(dValue));
+                    // cell.setCellValue(textValue);
+                    // } else if (value instanceof Long) {
+                    // long longValue = (Long) value;
+                    // cell.setCellValue(longValue);
+                    // }
+                    if (value instanceof Boolean) {
+                        boolean bValue = (Boolean) value;
+                        textValue = "是";
+                        if (!bValue) {
+                            textValue = "否";
+                        }
+                    } else if (value instanceof Date) {
+                        Date date = (Date) value;
+                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+                        textValue = sdf.format(date);
+                    }
+                    else {
+                        // 其它数据类型都当作字符串简单处理
+                        textValue = String.valueOf(value);
+                    }
+                    // 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成
+                    if (textValue != null) {
+                        Pattern p = Pattern.compile("^//d+(//.//d+)?$");
+                        Matcher matcher = p.matcher(textValue);
+                        if (matcher.matches()) {
+                            // 是数字当作double处理
+                            cell.setCellValue(Double.parseDouble(textValue));
+                        } else {
+                            XSSFRichTextString richString = new XSSFRichTextString(
+                                    textValue);
+
+                            cell.setCellValue(richString);
+                        }
+                    }
+                } catch (NoSuchFieldException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                } catch (IllegalAccessException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                } catch (SecurityException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                } catch (IllegalArgumentException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                } finally {
+                    // 清理资源
+                }
+            }
+            
+        }
+        try {
+            workbook.write(out);
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+    }
+}

+ 34 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/excel/ExportUtils.java

@@ -0,0 +1,34 @@
+package cn.com.qmth.stmms.ms.commons.utils.excel;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.net.URLEncoder;
+import java.util.Collection;
+
+
+/*
+ * excel导出工具
+ */
+public class ExportUtils {
+
+    private static final String DEFALUT_CONTENT_TYPE = "application/vnd.ms-excel";
+
+    private static final String DEFALUT_EXT = ".xlsx";
+
+    public static void exportEXCEL(String fileName,Class<?> dataClass,
+                             Collection<?> dataset,HttpServletResponse response) {
+        try {
+        	
+            response.setHeader("Content-Disposition", "inline; filename="
+                    +URLEncoder.encode(fileName, "UTF-8") + DEFALUT_EXT);
+            response.setContentType(DEFALUT_CONTENT_TYPE);
+            ServletOutputStream outputStream = response.getOutputStream();
+            ExcelWriter excelExporter = new ExcelWriter(dataClass);
+            excelExporter.write("sheet1",dataset,outputStream);
+            outputStream.flush();
+            outputStream.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 63 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/image/ImageCompression.java

@@ -0,0 +1,63 @@
+package cn.com.qmth.stmms.ms.commons.utils.image;
+
+import cn.com.qmth.stmms.ms.commons.config.ImageCompressionConfig;
+import net.coobird.thumbnailator.Thumbnails;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * 图片压缩
+ * Created by zhengmin on 2016/11/18.
+ */
+public class ImageCompression {
+
+    /**
+     * 分辨率压缩
+     * @param in 图片文件输入流
+     * @return
+     * @throws IOException
+     */
+    public static BufferedImage compress(File in, ImageCompressionConfig config) throws IOException {
+        if(config == null){
+            return ImageIO.read(in);
+        }
+        BufferedImage image = ImageIO.read(in);
+        int originWidth = image.getWidth();
+        int originHeight = image.getHeight();
+        int sizeWidth = config.getMinWith();
+        int sizeHeight = config.getMinHeight();
+
+        if(config.getPercent() != null && config.getPercent() > 0 && config.getPercent() <= 100){
+            float percent = config.getPercent()/100;
+            sizeWidth = (int)(sizeWidth*percent);
+            sizeHeight = (int)(sizeHeight*percent);
+            if(sizeWidth < config.getMinWith()){
+                sizeWidth = config.getMinWith();
+            }
+            if(sizeHeight < config.getMinHeight()){
+                sizeHeight = config.getMinHeight();
+            }
+        }
+
+        int width = sizeWidth;
+        int height = sizeHeight;
+
+
+        if(originWidth < originHeight){
+            width = sizeHeight;
+            height = sizeWidth;
+        }
+        return Thumbnails.of(image)
+                .size(width, height)
+                .outputFormat("jpg")
+                .asBufferedImage();
+    }
+
+    public static void rotate(File in,File out,int degree) throws IOException {
+        BufferedImage image = ImageIO.read(in);
+        Thumbnails.of(image).size(image.getWidth(),image.getHeight()).rotate(degree).toFile(out);
+    }
+}

+ 104 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/specification/PagingAndSortingDTO.java

@@ -0,0 +1,104 @@
+package cn.com.qmth.stmms.ms.commons.utils.specification;
+
+/**
+ * 分页DTO
+ * @author xudengqi
+ * 2016年8月18日
+ */
+public class PagingAndSortingDTO {
+	
+	private int page;
+	
+	private int size;
+	
+	private int pageCount;
+	
+	private String[] properties;
+	
+	private String order;
+	
+	private long totalCount;
+	
+	private Object data;
+	
+	
+    protected PagingAndSortingDTO() {
+    }
+
+    public PagingAndSortingDTO(int page, int size) {
+        this.page = page;
+        this.size = size;
+    }
+
+    public PagingAndSortingDTO(Object data){
+        this.data = data;
+    }
+
+    public PagingAndSortingDTO(int page, int size, int pageCount,long totalCount, Object data) {
+        this.page = page;
+        this.size = size;
+        this.pageCount = pageCount;
+        this.data = data;
+        this.totalCount = totalCount;
+    }
+
+	public int getPage() {
+		return page;
+	}
+
+	public void setPage(int page) {
+		this.page = page;
+	}
+
+	public int getSize() {
+		return size;
+	}
+
+	public void setSize(int size) {
+		this.size = size;
+	}
+
+	public int getPageCount() {
+		return pageCount;
+	}
+
+	public void setPageCount(int pageCount) {
+		this.pageCount = pageCount;
+	}
+
+	public String[] getProperties() {
+		return properties;
+	}
+
+	public void setProperties(String[] properties) {
+		this.properties = properties;
+	}
+
+	public String getOrder() {
+		return order;
+	}
+
+	public void setOrder(String order) {
+		this.order = order;
+	}
+
+	public long getTotalCount() {
+		return totalCount;
+	}
+
+	public void setTotalCount(long totalCount) {
+		this.totalCount = totalCount;
+	}
+
+	public Object getData() {
+		return data;
+	}
+
+	public void setData(Object data) {
+		this.data = data;
+	}
+	
+    
+    
+
+}

+ 74 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/specification/PagingAndSortingSpecification.java

@@ -0,0 +1,74 @@
+package cn.com.qmth.stmms.ms.commons.utils.specification;
+
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
+
+/**
+ * 构建动态查询、分页、排序
+ * @author xudengqi
+ * 2016年8月18日
+ */
+public abstract class PagingAndSortingSpecification implements QuerySpecification{
+	
+	private Integer page;
+    private Integer size;
+    private String order;
+    private String[] properties;
+
+    public Integer getPage() {
+        return page;
+    }
+
+    public void setPage(Integer page) {
+        this.page = page;
+    }
+
+    public Integer getSize() {
+        return size;
+    }
+
+    public void setSize(Integer size) {
+        this.size = size;
+    }
+
+    public String getOrder() {
+        return order;
+    }
+
+    public void setOrder(String order) {
+        this.order = order;
+    }
+
+    public String[] getProperties() {
+        return properties;
+    }
+
+    public void setProperties(String[] properties) {
+        this.properties = properties;
+    }
+
+    @Override
+    public abstract Specification<?> getSpecification();
+
+    @Override
+    public PageRequest getPageRequest(){
+        PageRequest pageRequest = null;
+
+        if(order == null || order.trim().length() == 0){
+            order = "ASC";
+        }
+        if(properties != null){
+            Sort sort = new Sort(Sort.Direction.valueOf(order),properties);
+            pageRequest = new PageRequest(page,size,sort);
+        }
+        else if(page != null && size != null){
+            pageRequest = new PageRequest(page,size);
+        }
+        else{
+            //TODO 暂时返还一条数据
+            pageRequest = new PageRequest(0,1);
+        }
+        return pageRequest;
+    }
+}

+ 16 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/specification/QuerySpecification.java

@@ -0,0 +1,16 @@
+package cn.com.qmth.stmms.ms.commons.utils.specification;
+
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.jpa.domain.Specification;
+
+/**
+ * 通过Specification动态构建动态查询、分页、排序
+ * @author xudengqi
+ * 2016年8月18日
+ */
+public interface QuerySpecification {
+	
+	Specification<?> getSpecification();
+
+    PageRequest getPageRequest();
+}

+ 51 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/web/PageableDTO.java

@@ -0,0 +1,51 @@
+package cn.com.qmth.stmms.ms.commons.web;
+
+/**
+ * Created by zhengmin on 2017/2/24.
+ */
+public class PageableDTO {
+
+    private Object data;
+    private Long totalCount;
+    private Integer pageCount;
+    private Integer page;
+
+    public PageableDTO(Object data, Long totalCount, Integer pageCount, Integer page) {
+        this.data = data;
+        this.totalCount = totalCount;
+        this.pageCount = pageCount;
+        this.page = page;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+    public Long getTotalCount() {
+        return totalCount;
+    }
+
+    public void setTotalCount(Long totalCount) {
+        this.totalCount = totalCount;
+    }
+
+    public Integer getPageCount() {
+        return pageCount;
+    }
+
+    public void setPageCount(Integer pageCount) {
+        this.pageCount = pageCount;
+    }
+
+    public Integer getPage() {
+        return page;
+    }
+
+    public void setPage(Integer page) {
+        this.page = page;
+    }
+}

+ 24 - 0
stmms-ms-commons/src/test/java/cn/com/qmth/stmms/ms/commons/image/ImageThumberTest.java

@@ -0,0 +1,24 @@
+package cn.com.qmth.stmms.ms.commons.image;
+
+import cn.com.qmth.stmms.ms.commons.utils.image.ImageCompression;
+import org.junit.Test;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * Created by zhengmin on 2016/11/18.
+ */
+public class ImageThumberTest {
+
+    @Test
+    public void test() throws IOException {
+        String s = "SC:1,SX:1,SM:0";
+        String r = s.replaceFirst("Ss:[0-1]","SX:3");
+        int c = 1;
+        System.out.println(c++);
+    }
+}

+ 29 - 0
stmms-ms-core/pom.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>stmms-ms-parent</artifactId>
+        <groupId>cn.com.qmth</groupId>
+        <version>${project.version}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>stmms-ms-core</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-validator</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-commons</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 87 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/ExamQuestion.java

@@ -0,0 +1,87 @@
+package cn.com.qmth.stmms.ms.core.domain;
+
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * 考题
+ * Created by zhengmin on 2016/9/21.
+ */
+@Entity
+public class ExamQuestion implements Serializable{
+
+    private static final long serialVersionUID = 966670964450775040L;
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @NotNull
+    private String areaCode;
+
+    @NotNull
+    private String name;
+
+    @NotNull
+    @Enumerated(value = EnumType.STRING)
+    private Subject subject;
+
+    @NotNull
+    private Long workId;
+    
+    private String areaName;
+
+    public ExamQuestion(String areaCode, Subject subject,Long workId,String areaName) {
+        this.areaCode = areaCode;
+        this.name = subject.getName() + this.areaCode;
+        this.subject = subject;
+        this.workId = workId;
+        this.areaName = areaName;
+    }
+
+    public ExamQuestion() {
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getAreaCode() {
+        return areaCode;
+    }
+
+    public void setAreaCode(String areaCode) {
+        this.areaCode = areaCode;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Subject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(Subject subject) {
+        this.subject = subject;
+    }
+
+	public String getAreaName() {
+		return areaName;
+	}
+
+	public void setAreaName(String areaName) {
+		this.areaName = areaName;
+	}
+}

+ 166 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Level.java

@@ -0,0 +1,166 @@
+package cn.com.qmth.stmms.ms.core.domain;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * 分档档次
+ * Created by zhengmin on 2016/9/21.
+ */
+@Entity
+@Table(indexes = {
+        @Index(name = "idx_level_workId_code",columnList = "workId,code",unique = true)})
+public class Level implements Serializable{
+
+
+    private static final long serialVersionUID = -5290818783456310642L;
+
+    public int getLevelValue() {
+        return levelValue;
+    }
+
+    public void setLevelValue(int levelValue) {
+        this.levelValue = levelValue;
+    }
+
+    public Long getWorkId() {
+        return workId;
+    }
+
+    public void setWorkId(Long workId) {
+        this.workId = workId;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public static enum LevelType{
+        /**
+         * 非录取
+         */
+        UNADMIT,
+        /**
+         * 录取
+         */
+        ADMITED
+    }
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private Long workId;
+
+    @NotNull
+    private String code;
+
+    private int levelValue;
+
+    @NotNull
+    private Integer maxScore;
+
+    @NotNull
+    private Integer minScore;
+
+    /**
+     * 给分间隔
+     */
+    private int intervalScore = 1;
+
+    @NotNull
+    private Integer weight;
+
+    @Enumerated(value = EnumType.ORDINAL)
+    private LevelType levelType;
+
+    /**
+     * 非录取挡位的给分集合
+     */
+    private String scoreList;
+
+    /**
+     * 占比阈值。percent thredhold,0-100
+     */
+    private int pt = 0;
+
+    public Level(){}
+
+    public Level(Long workId,String code, int maxScore, int minScore, LevelType levelType,Integer weight) {
+        this.workId = workId;
+        this.code = code;
+        this.maxScore = maxScore;
+        this.minScore = minScore;
+        this.levelType = levelType;
+        this.weight = weight;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public Integer getMaxScore() {
+        return maxScore;
+    }
+
+    public void setMaxScore(Integer maxScore) {
+        this.maxScore = maxScore;
+    }
+
+    public Integer getMinScore() {
+        return minScore;
+    }
+
+    public void setMinScore(Integer minScore) {
+        this.minScore = minScore;
+    }
+
+    public int getIntervalScore() {
+        return intervalScore;
+    }
+
+    public void setIntervalScore(int intervalScore) {
+        this.intervalScore = intervalScore;
+    }
+
+    public Integer getWeight() {
+        return weight;
+    }
+
+    public void setWeight(Integer weight) {
+        this.weight = weight;
+    }
+
+    public LevelType getLevelType() {
+        return levelType;
+    }
+
+    public void setLevelType(LevelType levelType) {
+        this.levelType = levelType;
+    }
+
+    public String getScoreList() {
+        return scoreList;
+    }
+
+    public void setScoreList(String scoreList) {
+        this.scoreList = scoreList;
+    }
+
+    public int getPt() {
+        return pt;
+    }
+
+    public void setPt(int pt) {
+        this.pt = pt;
+    }
+}

+ 141 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/MarkLog.java

@@ -0,0 +1,141 @@
+package cn.com.qmth.stmms.ms.core.domain;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+/**
+ * 
+ * @Description: 操作记录
+ * @author ting.yin
+ * @date 2016年10月21日
+ */
+@Entity
+public class MarkLog implements Serializable {
+
+	private static final long serialVersionUID = -8376036816154911286L;
+
+	@Id
+	@GeneratedValue
+	private Long id;
+
+	private Long workId;
+
+	private MarkStage markStage;
+
+	private String loginName;
+	
+	private String markerName;
+
+	private String examNumber;
+	
+	private String secretNumber;
+
+	private String remark;
+	
+	private String result;
+
+	@Temporal(value = TemporalType.DATE)
+	private Date createdOn;
+
+	public MarkLog() {
+	}
+
+	public MarkLog(Long workId, MarkStage markStage, String loginName, String markerName,
+			String examNumber,String secretNumber,String result) {
+		this.workId = workId;
+		this.markStage = markStage;
+		this.loginName = loginName;
+		this.markerName = markerName;
+		this.examNumber = examNumber;
+		this.secretNumber = secretNumber;
+		this.result = result;
+		this.createdOn = new Date();
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getWorkId() {
+		return workId;
+	}
+
+	public void setWorkId(Long workId) {
+		this.workId = workId;
+	}
+
+	public MarkStage getMarkStage() {
+		return markStage;
+	}
+
+	public void setMarkStage(MarkStage markStage) {
+		this.markStage = markStage;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public Date getCreatedOn() {
+		return createdOn;
+	}
+
+	public void setCreatedOn(Date createdOn) {
+		this.createdOn = createdOn;
+	}
+
+	public String getResult() {
+		return result;
+	}
+
+	public void setResult(String result) {
+		this.result = result;
+	}
+
+	public String getLoginName() {
+		return loginName;
+	}
+
+	public void setLoginName(String loginName) {
+		this.loginName = loginName;
+	}
+
+	public String getMarkName() {
+		return markerName;
+	}
+
+	public void setMarkName(String markName) {
+		this.markerName = markName;
+	}
+
+	public String getExamNumber() {
+		return examNumber;
+	}
+
+	public void setExamNumber(String examNumber) {
+		this.examNumber = examNumber;
+	}
+
+	public String getSecretNumber() {
+		return secretNumber;
+	}
+
+	public void setSecretNumber(String secretNumber) {
+		this.secretNumber = secretNumber;
+	}
+
+}

+ 25 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/MarkStage.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.stmms.ms.core.domain;
+
+/**
+ * 评卷阶段
+ * Created by zhengmin on 2016/9/22.
+ */
+public enum MarkStage {
+
+    /**
+     * 初始
+     */
+    INIT,
+    /**
+     * 分档
+     */
+    LEVEL,
+    /**
+     * 打分
+     */
+    SCORE,
+    /**
+     * 结束
+     */
+    END
+}

+ 95 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/MarkSubject.java

@@ -0,0 +1,95 @@
+package cn.com.qmth.stmms.ms.core.domain;
+
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * 科目
+ * Created by zhengmin on 2016/9/21.
+ */
+@Entity
+public class MarkSubject implements Serializable{
+
+    private static final long serialVersionUID = -7205062745569303448L;
+
+    /**
+     * workId + "-" + subject
+     */
+    @Id
+    private String id;
+
+    private String name;
+
+    private Long workId;
+
+    private int totalScore = 100;
+
+    private String collectConfig;
+
+    @Enumerated(value = EnumType.ORDINAL)
+    private MarkStage stage;
+
+    public MarkSubject(Subject subject,Long workId) {
+        this.id = workId + "-" + subject;
+        this.name = subject.getName();
+        this.stage = MarkStage.INIT;
+    }
+
+    public MarkSubject() {
+    }
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(int totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public MarkStage getStage() {
+        return stage;
+    }
+
+    public void setStage(MarkStage stage) {
+        this.stage = stage;
+    }
+
+    public Long getWorkId(){
+        return Long.parseLong(this.getId().split("-")[0]);
+    }
+
+    public Subject getSubject(){
+        return Subject.valueOf(this.getId().split("-")[1]);
+    }
+
+    public void setWorkId(Long workId) {
+        this.workId = workId;
+    }
+
+    public String getCollectConfig() {
+        return collectConfig;
+    }
+
+    public void setCollectConfig(String collectConfig) {
+        this.collectConfig = collectConfig;
+    }
+}

+ 325 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Paper.java

@@ -0,0 +1,325 @@
+package cn.com.qmth.stmms.ms.core.domain;
+
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 试卷
+ * Created by zhengmin on 2016/9/21.
+ */
+@Entity
+@Table(indexes = {
+        @Index(name = "idx_paper_index",columnList = "idx"),
+        @Index(name = "idx_paper_exam_number",columnList = "examNumber"),
+        @Index(name = "idx_paper_area_code",columnList = "areaCode"),
+        @Index(name = "idx_paper_student_name",columnList = "studentName")})
+public class Paper implements Serializable{
+
+    private static final long serialVersionUID = 3200579901138269179L;
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @NotNull
+    private Long workId;
+
+    private String secretNumber;
+
+    private Long idx;
+
+    @NotNull
+    private String studentName;
+
+    @NotNull
+    private String examNumber;
+
+    @NotNull
+    @Enumerated(value = EnumType.STRING)
+    private Subject subject;
+
+    @NotNull
+    private Long questionId;
+
+    @NotNull
+    private String areaCode;
+
+    @NotNull
+    private String questionName;
+
+    private String level;
+
+    /**
+     * 建议重评档位
+     */
+    private String redoLevel;
+
+    private Double score;
+
+    /**
+     * 是否仲裁状态
+     */
+    private boolean isArbitrated;
+
+    private boolean isRejected;
+
+    /**
+     * 是否由科组长直接评卷
+     */
+    private boolean markByLeader;
+
+    /**
+     * 是否逻辑分档(系统定档)
+     */
+    private boolean markedLogic;
+
+    private Date updatedOn;
+
+    /**
+     * 采集时是否手工绑定
+     */
+    private boolean isManual;
+
+    private Date uploadedOn;
+    private int uploadedCount = 1;
+
+    /**
+     * 是否标记
+     */
+    private boolean isTagged;
+
+    public Paper(Long workId, Long idx, Subject subject, ExamQuestion examQuestion, Student student, boolean isManual) {
+        this.workId = workId;
+        this.idx = idx;
+        this.studentName = student.getName();
+        String examNumber = student.getExamNumber();
+        this.examNumber = examNumber;
+        this.subject = subject;
+        this.questionId = examQuestion.getId();
+        this.areaCode = examQuestion.getAreaCode();
+        this.questionName = examQuestion.getName();
+        this.secretNumber = subject.ordinal() + examQuestion.getAreaCode() + examNumber.substring(3,examNumber.length());
+        this.isManual = isManual;
+        this.uploadedOn = new Date();
+    }
+
+    public Paper() {
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getWorkId() {
+        return workId;
+    }
+
+    public void setWorkId(Long workId) {
+        this.workId = workId;
+    }
+
+
+    public String getStudentName() {
+        return studentName;
+    }
+
+    public void setStudentName(String studentName) {
+        this.studentName = studentName;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public Subject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(Subject subject) {
+        this.subject = subject;
+    }
+
+    public Long getQuestionId() {
+        return questionId;
+    }
+
+    public void setQuestionId(Long questionId) {
+        this.questionId = questionId;
+    }
+
+    public String getQuestionName() {
+        return questionName;
+    }
+
+    public void setQuestionName(String questionName) {
+        this.questionName = questionName;
+    }
+
+    public String getLevel() {
+        return level;
+    }
+
+    public void setLevel(String level) {
+        this.level = level;
+    }
+
+    public Double getScore() {
+        return score;
+    }
+
+    public void setScore(Double score) {
+        this.score = score;
+    }
+
+
+    public boolean isManual() {
+        return isManual;
+    }
+
+    public void setManual(boolean manual) {
+        isManual = manual;
+    }
+
+    public Date getUploadedOn() {
+        return uploadedOn;
+    }
+
+    public void setUploadedOn(Date uploadedOn) {
+        this.uploadedOn = uploadedOn;
+    }
+
+    public Long getIdx() {
+        return idx;
+    }
+
+    public void setIdx(Long idx) {
+        this.idx = idx;
+    }
+
+    public boolean isArbitrated() {
+        return isArbitrated;
+    }
+
+    public void setArbitrated(boolean arbitrated) {
+        isArbitrated = arbitrated;
+    }
+
+    public String getRedoLevel() {
+        return redoLevel;
+    }
+
+    public void setRedoLevel(String redoLevel) {
+        this.redoLevel = redoLevel;
+    }
+
+    public boolean isRejected() {
+        return isRejected;
+    }
+
+    public void setRejected(boolean rejected) {
+        isRejected = rejected;
+    }
+
+    public boolean isTagged() {
+        return isTagged;
+    }
+
+    public void setTagged(boolean tagged) {
+        isTagged = tagged;
+    }
+
+    /**
+     * 定档
+     * @param level
+     */
+    public void determineLevel(String level){
+        this.setLevel(level);
+        this.setRejected(false);
+        this.setArbitrated(false);
+        this.setRedoLevel(null);
+        this.setUpdatedOn(new Date());
+    }
+
+    /**
+     * 打回
+     * @param redoLevel
+     */
+    public void reject(String redoLevel){
+        this.setRejected(true);
+        this.setArbitrated(false);
+        this.setRedoLevel(redoLevel);
+        this.setLevel(null);
+        this.setTagged(true);
+        this.setMarkByLeader(false);
+        this.setUpdatedOn(new Date());
+    }
+
+    /**
+     * 仲裁
+     */
+    public void arbitrate(){
+        this.setRejected(false);
+        this.setArbitrated(true);
+        this.setLevel(null);
+        this.setUpdatedOn(new Date());
+    }
+
+    public boolean isMarkByLeader() {
+        return markByLeader;
+    }
+
+    public void setMarkByLeader(boolean markByLeader) {
+        this.markByLeader = markByLeader;
+    }
+
+    public String getSecretNumber() {
+        return secretNumber;
+    }
+
+    public void setSecretNumber(String secretNumber) {
+        this.secretNumber = secretNumber;
+    }
+
+    public Date getUpdatedOn() {
+        return updatedOn;
+    }
+
+    public void setUpdatedOn(Date updatedOn) {
+        this.updatedOn = updatedOn;
+    }
+
+    public String getAreaCode() {
+        return areaCode;
+    }
+
+    public void setAreaCode(String areaCode) {
+        this.areaCode = areaCode;
+    }
+
+    public boolean isMarkedLogic() {
+        return markedLogic;
+    }
+
+    public void setMarkedLogic(boolean markedLogic) {
+        this.markedLogic = markedLogic;
+    }
+
+    public int getUploadedCount() {
+        return uploadedCount;
+    }
+
+    public void setUploadedCount(int uploadedCount) {
+        this.uploadedCount = uploadedCount;
+    }
+}

+ 124 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Student.java

@@ -0,0 +1,124 @@
+package cn.com.qmth.stmms.ms.core.domain;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * 考生信息
+ * Created by zhengmin on 2016/9/21.
+ */
+@Entity
+@Table(indexes = {
+        @Index(name = "idx_student_name",columnList = "name"),
+        @Index(name = "idx_student_examnumber",columnList = "examNumber")})
+public class Student implements Serializable{
+
+
+    private static final long serialVersionUID = -8190655998628521750L;
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private String name;
+
+    private String examNumber;
+
+    private String areaCode;
+    
+    private String areaName;
+
+    private Long workId;
+    
+    private boolean isAbsent = false;
+    
+    private String examRoom;
+
+    /**
+     * 上传状态。标识科目的试卷是否上传,格式为:SC:1,SX:1,SM:0
+     */
+    private String uploadStatus = "SX:0,SC:0,SM:0";
+
+    public Student(String name, String examNumber,String areaName, String areaCode,Long workId,String examRoom) {
+        this.name = name;
+        this.examNumber = examNumber;
+        this.areaName = areaName;
+        this.areaCode = areaCode;
+        this.workId = workId;
+        this.examRoom = examRoom;
+    }
+
+    public Student() {
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getAreaCode() {
+        return areaCode;
+    }
+
+    public void setAreaCode(String areaCode) {
+        this.areaCode = areaCode;
+    }
+
+    public Long getWorkId() {
+        return workId;
+    }
+
+    public void setWorkId(Long workId) {
+        this.workId = workId;
+    }
+
+	public String getExamRoom() {
+		return examRoom;
+	}
+
+	public void setExamRoom(String examRoom) {
+		this.examRoom = examRoom;
+	}
+
+	public boolean isAbsent() {
+		return isAbsent;
+	}
+
+	public void setAbsent(boolean isAbsent) {
+		this.isAbsent = isAbsent;
+	}
+
+	public String getAreaName() {
+		return areaName;
+	}
+
+	public void setAreaName(String areaName) {
+		this.areaName = areaName;
+	}
+
+    public String getUploadStatus() {
+        return uploadStatus;
+    }
+
+    public void setUploadStatus(String uploadStatus) {
+        this.uploadStatus = uploadStatus;
+    }
+}

+ 98 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Work.java

@@ -0,0 +1,98 @@
+package cn.com.qmth.stmms.ms.core.domain;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 评卷工作
+ * Created by zhengmin on 2016/9/21.
+ */
+@Entity
+public class Work implements Serializable{
+
+
+    private static final long serialVersionUID = -5020635029000695707L;
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private String name;
+
+    /**
+     * 当前工作
+     */
+    private boolean active;
+
+    @OneToMany(cascade = CascadeType.ALL)
+    @JoinColumn(name = "workId")
+    private List<Level> levels = new ArrayList<>();
+
+    @OneToMany(cascade = CascadeType.REMOVE)
+    @JoinColumn(name = "workId")
+    private List<MarkSubject> subjects = new ArrayList<>();
+
+    @Temporal(value = TemporalType.DATE)
+    private Date createdOn;
+
+    public Work(String name) {
+        this.name = name;
+        this.createdOn = new Date();
+    }
+
+    public Work() {
+        this.createdOn = new Date();
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Date getCreatedOn() {
+        return createdOn;
+    }
+
+    public void setCreatedOn(Date createdOn) {
+        this.createdOn = createdOn;
+    }
+
+
+    public List<Level> getLevels() {
+        return levels;
+    }
+
+    public void setLevels(List<Level> levels) {
+        this.levels = levels;
+    }
+
+    public List<MarkSubject> getSubjects() {
+        return subjects;
+    }
+
+    public void setSubjects(List<MarkSubject> subjects) {
+        this.subjects = subjects;
+    }
+
+    public boolean isActive() {
+        return active;
+    }
+
+    public void setActive(boolean active) {
+        this.active = active;
+    }
+}

+ 193 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/task/MarkTask.java

@@ -0,0 +1,193 @@
+package cn.com.qmth.stmms.ms.core.domain.task;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 评卷任务
+ * Created by zhengmin on 2016/9/22.
+ */
+@Entity
+@Table(indexes = {
+        @Index(name = "idx_mark_task_paper_id",columnList = "paperId")})
+public class MarkTask implements Serializable {
+
+    private static final long serialVersionUID = -1095989485341316938L;
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @NotNull
+    private Long markerId;
+
+    @NotNull
+    private String markerName;
+
+    @Enumerated(value = EnumType.STRING)
+    private Subject subject;
+
+    @NotNull
+    private Long workId;
+
+    @NotNull
+    @ManyToOne
+    @JoinColumn(name = "paperId")
+    private Paper paper;
+
+    private Long questionId;
+
+    private String result;
+
+    private String originLevel;
+
+    private Integer levelValue;
+
+    @NotNull
+    @Enumerated(value = EnumType.ORDINAL)
+    private MarkStage stage;
+
+    /**
+     * 是否被打回重评
+     */
+    private boolean isRejected;
+
+    @Temporal(value = TemporalType.TIMESTAMP)
+    private Date createdOn;
+
+    @Temporal(value = TemporalType.TIMESTAMP)
+    private Date updatedOn;
+
+    public MarkTask(MarkUser marker, Paper paper, MarkStage stage){
+        this.markerId = marker.getId();
+        this.markerName = marker.getName();
+        this.subject = marker.getSubject();
+        this.workId = marker.getWorkId();
+        this.paper = paper;
+        this.questionId = paper.getQuestionId();
+        this.stage = stage;
+        this.createdOn = new Date();
+    }
+
+    public MarkTask() {
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getQuestionId() {
+        return questionId;
+    }
+
+    public void setQuestionId(Long questionId) {
+        this.questionId = questionId;
+    }
+
+    public MarkStage getStage() {
+        return stage;
+    }
+
+    public void setStage(MarkStage stage) {
+        this.stage = stage;
+    }
+
+    public Date getCreatedOn() {
+        return createdOn;
+    }
+
+    public void setCreatedOn(Date createdOn) {
+        this.createdOn = createdOn;
+    }
+
+    public Date getUpdatedOn() {
+        return updatedOn;
+    }
+
+    public void setUpdatedOn(Date updatedOn) {
+        this.updatedOn = updatedOn;
+    }
+
+    public boolean isRejected() {
+        return isRejected;
+    }
+
+    public void setRejected(boolean rejected) {
+        isRejected = rejected;
+    }
+
+    public Subject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(Subject subject) {
+        this.subject = subject;
+    }
+
+    public Long getWorkId() {
+        return workId;
+    }
+
+    public void setWorkId(Long workId) {
+        this.workId = workId;
+    }
+
+    public Integer getLevelValue() {
+        return levelValue;
+    }
+
+    public void setLevelValue(Integer levelValue) {
+        this.levelValue = levelValue;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        this.result = result;
+    }
+
+    public Long getMarkerId() {
+        return markerId;
+    }
+
+    public void setMarkerId(Long markerId) {
+        this.markerId = markerId;
+    }
+
+    public Paper getPaper() {
+        return paper;
+    }
+
+    public void setPaper(Paper paper) {
+        this.paper = paper;
+    }
+
+    public String getMarkerName() {
+        return markerName;
+    }
+
+    public void setMarkerName(String markerName) {
+        this.markerName = markerName;
+    }
+
+    public String getOriginLevel() {
+        return originLevel;
+    }
+
+    public void setOriginLevel(String originLevel) {
+        this.originLevel = originLevel;
+    }
+}

+ 24 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/task/TaskStatus.java

@@ -0,0 +1,24 @@
+package cn.com.qmth.stmms.ms.core.domain.task;
+
+/**
+ * 任务状态
+ * Created by zhengmin on 2016/9/22.
+ */
+public enum TaskStatus {
+    /**
+     * 初始化
+     */
+    INIT,
+    /**
+     * 仲裁
+     */
+    ARBITRATED,
+    /**
+     * 待重评
+     */
+    REDO,
+    /**
+     * 完成
+     */
+    COMPLETE
+}

+ 124 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/AbstractUser.java

@@ -0,0 +1,124 @@
+package cn.com.qmth.stmms.ms.core.domain.user;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+
+/**
+ * Created by zhengmin on 2016/8/15.
+ */
+
+@MappedSuperclass
+public abstract class AbstractUser implements Serializable {
+
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @NotNull
+    @Column(name = "login_name", unique = true)
+    private String loginName;
+
+    private String password;
+
+    private String name;
+
+    private boolean enabled;
+
+    @Temporal(value = TemporalType.TIMESTAMP)
+    private Date lastLoginTime;
+
+    @Transient
+    private String token;
+    
+    private String sessionId;
+
+    private int pwChangedCount = 0;
+
+    public AbstractUser(String loginName, String password) {
+        this.loginName = loginName;
+        this.password = password;
+        this.enabled = true;
+    }
+
+    public AbstractUser(){
+        this.enabled = true;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getLoginName() {
+        return loginName;
+    }
+
+    public void setLoginName(String loginName) {
+        this.loginName = loginName;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public Date getLastLoginTime() {
+        return lastLoginTime;
+    }
+
+    public void setLastLoginTime(Date lastLoginTime) {
+        this.lastLoginTime = lastLoginTime;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+	public String getSessionId() {
+		return sessionId;
+	}
+
+	public void setSessionId(String sessionId) {
+		this.sessionId = sessionId;
+	}
+
+    public int getPwChangedCount() {
+        return pwChangedCount;
+    }
+
+    public void setPwChangedCount(int pwChangedCount) {
+        this.pwChangedCount = pwChangedCount;
+    }
+}
+
+

+ 14 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/Admin.java

@@ -0,0 +1,14 @@
+package cn.com.qmth.stmms.ms.core.domain.user;
+
+/**
+ * 管理员用户
+ * Created by zhengmin on 2016/10/4.
+ */
+public class Admin extends AbstractUser{
+
+    private static final long serialVersionUID = -4356270039601608579L;
+
+    public Admin(String loginName,String password){
+        super(loginName,password);
+    }
+}

+ 20 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/MarkRight.java

@@ -0,0 +1,20 @@
+package cn.com.qmth.stmms.ms.core.domain.user;
+
+/**
+ * Created by zhengmin on 2016/9/21.
+ */
+public enum MarkRight {
+    ALLOW_LEVELING("只允许分档"),
+    ALLOW_SCORING("只允许打分"),
+    ALLOW_ALL("允许分档打分");
+    
+    private String name;
+
+    private MarkRight(String name){
+        this.name = name;
+    }
+
+    public String getName(){
+        return this.name;
+    }
+}

+ 94 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/MarkUser.java

@@ -0,0 +1,94 @@
+package cn.com.qmth.stmms.ms.core.domain.user;
+
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.util.Random;
+
+/**
+ * Created by zhengmin on 2016/10/4.
+ */
+@Entity
+public class MarkUser extends AbstractUser{
+
+    private static final long serialVersionUID = -8261921661291192687L;
+
+    @NotNull
+    @Enumerated(value = EnumType.STRING)
+    private Subject subject;
+
+    @NotNull
+    private Long workId;
+
+    @Enumerated(value = EnumType.STRING)
+    private Role role;
+
+    private Long groupId;
+
+    private MarkRight markRight;
+
+    public MarkUser(String loginName,
+                    String password,
+                    Long workId,
+                    Subject subject,
+                    String name,
+                    Role role){
+        super(loginName,password);
+        this.workId = workId;
+        this.subject = subject;
+        this.setName(name);
+        this.role = role;
+    }
+
+    public MarkUser() {
+        super();
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < 6; i++) {
+            Random ran = new Random();
+            int x = ran.nextInt(9);
+            sb.append(x);
+        }
+        this.setPassword("123456");
+    }
+
+    public Subject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(Subject subject) {
+        this.subject = subject;
+    }
+
+    public Long getWorkId() {
+        return workId;
+    }
+
+    public void setWorkId(Long workId) {
+        this.workId = workId;
+    }
+
+    public Role getRole() {
+        return role;
+    }
+
+    public void setRole(Role role) {
+        this.role = role;
+    }
+
+    public Long getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(Long groupId) {
+        this.groupId = groupId;
+    }
+
+    public MarkRight getMarkRight() {
+        return markRight;
+    }
+
+    public void setMarkRight(MarkRight markRight) {
+        this.markRight = markRight;
+    }
+}

+ 79 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/MarkerGroup.java

@@ -0,0 +1,79 @@
+package cn.com.qmth.stmms.ms.core.domain.user;
+
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 评卷员组
+ * Created by zhengmin on 2016/9/22.
+ */
+@Entity
+public class MarkerGroup implements Serializable{
+
+    private static final long serialVersionUID = 966105324299193932L;
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private String name;
+
+    @OneToMany
+    @JoinColumn(name = "groupId")
+    private Set<MarkUser> markers = new HashSet<>();
+
+    @NotNull
+    @Enumerated(value = EnumType.STRING)
+    private Subject subject;
+
+    @NotNull
+    private Long workId;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Set<MarkUser> getMarkers() {
+        return markers;
+    }
+
+    public void setMarkers(Set<MarkUser> markers) {
+        this.markers = markers;
+    }
+
+    public void addMarker(MarkUser marker){
+        this.markers.add(marker);
+    }
+
+    public Subject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(Subject subject) {
+        this.subject = subject;
+    }
+
+    public Long getWorkId() {
+        return workId;
+    }
+
+    public void setWorkId(Long workId) {
+        this.workId = workId;
+    }
+}

+ 18 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/Role.java

@@ -0,0 +1,18 @@
+package cn.com.qmth.stmms.ms.core.domain.user;
+
+/**
+ * Created by zhengmin on 2016/10/9.
+ */
+public enum Role {
+    MARKER("评卷员"),MARK_LEADER("科组长"),ADMIN("管理员");
+
+    private String name;
+
+    private Role(String name){
+        this.name = name;
+    }
+
+    public String getName(){
+        return this.name;
+    }
+}

+ 25 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/ExamQuestionRepo.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import cn.com.qmth.stmms.ms.core.domain.ExamQuestion;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2016/10/9.
+ */
+public interface ExamQuestionRepo extends JpaRepository<ExamQuestion,Long>{
+
+    List<ExamQuestion> findByWorkIdAndSubject(Long workId, Subject subject);
+
+	long countByWorkId(Long workId);
+
+	long countByWorkIdAndAreaCode(Long workId,String areaCode);
+
+	ExamQuestion findByWorkIdAndSubjectAndAreaCode(Long workId,
+			Subject subject, String areaCode);
+
+	void deleteByWorkId(Long workId);
+}

+ 16 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/LevelRepo.java

@@ -0,0 +1,16 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import cn.com.qmth.stmms.ms.core.domain.Level;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2016/9/24.
+ */
+public interface LevelRepo extends JpaRepository<Level,Long>{
+
+    List<Level> findByWorkId(Long workId);
+
+    Level findByWorkIdAndCode(Long workId,String code);
+}

+ 12 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkLogRepo.java

@@ -0,0 +1,12 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkLog;
+
+/**
+ * @author ting.yin
+ * @date 2016年10月21日
+ */
+public interface MarkLogRepo extends JpaRepository<MarkLog,Long>{
+}

+ 11 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkSubjectRepo.java

@@ -0,0 +1,11 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkSubject;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * Created by zhengmin on 2016/9/24.
+ */
+public interface MarkSubjectRepo extends JpaRepository<MarkSubject,String> {
+
+}

+ 90 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkTaskRepo.java

@@ -0,0 +1,90 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.task.MarkTask;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2016/9/23.
+ */
+public interface MarkTaskRepo extends JpaRepository<MarkTask,Long>,JpaSpecificationExecutor{
+
+    /**
+     * 查询指定阶段试卷的评卷任务
+     * @param paperId 试卷id
+     * @param stage 评卷阶段
+     * @return
+     */
+    List<MarkTask> findByPaperIdAndStage(Long paperId, MarkStage stage);
+
+    /**
+     * 评卷员任务数量
+     * @param markerId
+     * @return
+     */
+    long countByMarkerId(Long markerId);
+
+    long countByMarkerIdAndQuestionId(Long markerId,Long questionId);
+
+    /**
+     * 查询评卷员的评卷任务
+     * @param markerId
+     * @param stage
+     * @return
+     */
+    @Query(value = "select mt from MarkTask mt left outer join fetch mt.paper where mt.markerId = ? and mt.stage = ?")
+    List<MarkTask> findByMarkerIdAndStage(Long markerId,MarkStage stage);
+
+    /**
+     * 查询评卷员的评卷任务
+     * @param markerId
+     * @param stage
+     * @param questionId
+     * @return
+     */
+    @Query(value = "select mt from MarkTask mt left outer join fetch mt.paper where mt.markerId = ? and mt.stage = ? and mt.questionId = ? order by mt.updatedOn desc")
+    List<MarkTask> findByMarkerIdAndStageAndQuestionId(Long markerId,MarkStage stage,Long questionId);
+
+    /**
+     * 删除评卷员所有任务
+     * @param subject
+     * @param stage
+     * @return
+     */
+    Long deleteByWorkIdAndSubjectAndStage(Long workId,Subject subject,MarkStage stage);
+
+    /**
+     * 统计评卷员各试题已评数及总数(分档阶段)
+     * @param markerId
+     * @return
+     */
+    @Query(value = "SELECT q.`id`,q.`name`,SUM(IF(t.`result` IS NULL,1,0)),COUNT(t.question_id) " +
+            "FROM mark_task t LEFT OUTER JOIN exam_question q ON t.`question_id` = q.`id` WHERE " +
+            "t.`marker_id` = ? and t.stage = ? GROUP BY t.`question_id` ORDER BY q.`id`",nativeQuery = true)
+    List<Object[]> countGroupByQuestion(Long markerId,Integer stageId);
+
+    /**
+     * 统计评卷员指定试题的各档位数量
+     * @param questionId
+     * @param markerId
+     * @return
+     */
+    @Query(value = "SELECT t.result,COUNT(*) FROM mark_task t " +
+            "WHERE t.`question_id` = ? AND t.`marker_id` = ? and t.stage = 1 " +
+            "GROUP BY t.`result` ORDER BY t.result",nativeQuery = true)
+    List<Object[]> countGroupByLevel(Long questionId,Long markerId);
+
+    /**
+     * 统计指定试卷的所有任务数量
+     * @param id
+     * @return
+     */
+	Long countByPaperId(Long id);
+
+}

+ 25 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkUserRepo.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.domain.user.Role;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2016/10/6.
+ */
+public interface MarkUserRepo extends JpaRepository<MarkUser,Long>{
+
+    List<MarkUser> findByWorkIdAndSubjectAndRole(Long workId, Subject subject, Role role);
+
+	List<MarkUser> findByWorkIdAndRole(Long workId, Role role);
+
+	MarkUser findByLoginName(String loginName);
+
+	List<MarkUser> findByWorkId(Long workId);
+
+	long countByWorkIdAndRole(Long workId,Role role);
+}

+ 15 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkerGroupRepo.java

@@ -0,0 +1,15 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import cn.com.qmth.stmms.ms.core.domain.user.MarkerGroup;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+/**
+ * Created by zhengmin on 2016/10/6.
+ */
+public interface MarkerGroupRepo extends JpaRepository<MarkerGroup,Long>{
+
+    List<MarkerGroup> findByWorkIdAndSubject(Long workId, Subject subject);
+}

+ 114 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/PaperRepo.java

@@ -0,0 +1,114 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+/**
+ * Created by zhengmin on 2016/9/23.
+ */
+public interface PaperRepo extends JpaRepository<Paper,Long>,JpaSpecificationExecutor<Paper>{
+
+    List<Paper> findByWorkIdAndSubject(Long workId, Subject subject);
+    List<Paper> findByWorkIdAndSubject(Long workId, Subject subject,Sort sort);
+
+    List<Paper> findByQuestionId(Long questionId, Sort sort);
+
+    Page<Paper> findByQuestionId(Long questionId, Pageable pageable);
+
+    /**
+     * 统计各省各科试卷数量[areaCode,areaName,questionName,count]
+     * @param workId
+     * @return
+     */
+    @Query(value = "SELECT q.`area_code`,q.`area_name`,p.`question_name`,COUNT(*) FROM paper p LEFT OUTER JOIN exam_question q ON p.`question_id` = q.`id` WHERE p.`work_id` = ? GROUP BY p.`question_id`,p.`question_name` ORDER BY p.`question_id` ",nativeQuery = true)
+    List<Object[]> countGroupByQuestion(Long workId);
+    
+    /**
+     * 统计科目各试题已评数及总数(分档阶段)
+     * @param workId
+     * @param subject
+     * @return
+     */
+    @Query(value = "SELECT p.`question_id`,p.question_name,SUM(IF(p.level IS NULL,1,0)),COUNT(p.`question_id`) " +
+            "FROM paper p WHERE p.`work_id` = ? AND p.`subject` = ?" +
+            "GROUP BY p.`question_id` ,p.question_name ORDER BY p.`question_id`",nativeQuery = true)
+    List<Object[]> countGroupByQuestionForLevel(Long workId,String subject);
+
+    /**
+     * 统计科目指定试题的各档位数量
+     * @param questionId
+     * @return
+     */
+    @Query(value = "SELECT p.`level`,COUNT(*)," +
+            "SUM(IF(p.`is_rejected` = 1, 1, 0))," +
+            "SUM(IF(p.`is_arbitrated` = 1, 1, 0))" +
+            "FROM paper p " +
+            "WHERE p.`question_id` = ? " +
+            "GROUP BY p.`level` ORDER BY p.`level`",nativeQuery = true)
+    List<Object[]> countGroupByLevel(Long questionId);
+    
+    /**
+     * 统计科目各试题已评数及总数(打分阶段)
+     * @param workId
+     * @return
+     */
+    @Query(value = "SELECT p.`question_id`,p.question_name,SUM(IF(p.score IS NULL,1,0)),COUNT(p.`question_id`) " +
+            "FROM paper p WHERE p.`work_id` = ? AND p.`subject` = ?" +
+            "GROUP BY p.`question_id` ,p.question_name ORDER BY p.`question_id`",nativeQuery = true)
+	List<Object[]> countGroupByQuestionForScore(Long workId, String string);
+	
+    /**
+     * 统计科目未分档的试卷数
+     * @param workId
+     * @param subject
+     * @return
+     */
+    Long countByWorkIdAndSubjectAndLevelIsNull(Long workId,Subject subject);
+
+    long countByWorkIdAndScoreIsNull(Long workId);
+
+    Long countByWorkId(Long workId);
+
+    long countByWorkIdAndQuestionId(Long workId,Long questionId);
+
+    /**
+     * 统计同一个考生的paper数量
+     * @param workId
+     * @param examNumber
+     * @return
+     */
+    Long countByWorkIdAndExamNumber(Long workId,String examNumber);
+
+    /**
+     * 查询指定试卷
+     * @param workId
+     * @param subject
+     * @param examNumber
+     * @return
+     */
+    Paper findByWorkIdAndSubjectAndExamNumber(Long workId,Subject subject,String examNumber);
+    
+    /**
+     * 查询同一个考生的paper
+     * @param workId
+     * @param examNumber
+     * @return
+     */
+	List<Paper> findByWorkIdAndExamNumber(Long workId,String examNumber);
+
+    @Query(value = "select p from Paper p where p.score >= ?1 or p.score <= ?2")
+    List<Paper> findByScoreRange(Double highScore,Double lowScore);
+
+    @Query(value = "SELECT p.`exam_number`,p.`student_name`,p.question_id,GROUP_CONCAT(score  ORDER BY p.`subject`) FROM paper p WHERE p.`work_id` = ? GROUP BY p.exam_number,p.`student_name`",nativeQuery = true)
+    List<Object[]> findScores(Long workId);
+}

+ 22 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/StudentRepo.java

@@ -0,0 +1,22 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+import cn.com.qmth.stmms.ms.core.domain.Student;
+
+import java.util.List;
+
+/**
+ * @author ting.yin
+ * @date 2016年10月27日
+ */
+public interface StudentRepo extends JpaRepository<Student, Long>,JpaSpecificationExecutor<Student> {
+
+	Student findByWorkIdAndExamNumber(Long workId, String examNumber);
+
+	void deleteByWorkId(Long workId);
+
+	List<Student> findByWorkId(Long workId);
+
+}

+ 12 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/WorkRepo.java

@@ -0,0 +1,12 @@
+package cn.com.qmth.stmms.ms.core.repository;
+
+import cn.com.qmth.stmms.ms.core.domain.Work;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * Created by zhengmin on 2016/10/9.
+ */
+public interface WorkRepo extends JpaRepository<Work,Long>{
+
+    Work findByActiveTrue();
+}

+ 95 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/specification/StudentSpecification.java

@@ -0,0 +1,95 @@
+package cn.com.qmth.stmms.ms.core.specification;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.criteria.Predicate;
+
+import org.springframework.data.jpa.domain.Specification;
+
+import cn.com.qmth.stmms.ms.commons.utils.specification.PagingAndSortingSpecification;
+import cn.com.qmth.stmms.ms.core.domain.Student;
+
+public class StudentSpecification extends PagingAndSortingSpecification {
+
+    private String workId;
+    private String areaCode;
+    private String examNumber;
+    private String name;
+    private String uploadStatus;
+    private Boolean isAbsent;
+
+    public String getWorkId() {
+		return workId;
+	}
+
+	public void setWorkId(String workId) {
+		this.workId = workId;
+	}
+
+    public String getAreaCode() {
+		return areaCode;
+	}
+
+	public void setAreaCode(String areaCode) {
+		this.areaCode = areaCode;
+	}
+
+	public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getExamNumber() {
+		return examNumber;
+	}
+
+	public void setExamNumber(String examNumber) {
+		this.examNumber = examNumber;
+	}
+
+	public Boolean getIsAbsent() {
+		return isAbsent;
+	}
+
+	public void setIsAbsent(Boolean isAbsent) {
+		this.isAbsent = isAbsent;
+	}
+
+	public String getUploadStatus() {
+		return uploadStatus;
+	}
+
+	public void setUploadStatus(String uploadStatus) {
+		this.uploadStatus = uploadStatus;
+	}
+
+	@Override
+    public Specification<Student> getSpecification(){
+        return (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<Predicate>();
+            if(getName() != null){
+                predicates.add(cb.like(root.get("name"), "%"+getName()+"%"));
+            }
+            if(getExamNumber() != null){
+                predicates.add(cb.like(root.get("examNumber"),"%"+getExamNumber()+"%"));
+            }
+            if(getWorkId() != null){
+                predicates.add(cb.equal(root.get("workId"),getWorkId()));
+            }
+            if(getAreaCode() != null){
+                predicates.add(cb.equal(root.get("areaCode"),getAreaCode()));
+            }
+            if(getIsAbsent()!= null){
+                predicates.add(cb.equal(root.get("isAbsent"),getIsAbsent()));
+            }
+            if(getUploadStatus() != null){
+                predicates.add(cb.like(root.get("uploadStatus"),"%"+getUploadStatus()+"%"));
+            }
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+    }
+}

+ 21 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/vo/Subject.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.stmms.ms.core.vo;
+
+/**
+ * Created by zhengmin on 2016/9/22.
+ */
+public enum Subject {
+
+    SX("速写"),
+    SC("色彩"),
+    SM("素描");
+
+    private String name;
+
+    private Subject(String name){
+        this.name = name;
+    }
+
+    public String getName(){
+        return this.name;
+    }
+}

+ 32 - 0
stmms-ms-log/pom.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>stmms-ms-parent</artifactId>
+        <groupId>cn.com.qmth</groupId>
+        <version>${project.version}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>stmms-ms-log</artifactId>
+
+    <dependencies>
+		<dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-marking</artifactId>
+        </dependency>
+                <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-accesscontrol</artifactId>
+        </dependency>
+        <dependency>  
+    		<groupId>org.springframework.boot</groupId>
+    		<artifactId>spring-boot-starter-aop</artifactId>
+		</dependency>
+    </dependencies>
+</project>

+ 125 - 0
stmms-ms-log/src/main/java/cn/com/qmth/stmms/ms/log/MarkLogAop.java

@@ -0,0 +1,125 @@
+package cn.com.qmth.stmms.ms.log;
+
+import java.util.HashMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import cn.com.qmth.stmms.ms.accesscontrol.config.LoginConfig;
+import cn.com.qmth.stmms.ms.core.domain.user.AbstractUser;
+import cn.com.qmth.stmms.ms.core.domain.user.Admin;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkLog;
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.domain.task.MarkTask;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.repository.MarkLogRepo;
+import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+
+/**
+ * 
+ * @Description: 操作记录
+ * @author ting.yin
+ * @date 2016年10月24日
+ */
+@Aspect
+@Component
+public class MarkLogAop {
+
+	private static Logger logger = LoggerFactory.getLogger(MarkLogAop.class);
+
+	@Autowired
+	private MarkLogRepo markLogRepo;
+
+	@Autowired
+	private MarkUserRepo markUserRepo;
+
+	@Autowired
+	private PaperRepo paperRepo;
+	
+    @Autowired
+    private LoginConfig loginConfig;
+
+	@Pointcut("execution(* cn.com.qmth.stmms.ms.marking.api.MarkTaskApi.marking(..))")
+	public void getTask() {
+	}
+
+	@AfterReturning(pointcut = "getTask()")
+	public void afterMarkPoint(JoinPoint joinPoint) {
+		MarkTask markTask = (MarkTask) joinPoint.getArgs()[0];
+		MarkUser markUser = markUserRepo.findOne(markTask.getMarkerId());
+//		MarkLog markLog = new MarkLog(markTask.getWorkId(),
+//									markTask.getStage(),
+//									markUser.getLoginName(),
+//									markUser.getName(),
+//									markTask.getPaper().getExamNumber(),
+//									markTask.getPaper().getSecretNumber(),
+//									markTask.getResult());
+//		markLogRepo.save(markLog);
+		String info = markUser.getLoginName() + ":" + markUser.getName() + ":" + markTask.getSubject() +
+				":" + markTask.getPaper().getId() + ":" + markTask.getResult();
+		logger.info(info);
+	}
+
+	/**
+
+	@Pointcut("execution(* cn.com.qmth.stmms.ms.marking.api.PaperApi.marking(..))")
+	public void getPaper() {
+	}
+
+	@AfterReturning(pointcut = "getPaper()")
+	@SuppressWarnings("unchecked")
+	public void afterLevelMarkPaperPoint(JoinPoint joinPoint) {
+		Paper paper = (Paper) joinPoint.getArgs()[0];
+		HashMap<String,String> body =  (HashMap<String, String>) joinPoint.getArgs()[1];
+		String level = body.get("level");
+		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
+				.getRequestAttributes()).getRequest();
+		HttpSession session = request.getSession();
+		String token = (String) session.getAttribute("token");
+		if (!StringUtils.isEmpty(token)) {
+			String loginName = token.substring(14);
+			AbstractUser user = null;
+			if(loginConfig.getLoginName().equals(loginName)){
+				user = new Admin(loginConfig.getLoginName(),loginConfig.getPassword());
+				user.setName("系统管理员");
+			}
+			else{
+				user = markUserRepo.findByLoginName(loginName);
+			}
+			MarkLog markLog = new MarkLog(paper.getWorkId(),
+					MarkStage.LEVEL,
+					user.getLoginName(),
+					user.getName(),
+					paper.getExamNumber(), 
+					paper.getSecretNumber(), 
+					level);
+			markLogRepo.save(markLog);
+		}else{
+			MarkLog markLog = new MarkLog(paper.getWorkId(), 
+					MarkStage.LEVEL,
+					null, 
+					"科组长", 
+					paper.getExamNumber(), 
+					paper.getSecretNumber(), 
+					level);
+			markLogRepo.save(markLog);
+		}
+	}
+	**/
+
+}

+ 46 - 0
stmms-ms-log/src/main/resources/logback-spring.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <include resource="org/springframework/boot/logging/logback/base.xml"/>
+
+    <!-- 日志文件存储路径 -->
+    <property name="LOG_HOME" value="./logs" />
+
+
+
+
+    <!-- 控制台输出 -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <!-- 日志输出编码 -->
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+            </pattern>
+        </layout>
+    </appender>
+
+    <appender name="FILE_MARK"  class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!--日志文件输出的文件名-->
+            <FileNamePattern>${LOG_HOME}/marking.log.%d{yyyy-MM-dd}.log</FileNamePattern>
+            <MaxHistory>30</MaxHistory>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
+            <pattern>%d{yyyy-MM-dd HH:mm:ss} - %msg%n
+            </pattern>
+        </layout>
+        <!--日志文件最大的大小-->
+        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <MaxFileSize>10MB</MaxFileSize>
+        </triggeringPolicy>
+    </appender>
+
+
+    <logger name="org.springframework" level="ERROR" />
+
+    <logger name="org.hibernate" level="ERROR" />
+
+    <logger name="cn.com.qmth.stmms.ms.log.MarkLogAop" level="INFO" >
+        <appender-ref ref="FILE_MARK" />
+    </logger>
+</configuration>

+ 55 - 0
stmms-ms-main/pom.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>stmms-ms-parent</artifactId>
+        <groupId>cn.com.qmth</groupId>
+        <version>${project.version}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>stmms-ms-main</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-admin</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-marking</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-accesscontrol</artifactId>
+        </dependency>
+		<dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-log</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-collect</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 18 - 0
stmms-ms-main/src/main/java/cn/com/qmth/stmms/ms/Application.java

@@ -0,0 +1,18 @@
+package cn.com.qmth.stmms.ms;
+
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@SpringBootApplication
+@EnableTransactionManagement
+@EnableAsync
+public class Application{
+
+    public static void main(String[] args) throws Exception {
+        SpringApplication.run(Application.class, args);
+    }
+
+}

+ 52 - 0
stmms-ms-main/src/main/resources/application.properties

@@ -0,0 +1,52 @@
+spring.profiles.active=prod
+
+spring.datasource.url=jdbc:mysql://localhost:3306/stmms-ms-2?useUnicode=true&characterEncoding=UTF-8
+spring.datasource.username=root
+spring.datasource.password=1234
+
+#spring.datasource.url=jdbc:mysql://192.168.1.74:3306/stmms-ms-2?useUnicode=true&characterEncoding=UTF-8
+#spring.datasource.username=root
+#spring.datasource.password=root
+
+
+spring.datasource.validation-query=SELECT 1 FROM DUAL
+spring.datasource.test-on-borrow=true
+
+#redis
+#spring.redis.host=192.168.199.102
+#spring.redis.port=32768
+
+server.port=9000
+server.compression.enabled=true
+server.compression.mime-types: application/json,application/xml,text/html,text/xml,text/plain,text/css,application/javascript
+
+
+logging.file=./logs/sys.log
+logging.level.org.springframework=ERROR
+logging.level.org.hibernate=ERROR
+
+spring.jpa.show-sql=false
+spring.jpa.hibernate.ddl-auto=update
+
+
+spring.http.multipart.max-file-size=10Mb
+
+app.config.deviation=2
+app.admin.loginName=admin-cy
+app.admin.password=123456
+
+sys.config.imageDir=/Users/yuanpan/tmp/stmms-ms/static/images
+sys.config.thumbDir=/Users/yuanpan/tmp/stmms-ms/static/thumbs
+#sys.config.imageDir=.\\static\\images
+#sys.config.thumbDir=.\\static\\thumbs
+sys.config.compression.percent=60
+#sys.config.imageServer.port=3000
+sys.config.imageServer.port=9000
+#sys.config.imageServer.ip=localhost
+
+
+#袁攀配置
+web.upload-path=/Users/yuanpan/tmp/stmms-ms/static/
+spring.mvc.static-path-pattern=/**
+spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,\
+  classpath:/static/,classpath:/public/,file:${web.upload-path}

+ 29 - 0
stmms-ms-marking/pom.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>stmms-ms-parent</artifactId>
+        <groupId>cn.com.qmth</groupId>
+        <version>${project.version}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>stmms-ms-marking</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth</groupId>
+            <artifactId>stmms-ms-commons</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 35 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/ExamQuestionApi.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.stmms.ms.marking.api;
+
+import cn.com.qmth.stmms.ms.core.domain.ExamQuestion;
+import cn.com.qmth.stmms.ms.core.repository.ExamQuestionRepo;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 试题api
+ * Created by zhengmin on 2016/11/8.
+ */
+@RestController
+@RequestMapping("api/questions")
+public class ExamQuestionApi {
+
+    @Autowired
+    private ExamQuestionRepo examQuestionRepo;
+
+    /**
+     * 试题列表
+     * @param workId 评卷工作id
+     * @param subject 科目
+     * @return
+     */
+    @RequestMapping(method = RequestMethod.GET)
+    public List<ExamQuestion> list(@RequestParam Long workId, @RequestParam Subject subject){
+        return examQuestionRepo.findByWorkIdAndSubject(workId,subject);
+    }
+}

+ 146 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/MakrerApi.java

@@ -0,0 +1,146 @@
+package cn.com.qmth.stmms.ms.marking.api;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import cn.com.qmth.stmms.ms.marking.assembler.LevelStatAssembler;
+import cn.com.qmth.stmms.ms.marking.assembler.MarkerAssembler;
+import cn.com.qmth.stmms.ms.marking.assembler.QuestionStatAssembler;
+import cn.com.qmth.stmms.ms.marking.dto.LevelStatDTO;
+import cn.com.qmth.stmms.ms.marking.dto.MarkerDTO;
+import cn.com.qmth.stmms.ms.marking.dto.QuestionStatDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import cn.com.qmth.stmms.ms.core.domain.Level;
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.MarkSubject;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkRight;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.domain.user.Role;
+import cn.com.qmth.stmms.ms.core.repository.LevelRepo;
+import cn.com.qmth.stmms.ms.core.repository.MarkSubjectRepo;
+import cn.com.qmth.stmms.ms.core.repository.MarkTaskRepo;
+import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+
+/**
+ * 评卷中,评卷员的相关数据api
+ * Created by zhengmin on 2016/10/14.
+ */
+@RestController
+@RequestMapping("api/markers")
+public class MakrerApi {
+
+    @Autowired
+    private MarkUserRepo markUserRepo;
+    
+    @Autowired
+    private MarkTaskRepo markTaskRepo;
+
+	@Autowired
+	private MarkerAssembler markerAssembler;
+
+    @Autowired
+    private QuestionStatAssembler questionStatAssembler;
+    
+    @Autowired
+    private MarkSubjectRepo markSubjectRepo;
+    
+    @Autowired
+    private LevelRepo levelRepo;
+
+    @Autowired
+    private LevelStatAssembler levelStatAssembler;
+
+    /**
+     * 评卷员信息
+     * @param markerId 评卷员用户id
+     * @return
+     */
+	@RequestMapping(value = "{markerId}",method = RequestMethod.GET)
+	public MarkerDTO getMarker(@PathVariable Long markerId){
+		MarkUser marker = markUserRepo.findOne(markerId);
+		return markerAssembler.toDTO(marker);
+	}
+
+    /**
+     * 评卷员列表
+     * @param workId 评卷工作id
+     * @param subject 科目
+     * @param markStage 允许参与的阶段
+     * @return
+     */
+    @RequestMapping(method = RequestMethod.GET)
+    public List<MarkUser> list(@RequestParam Long workId,
+                               @RequestParam Subject subject,
+                               @RequestParam MarkStage markStage){
+    	List<MarkUser>  markUsers = markUserRepo.findByWorkIdAndSubjectAndRole(workId,subject, Role.MARKER);
+    	if(MarkStage.LEVEL == markStage ){
+    		markUsers = markUsers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_LEVELING||m.getMarkRight() == MarkRight.ALLOW_ALL).collect(Collectors.toList());
+    	}else if(MarkStage.SCORE == markStage){
+    		markUsers = markUsers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_SCORING||m.getMarkRight() == MarkRight.ALLOW_ALL).collect(Collectors.toList());
+    	}
+        return markUsers;
+    }
+
+    /**
+     * 评卷员分档数量及占比数据
+     * @param marker 评卷员用户id
+     * @param questionId 试题id
+     * @return
+     */
+    @RequestMapping(value = "{marker}/stat/levels",method = RequestMethod.GET)
+    public List<LevelStatDTO> levelStats(@PathVariable MarkUser marker, @RequestParam Long questionId){
+    	List<LevelStatDTO> levelStatDTOs = new ArrayList<>();
+        markTaskRepo.countGroupByLevel(questionId,marker.getId())
+                .forEach(o -> {
+                    levelStatDTOs.add(levelStatAssembler.toDTO(o));
+                });
+        MarkSubject markSubject = markSubjectRepo.findOne(marker.getWorkId() + "-" + marker.getSubject().toString());
+        List<Level> levels = levelRepo.findByWorkId(markSubject.getWorkId());
+        for(Level level : levels){
+            long count = levelStatDTOs.stream().filter(l -> String.valueOf(l.getId()).equals(level.getCode())).count();
+            if(count == 0){
+                LevelStatDTO dto = new LevelStatDTO();
+                dto.setId(level.getCode());
+                dto.setCount(0);
+                dto.setPercent(0.0);
+                levelStatDTOs.add(dto);
+            }
+        }
+        long total = markTaskRepo.countByMarkerIdAndQuestionId(marker.getId(),questionId);
+        levelStatDTOs.forEach(o -> {
+            if(o.getId()!=null){
+                double p = (double)o.getCount()/total;
+                BigDecimal bd = new BigDecimal(p).setScale(3, RoundingMode.HALF_EVEN);
+            	o.setPercent(bd.doubleValue());
+            }
+        });
+        return levelStatDTOs;
+    }
+
+    /**
+     * 各试题统计数据
+     * @param marker 评卷员用户id
+     * @return
+     */
+    @RequestMapping(value = "{marker}/stat/questions",method = RequestMethod.GET)
+    public List<QuestionStatDTO> questions(@PathVariable MarkUser marker){
+        List<QuestionStatDTO> questionStatDTOs = new ArrayList<>();
+        List<Object[]> qStats = null;
+        MarkSubject markSubject = markSubjectRepo.findOne(marker.getWorkId() + "-" + marker.getSubject().toString());
+        qStats = markTaskRepo.countGroupByQuestion(marker.getId(),markSubject.getStage().ordinal());
+        if(qStats != null) {
+            for (Object[] objects : qStats) {
+                QuestionStatDTO dto = questionStatAssembler.toDTO(objects);
+                questionStatDTOs.add(dto);
+            }
+        }
+        return questionStatDTOs;
+    }
+	
+}

+ 219 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/MarkSubjectApi.java

@@ -0,0 +1,219 @@
+package cn.com.qmth.stmms.ms.marking.api;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import cn.com.qmth.stmms.ms.marking.assembler.LevelStatAssembler;
+import cn.com.qmth.stmms.ms.marking.assembler.QuestionStatAssembler;
+import cn.com.qmth.stmms.ms.marking.dto.LevelStatDTO;
+import cn.com.qmth.stmms.ms.marking.dto.QuestionStatDTO;
+import cn.com.qmth.stmms.ms.marking.service.StageControlService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import cn.com.qmth.stmms.ms.core.domain.Level;
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.MarkSubject;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkRight;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkerGroup;
+import cn.com.qmth.stmms.ms.core.domain.user.Role;
+import cn.com.qmth.stmms.ms.core.repository.*;
+
+/**
+ * 评卷科目数据api
+ * Created by zhengmin on 2016/10/10.
+ */
+@RestController
+@RequestMapping("api/marksubjects")
+public class MarkSubjectApi {
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @Autowired
+    private MarkSubjectRepo markSubjectRepo;
+
+    @Autowired
+    private QuestionStatAssembler questionStatAssembler;
+
+    @Autowired
+    private LevelRepo levelRepo;
+
+    @Autowired
+    private LevelStatAssembler levelStatAssembler;
+    
+	@Autowired
+	private MarkerGroupRepo markerGroupRepo;
+	
+	@Autowired
+	private MarkUserRepo markUserRepo;
+	
+	@Autowired
+	private StageControlService stageControlService;
+
+    /**
+     * 当个评卷科目信息
+     * @param markSubjectId 评卷科目id
+     * @return
+     */
+    @RequestMapping(value = "{markSubjectId}",method = RequestMethod.GET)
+    public MarkSubject get(@PathVariable String markSubjectId){
+        return markSubjectRepo.findOne(markSubjectId);
+    }
+
+    /**
+     * 该评卷科目下的评卷员列表
+     * @param markSubject 评卷科目id
+     * @return
+     */
+    @RequestMapping(value = "{markSubject}/markers",method = RequestMethod.GET)
+    public List<MarkUser> markUsers(@PathVariable MarkSubject markSubject){
+        List<MarkUser>  markUsers = markUserRepo.findByWorkIdAndSubjectAndRole(markSubject.getWorkId(),markSubject.getSubject(), Role.MARKER);
+        if(MarkStage.LEVEL == markSubject.getStage() ){
+            markUsers = markUsers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_LEVELING||m.getMarkRight() == MarkRight.ALLOW_ALL).collect(Collectors.toList());
+        }else if(MarkStage.SCORE == markSubject.getStage()){
+            markUsers = markUsers.stream().filter(m -> m.getMarkRight() == MarkRight.ALLOW_SCORING||m.getMarkRight() == MarkRight.ALLOW_ALL).collect(Collectors.toList());
+        }
+        return markUsers;
+    }
+
+    /**
+     * 该评卷科目的试题统计信息
+     * @param markSubject 评卷科目id
+     * @return
+     */
+    @RequestMapping(value = "{markSubject}/stat/questions",method = RequestMethod.GET)
+    public List<QuestionStatDTO> questions(@PathVariable MarkSubject markSubject){
+        List<QuestionStatDTO> questionStatDTOs = new ArrayList<>();
+        List<Object[]> qStats = null;
+        if(markSubject.getStage() == MarkStage.LEVEL){
+        	qStats = paperRepo.countGroupByQuestionForLevel(markSubject.getWorkId(),markSubject.getSubject().toString());
+        }else{
+        	qStats = paperRepo.countGroupByQuestionForScore(markSubject.getWorkId(),markSubject.getSubject().toString());
+        }
+        for(Object[] objects : qStats){
+            QuestionStatDTO dto = questionStatAssembler.toDTO(objects);
+            questionStatDTOs.add(dto);
+        }
+        return questionStatDTOs;
+    }
+
+    /**
+     * 该评卷科目的分档统计信息
+     * @param markSubject 评卷科目id
+     * @param questionId 试题id
+     * @return
+     */
+    @RequestMapping(value = "{markSubject}/stat/levels",method = RequestMethod.GET)
+    public List<LevelStatDTO> levelStat(@PathVariable MarkSubject markSubject, @RequestParam Long questionId){
+        List<LevelStatDTO> levelStatDTOs = new ArrayList<>();
+        paperRepo.countGroupByLevel(questionId)
+                .forEach(o -> {
+                    levelStatDTOs.add(levelStatAssembler.toDTO(o));
+                });
+        List<Level> levels = levelRepo.findByWorkId(markSubject.getWorkId());
+        for(Level level : levels){
+            long count = levelStatDTOs.stream().filter(l -> String.valueOf(l.getId()).equals(level.getCode())).count();
+            if(count == 0){
+                LevelStatDTO dto = new LevelStatDTO();
+                dto.setId(level.getCode());
+                dto.setCount(0);
+                dto.setPercent(0.0);
+                levelStatDTOs.add(dto);
+            }
+        }
+        long total = paperRepo.countByWorkIdAndQuestionId(markSubject.getWorkId(),questionId);
+        levelStatDTOs.forEach(o -> {
+            if(o.getId()!=null){
+                double p = (double)o.getCount()/total;
+                BigDecimal bd = new BigDecimal(p).setScale(3, RoundingMode.HALF_EVEN);
+                o.setPercent(bd.doubleValue());
+            }
+        });
+        return levelStatDTOs;
+    }
+
+    /**
+     * 该评卷科目下的评卷员分组列表
+     * @param markSubject 评卷科目id
+     * @return
+     */
+	@RequestMapping(value = "{markSubject}/markergroups",method = RequestMethod.GET)
+	public List<MarkerGroup> getMarkerGroups(@PathVariable MarkSubject markSubject) {
+		return markerGroupRepo.findByWorkIdAndSubject(markSubject.getWorkId(), markSubject.getSubject());
+	}
+
+    /**
+     * 创建评卷组
+     * @param markSubject 评卷科目id
+     * @param markerGroup 评卷组
+     */
+	@RequestMapping(value = "{markSubject}/markergroups",method = RequestMethod.POST)
+	public void createMarkerGroup(@PathVariable MarkSubject markSubject,@RequestBody MarkerGroup markerGroup) {
+		markerGroup.setWorkId(markSubject.getWorkId());
+		markerGroup.setSubject(markSubject.getSubject());
+		markerGroupRepo.save(markerGroup);
+	}
+
+    /**
+     * 修改评卷组名
+     * @param markSubject 评卷科目id
+     * @param domain 评卷组id
+     * @param markerGroup 评卷组
+     */
+	@RequestMapping(value = "{markSubject}/markergroups/{domain}", method = RequestMethod.PATCH)
+	public void updateMarkerGroup(@PathVariable MarkSubject markSubject,@PathVariable MarkerGroup domain,@RequestBody MarkerGroup markerGroup) {
+		domain.setName(markerGroup.getName());
+		markerGroupRepo.save(markerGroup);
+	}
+
+    /**
+     * 删除评卷组
+     * @param markSubject 评卷科目id
+     * @param domain 评卷组id
+     */
+	@RequestMapping(value = "{markSubject}/markergroups/{domain}", method = RequestMethod.DELETE)
+	public void removeMarkerGroup(@PathVariable MarkSubject markSubject,@PathVariable MarkerGroup domain) {
+		markerGroupRepo.delete(domain);
+	}
+
+    /**
+     * 单个评卷组信息
+     * @param markSubject 评卷科目id
+     * @param domain 评卷组id
+     * @return
+     */
+	@RequestMapping(value = "{markSubject}/markergroups/{domain}", method = RequestMethod.GET)
+	public MarkerGroup getMarkerGroup(@PathVariable MarkSubject markSubject,@PathVariable MarkerGroup domain) {
+		return domain;
+	}
+
+    /**
+     * 为评卷组设置评卷员
+     * @param markSubject 评卷科目id
+     * @param domain 评卷组id
+     * @param markerIds 评卷员用户id数组
+     */
+	@RequestMapping(value = "{markSubject}/markergroups/{domain}/setmaker", method = RequestMethod.PATCH)
+	public void setMaker(@PathVariable MarkSubject markSubject,@PathVariable MarkerGroup domain,@RequestParam Long... markerIds) {
+		domain.setMarkers(new HashSet<MarkUser>());
+		for (Long markerId : markerIds) {
+			domain.addMarker(markUserRepo.findOne(markerId));
+		}
+		markerGroupRepo.save(domain);
+	}
+
+    /**
+     * 该评卷科目进入下一阶段
+     * @param markSubject 评卷科目id
+     */
+	@RequestMapping(value = "{markSubject}", method = RequestMethod.PATCH)
+	public void goNext(@PathVariable MarkSubject markSubject) {
+		stageControlService.goNext(markSubject);
+	}
+}

+ 119 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/MarkTaskApi.java

@@ -0,0 +1,119 @@
+package cn.com.qmth.stmms.ms.marking.api;
+
+import java.util.*;
+import java.util.stream.Stream;
+
+import cn.com.qmth.stmms.ms.commons.web.PageableDTO;
+import cn.com.qmth.stmms.ms.marking.assembler.MarkTaskAssembler;
+import cn.com.qmth.stmms.ms.marking.dto.MarkTaskDTO;
+import cn.com.qmth.stmms.ms.marking.service.MarkingService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.task.MarkTask;
+import cn.com.qmth.stmms.ms.core.repository.LevelRepo;
+import cn.com.qmth.stmms.ms.core.repository.MarkTaskRepo;
+import org.springframework.web.bind.annotation.*;
+
+import javax.persistence.criteria.Predicate;
+
+/**
+ * 评卷任务数据api
+ * Created by zhengmin on 2016/10/12.
+ */
+@RestController
+@RequestMapping("api/marktasks")
+public class MarkTaskApi {
+
+    @Autowired
+    private MarkTaskRepo markTaskRepo;
+    
+    @Autowired
+    private MarkingService markingService;
+    
+    @Autowired
+    private LevelRepo levelRepo;
+
+    @Autowired
+    private MarkTaskAssembler markTaskAssembler;
+
+    /**
+     * 评卷员的评卷任务
+     * @param markerId 评卷员用户id
+     * @param stage 评卷阶段
+     * @param level 档位
+     * @param sn 密号
+     * @param questionId 试题id
+     * @return
+     */
+    @RequestMapping(method = RequestMethod.GET)
+    public PageableDTO list(@RequestParam Long markerId,
+                            @RequestParam MarkStage stage,
+                            @RequestParam(required = false) Boolean isSample,
+                            @RequestParam(required = false) String level,
+                            @RequestParam(required = false) String sn,
+                            @RequestParam Long questionId,
+                            Pageable pageable){
+        List<MarkTaskDTO> markTaskDTOs = new ArrayList<>();
+
+        Specification<MarkTask> specification = (root, query, builder) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(builder.equal(root.get("questionId"),questionId));
+            predicates.add(builder.equal(root.get("markerId"),markerId));
+            predicates.add(builder.equal(root.get("stage"),stage));
+            if(level == null){
+                predicates.add(builder.isNull(root.get("result")));
+            }
+            else if(stage == MarkStage.LEVEL){
+                predicates.add(builder.equal(root.get("result"),level));
+            }
+            else if(stage == MarkStage.SCORE){
+                predicates.add(builder.isNotNull(root.get("result")));
+            }
+            if(isSample != null){
+                predicates.add(builder.equal(root.get("paper").get("markByLeader"),isSample));
+            }
+            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        Page<MarkTask> markTasks = markTaskRepo.findAll(specification,pageable);
+        markTasks.getContent().forEach(m -> {
+            markTaskDTOs.add(markTaskAssembler.toDTO(m));
+        });
+        if(stage == MarkStage.SCORE && level == null){
+            Collections.sort(markTaskDTOs, (MarkTaskDTO a,MarkTaskDTO b) -> a.getLevel().compareTo(b.getLevel()));
+        }
+        return new PageableDTO(markTaskDTOs,markTasks.getTotalElements(),markTasks.getTotalPages(),pageable.getPageNumber());
+    }
+
+    /**
+     * 提交评卷任务
+     * @param markTask 评卷你任务id
+     * @param body 评卷内容
+     * @return
+     */
+    @RequestMapping(value = "{markTask}",method = RequestMethod.PATCH)
+    public ResponseEntity marking(@PathVariable MarkTask markTask, @RequestBody HashMap<String,String> body){
+        MarkStage stage = MarkStage.valueOf(body.get("stage"));
+        String result = body.get("result");
+        if(stage == null || result == null){
+            return new ResponseEntity(HttpStatus.BAD_REQUEST);
+        }
+        switch (stage){
+            case LEVEL:
+                markingService.levelMark(markTask,result);
+                break;
+            case SCORE:
+                Integer score = Integer.parseInt(result);
+                markingService.scoring(markTask,score);
+                break;
+        }
+        return new ResponseEntity(markTaskAssembler.toDTO(markTask),HttpStatus.OK);
+    }
+
+}

+ 230 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/PaperApi.java

@@ -0,0 +1,230 @@
+package cn.com.qmth.stmms.ms.marking.api;
+
+import java.util.*;
+
+import cn.com.qmth.stmms.ms.commons.web.PageableDTO;
+import cn.com.qmth.stmms.ms.core.vo.Subject;
+import cn.com.qmth.stmms.ms.marking.assembler.MarkTaskAssembler;
+import cn.com.qmth.stmms.ms.marking.assembler.PaperAssembler;
+import cn.com.qmth.stmms.ms.marking.dto.MarkTaskDTO;
+import cn.com.qmth.stmms.ms.marking.dto.PaperDTO;
+import cn.com.qmth.stmms.ms.marking.service.MarkingService;
+import org.assertj.core.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.*;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.repository.MarkTaskRepo;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+import org.springframework.web.bind.annotation.*;
+
+import javax.persistence.criteria.Predicate;
+
+/**
+ * 试卷相关api
+ * Created by zhengmin on 2016/10/10.
+ */
+@RestController
+@RequestMapping("api/papers")
+public class PaperApi {
+
+    @Autowired
+    private PaperAssembler paperAssembler;
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @Autowired
+    private MarkTaskRepo markTaskRepo;
+
+    @Autowired
+    private MarkTaskAssembler markTaskAssembler;
+
+    @Autowired
+    private MarkingService markingService;
+
+    /**
+     * 单个试卷信息
+     * @param paperId 试卷id
+     * @return
+     */
+    @RequestMapping(value = "{paperId}",method = RequestMethod.GET)
+    public PaperDTO get(@PathVariable Long paperId){
+        return paperAssembler.toDTO(paperRepo.findOne(paperId));
+    }
+
+    /**
+     * 单个试卷信息
+     * @param questionId 试题id
+     * @param sn 密号
+     * @param examNumber 准考证号
+     * @return
+     */
+    @RequestMapping(value = "/one",method = RequestMethod.GET)
+    public PaperDTO getOne(@RequestParam Long questionId,
+                           @RequestParam(required = false) String sn,
+                           @RequestParam(required = false) String examNumber){
+        PaperDTO paperDTO = null;
+        Specification<Paper> specification = (root,query,builder) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(builder.equal(root.get("questionId"),questionId));
+            if(sn != null){
+                predicates.add(builder.equal(root.get("secretNumber"),sn));
+            }
+            if(examNumber != null){
+                predicates.add(builder.equal(root.get("examNumber"),examNumber));
+            }
+
+            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+        Optional<Paper> paperOptional = paperRepo.findAll(specification,new PageRequest(0,1))
+                .getContent().stream().findFirst();
+        if(paperOptional.isPresent()){
+            paperDTO = paperAssembler.toDTO(paperOptional.get());
+        }
+        return paperDTO;
+    }
+
+    @RequestMapping(value="listByQuestion",method = RequestMethod.GET)
+    public PageableDTO listByQuerion(@RequestParam String areaCode,
+                                     @RequestParam Subject subject,
+                                     @RequestParam(required = false) Long startNumber,
+                                     @RequestParam(required = false) Long endNumber,
+                                     @RequestParam(required = false) Boolean isManual,
+                                     Pageable pageable){
+        Specification<Paper> specification = (root,query,builder) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(builder.equal(root.get("areaCode"),areaCode));
+            predicates.add(builder.equal(root.get("subject"),subject));
+            if(startNumber != null && endNumber != null){
+                predicates.add(builder.between(root.get("examNumber"),startNumber,endNumber));
+            }
+            else if(startNumber != null){
+                predicates.add(builder.equal(root.get("examNumber"),startNumber));
+            }
+            if(isManual != null){
+                predicates.add(builder.equal(root.get("isManual"),isManual));
+            }
+
+            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+        List<PaperDTO> paperDTOs = new ArrayList<>();
+        Page<Paper> paperPage = paperRepo.findAll(specification,pageable);
+        paperPage.getContent().forEach(p -> {
+            paperDTOs.add(paperAssembler.toDTO(p));
+        });
+        return new PageableDTO(paperDTOs,paperPage.getTotalElements(),paperPage.getTotalPages(),pageable.getPageNumber());
+    }
+
+    /**
+     * 试卷列表
+     * @param questionId 试题id
+     * @param level 档位,如果为空,则测序待评
+     * @param arbi 是否仲裁
+     * @param reject 是否打回
+     * @param pageable 分页参数
+     * @return
+     */
+    @RequestMapping(method = RequestMethod.GET)
+    public PageableDTO list(@RequestParam Long questionId,
+                               @RequestParam(required = false) String level,
+                               @RequestParam(required = false) Boolean isSample,
+                               @RequestParam(required = false) Boolean markedLogic,
+                               @RequestParam(required = false) Boolean arbi,
+                               @RequestParam(required = false) Boolean reject,
+                               Pageable pageable) {
+        Specification<Paper> specification = (root,query,builder) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(builder.equal(root.get("questionId"),questionId));
+            if(Objects.isNull(level)){
+                predicates.add(builder.isNull(root.get("level")));
+            }
+            else{
+                predicates.add(builder.equal(root.get("level"),level));
+            }
+            if(arbi != null){
+                predicates.add(builder.equal(root.get("isArbitrated"),arbi));
+            }
+            if(reject != null){
+                predicates.add(builder.equal(root.get("isRejected"),reject));
+            }
+            if(isSample != null){
+                predicates.add(builder.equal(root.get("markByLeader"),isSample));
+            }
+            if(markedLogic != null){
+                predicates.add(builder.equal(root.get("markedLogic"),markedLogic));
+            }
+            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
+
+        };
+
+        Page<Paper> papers = paperRepo.findAll(specification,pageable);
+        List<PaperDTO> paperDTOs = new ArrayList<>();
+        papers.forEach(p -> {
+            paperDTOs.add(paperAssembler.toDTO(p));
+        });
+        return new PageableDTO(paperDTOs,papers.getTotalElements(),papers.getTotalPages(),pageable.getPageNumber());
+    }
+
+    /**
+     * 试卷处理。提交评卷
+     * @param paper 试卷id
+     * @param body 试卷信息
+     * @return
+     */
+    @RequestMapping(value = "{paper}", method = RequestMethod.PATCH)
+    @Transactional
+    public ResponseEntity marking(@PathVariable Paper paper, @RequestBody HashMap<String, String> body) {
+        String action = body.get("action");
+        String level = body.get("level");
+        String tagged = body.get("tagged");
+        if (action != null && level != null) {
+            if (action.equals("leveling")) {
+                markingService.levelMarkPaper(paper, level);
+            } else if (action.equals("reject")) {
+                markingService.reject(paper, level);
+            }
+        }
+        if (tagged != null) {
+            boolean isTagged = paper.isTagged();
+            paper.setTagged(!isTagged);
+            paperRepo.save(paper);
+        }
+        return new ResponseEntity(paperAssembler.toDTO(paper), HttpStatus.OK);
+    }
+
+    /**
+     * 标记试卷
+     * @param paper 试卷id
+     * @return
+     */
+    @RequestMapping(value = "{paper}/tag", method = RequestMethod.PATCH)
+    @Transactional
+    public Paper tagging(@PathVariable Paper paper) {
+        boolean isTagged = paper.isTagged();
+        paper.setTagged(!isTagged);
+        paperRepo.save(paper);
+        return paper;
+    }
+
+    /**
+     * 该试卷的评卷记录
+     * @param paperId 试卷id
+     * @param stage 评卷阶段
+     * @return
+     */
+    @RequestMapping(value = "{paperId}/marktasks", method = RequestMethod.GET)
+    public List<MarkTaskDTO> markTasks(@PathVariable Long paperId, @RequestParam MarkStage stage) {
+        List<MarkTaskDTO> markTaskDTOs = new ArrayList<>();
+        markTaskRepo.findByPaperIdAndStage(paperId, stage).forEach(o -> {
+            markTaskDTOs.add(markTaskAssembler.toDTO(o));
+        });
+        return markTaskDTOs;
+    }
+
+}

+ 34 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/LevelStatAssembler.java

@@ -0,0 +1,34 @@
+package cn.com.qmth.stmms.ms.marking.assembler;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import cn.com.qmth.stmms.ms.marking.dto.LevelStatDTO;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * Created by zhengmin on 2016/10/14.
+ */
+@Component
+public class LevelStatAssembler {
+
+    public LevelStatDTO toDTO(Object[] levelStats){
+        LevelStatDTO levelStatDTO = null;
+        if(levelStats != null){
+            levelStatDTO = new LevelStatDTO();
+            levelStatDTO.setId(levelStats[0]);
+            BigInteger count =(BigInteger) levelStats[1];
+            levelStatDTO.setCount(count.intValue());
+            if(levelStats.length>2){
+            	BigDecimal rejected =(BigDecimal) levelStats[2];
+            	levelStatDTO.setRejected(rejected.intValue());
+            }
+            if(levelStats.length>3){
+            	BigDecimal arbitrated =(BigDecimal) levelStats[3];
+            	levelStatDTO.setArbitrated(arbitrated.intValue());
+            }
+        }
+        return levelStatDTO;
+    }
+}

+ 48 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/MarkTaskAssembler.java

@@ -0,0 +1,48 @@
+package cn.com.qmth.stmms.ms.marking.assembler;
+
+import cn.com.qmth.stmms.ms.commons.config.SystemConfig;
+import cn.com.qmth.stmms.ms.marking.dto.MarkTaskDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.domain.task.MarkTask;
+
+/**
+ * Created by zhengmin on 2016/10/12.
+ */
+@Component
+public class MarkTaskAssembler {
+
+    @Autowired
+    private SystemConfig systemConfig;
+
+    public MarkTaskDTO toDTO(MarkTask markTask){
+        MarkTaskDTO markTaskDTO = null;
+        if(markTask != null){
+            markTaskDTO = new MarkTaskDTO();
+            markTaskDTO.setId(markTask.getId());
+            markTaskDTO.setRejected(markTask.isRejected());
+            markTaskDTO.setMarker(markTask.getMarkerName());
+            markTaskDTO.setUpdatedOn(markTask.getUpdatedOn());
+            markTaskDTO.setResult(markTask.getResult());
+            Paper paper = markTask.getPaper();
+            if(markTask.getStage() == MarkStage.LEVEL){
+                markTaskDTO.setLevel(markTask.getResult());
+                markTaskDTO.setOriginLevel(markTask.getOriginLevel());
+            }
+            else {
+                markTaskDTO.setLevel(paper.getLevel());
+            }
+            markTaskDTO.setSn(paper.getSecretNumber());
+            markTaskDTO.setRedoLevel(paper.getRedoLevel());
+            String imgSrc = systemConfig.getImageUrl(markTask.getWorkId(),paper.getSubject().toString(),paper.getAreaCode(),paper.getExamNumber());
+            String thumbSrc = systemConfig.getThumbUrl(markTask.getWorkId(),paper.getSubject().toString(),paper.getAreaCode(),paper.getExamNumber());
+            markTaskDTO.setThumbSrc(thumbSrc);
+            markTaskDTO.setImgSrc(imgSrc);
+            markTaskDTO.setSample(paper.isMarkByLeader());
+        }
+        return markTaskDTO;
+    }
+}

+ 37 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/MarkerAssembler.java

@@ -0,0 +1,37 @@
+package cn.com.qmth.stmms.ms.marking.assembler;
+
+import cn.com.qmth.stmms.ms.marking.dto.MarkerDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkSubject;
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.repository.MarkSubjectRepo;
+
+/**
+ * Created by zhengmin on 2016/10/20.
+ */
+@Component
+public class MarkerAssembler {
+
+    @Autowired
+    private MarkSubjectRepo markSubjectRepo;
+
+    public MarkerDTO toDTO(MarkUser marker){
+        MarkerDTO markerDTO = null;
+        if(marker != null){
+            markerDTO = new MarkerDTO();
+            markerDTO.setId(marker.getId());
+            markerDTO.setName(marker.getName());
+            markerDTO.setMarkRight(marker.getMarkRight());
+            markerDTO.setSubject(marker.getSubject());
+            markerDTO.setWorkId(marker.getWorkId());
+            String markSubjectId = marker.getWorkId() + "-" +marker.getSubject().toString();
+            MarkSubject markSubject = markSubjectRepo.findOne(markSubjectId);
+            markerDTO.setMarkSubjectId(markSubjectId);
+            markerDTO.setMarkStage(markSubject.getStage());
+            markerDTO.setGroupId(String.valueOf(marker.getGroupId()));
+        }
+        return markerDTO;
+    }
+}

+ 54 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/PaperAssembler.java

@@ -0,0 +1,54 @@
+package cn.com.qmth.stmms.ms.marking.assembler;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.ms.commons.config.SystemConfig;
+import cn.com.qmth.stmms.ms.marking.dto.PaperDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.stmms.ms.core.domain.MarkStage;
+import cn.com.qmth.stmms.ms.core.domain.Paper;
+import cn.com.qmth.stmms.ms.core.domain.task.MarkTask;
+import cn.com.qmth.stmms.ms.core.repository.MarkTaskRepo;
+
+/**
+ * Created by zhengmin on 2016/10/10.
+ */
+@Component
+public class PaperAssembler {
+
+    @Autowired
+    private MarkTaskRepo markTaskRepo;
+
+    @Autowired
+    private MarkTaskAssembler markTaskAssembler;
+
+    @Autowired
+    private SystemConfig systemConfig;
+
+    public PaperDTO toDTO(Paper paper){
+        PaperDTO paperDTO = null;
+        if(paper != null){
+            paperDTO = new PaperDTO();
+            paperDTO.setId(paper.getId());
+            paperDTO.setExamNumber(paper.getExamNumber());
+            paperDTO.setSn(paper.getSecretNumber());
+            paperDTO.setLevel(paper.getLevel());
+            paperDTO.setManual(paper.isManual());
+            paperDTO.setScore(paper.getScore());
+            paperDTO.setArbitrated(paper.isArbitrated());
+            paperDTO.setRejected(paper.isRejected());
+            paperDTO.setSample(paper.isMarkByLeader());
+            paperDTO.setTagged(paper.isTagged());
+            paperDTO.setMarkedLogic(paper.isMarkedLogic());
+            paperDTO.setRedoLevel(paper.getRedoLevel());
+            paperDTO.setUpdatedOn(paper.getUpdatedOn());
+            String imgSrc = systemConfig.getImageUrl(paper.getWorkId(),paper.getSubject().toString(),paper.getAreaCode(),paper.getExamNumber());
+            String thumbSrc = systemConfig.getThumbUrl(paper.getWorkId(),paper.getSubject().toString(),paper.getAreaCode(),paper.getExamNumber());
+            paperDTO.setImgSrc(imgSrc);
+            paperDTO.setThumbSrc(thumbSrc);
+        }
+        return paperDTO;
+    }
+}

+ 45 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/QuestionStatAssembler.java

@@ -0,0 +1,45 @@
+package cn.com.qmth.stmms.ms.marking.assembler;
+
+import cn.com.qmth.stmms.ms.marking.dto.QuestionStatDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.stmms.ms.core.repository.LevelRepo;
+import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
+
+/**
+ * Created by zhengmin on 2016/10/14.
+ */
+@Component
+public class QuestionStatAssembler {
+
+    @Autowired
+    private LevelRepo levelRepo;
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    public QuestionStatDTO toDTO(Object[] qStats){
+        return this.assemble(qStats);
+    }
+
+    public QuestionStatDTO toDTOWithMarkers(Object[] qStats){
+        QuestionStatDTO qpDTO = this.assemble(qStats);
+        if(qpDTO != null){
+
+        }
+        return qpDTO;
+    }
+
+    private QuestionStatDTO assemble(Object[] qStats){
+        QuestionStatDTO qpDTO = null;
+        if(qStats != null){
+            qpDTO = new QuestionStatDTO();
+            qpDTO.setId(qStats[0]);
+            qpDTO.setName(qStats[1]);
+            qpDTO.setLeftCount(qStats[2]);
+            qpDTO.setTotalCount(qStats[3]);
+        }
+        return qpDTO;
+    }
+}

Some files were not shown because too many files changed in this diff