罗识 7 năm trước cách đây
commit
426a266706
100 tập tin đã thay đổi với 10671 bổ sung0 xóa
  1. 340 0
      pom.xml
  2. 67 0
      stmms-biz/pom.xml
  3. 30 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/annotation/AuthValidate.java
  4. 10 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/interfaces/AuthValidator.java
  5. 9 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/model/AuthInfo.java
  6. 36 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/model/BasicAuthInfo.java
  7. 40 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/AuthInfoService.java
  8. 35 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/validator/AdminUserValidator.java
  9. 41 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/validator/AuthValidateService.java
  10. 45 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/validator/DefaultValidator.java
  11. 35 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/validator/ScannerValidator.java
  12. 16 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/dao/CampusDao.java
  13. 137 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/model/Campus.java
  14. 58 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/query/CampusSearchQuery.java
  15. 27 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/service/CampusService.java
  16. 117 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/service/impl/CampusServiceImp.java
  17. 296 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/BaseQuery.java
  18. 28 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/common/BaseQueryService.java
  19. 29 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamDao.java
  20. 43 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamPackageDao.java
  21. 48 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamQuestionDao.java
  22. 120 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamStudentDao.java
  23. 82 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamSubjectDao.java
  24. 97 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkGroupDao.java
  25. 44 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkerDao.java
  26. 12 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ScoreRateDao.java
  27. 15 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/TagDao.java
  28. 128 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Exam.java
  29. 73 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamPackage.java
  30. 75 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamPackagePK.java
  31. 206 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamQuestion.java
  32. 605 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamStudent.java
  33. 211 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamSubject.java
  34. 75 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamSubjectPK.java
  35. 231 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroup.java
  36. 85 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroupPK.java
  37. 255 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Marker.java
  38. 119 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/QuestionPK.java
  39. 144 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ScoreRate.java
  40. 136 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ScoreRatePK.java
  41. 38 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Tag.java
  42. 37 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/ExamPackageSearchQuery.java
  43. 82 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/ExamSearchQuery.java
  44. 287 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/ExamStudentSearchQuery.java
  45. 59 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/MarkerSearchQuery.java
  46. 32 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamPackageService.java
  47. 40 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamQuestionService.java
  48. 28 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamService.java
  49. 90 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamStudentService.java
  50. 56 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamSubjectService.java
  51. 44 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/MarkGroupService.java
  52. 42 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/MarkerService.java
  53. 14 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ScoreRateService.java
  54. 19 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/TagService.java
  55. 124 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamPackageServiceImpl.java
  56. 165 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamQuestionServiceImpl.java
  57. 139 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamServiceImpl.java
  58. 574 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamStudentServiceImpl.java
  59. 240 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ExamSubjectServiceImpl.java
  60. 169 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/MarkGroupServiceImpl.java
  61. 233 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/MarkerServiceImpl.java
  62. 84 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/ScoreRateServiceImpl.java
  63. 31 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/impl/TagServiceImpl.java
  64. 75 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/query/ExamQuestionSearchQuery.java
  65. 102 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/query/ExamSubjectSearchQuery.java
  66. 56 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/query/ScoreRateSearchQuery.java
  67. 87 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkLibraryDao.java
  68. 39 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/dao/MarkTrackDao.java
  69. 29 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkCount.java
  70. 238 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkLibrary.java
  71. 173 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkStepDTO.java
  72. 135 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkTrack.java
  73. 85 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkTrackPK.java
  74. 317 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/Task.java
  75. 92 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/TrackDTO.java
  76. 120 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/query/MarkLibrarySearchQuery.java
  77. 254 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkLibraryServiceImpl.java
  78. 65 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkTrackServiceImpl.java
  79. 292 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/TaskServiceImpl.java
  80. 56 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkLibraryService.java
  81. 25 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkTrackService.java
  82. 29 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/TaskService.java
  83. 10 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/dao/SchoolDao.java
  84. 160 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/model/School.java
  85. 37 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/query/SchoolSearchQuery.java
  86. 18 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/service/SchoolService.java
  87. 80 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/service/impl/SchoolServiceImpl.java
  88. 23 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/dao/UserDao.java
  89. 186 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/model/User.java
  90. 34 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/service/UserService.java
  91. 162 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/service/impl/UserServiceImpl.java
  92. 77 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/service/query/UserSearchQuery.java
  93. 52 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/AbstractTask.java
  94. 34 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/BlockTaskCountUtil.java
  95. 156 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/CurrentTaskUtil.java
  96. 197 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/CurrentTaskUtil2.java
  97. 53 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/MarkRedisUtil.java
  98. 85 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/PageModel.java
  99. 130 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/ScoreCalculateUtil.java
  100. 81 0
      stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/ScoreInfo.java

+ 340 - 0
pom.xml

@@ -0,0 +1,340 @@
+<?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.stmms</groupId>
+	<artifactId>stmms-parent</artifactId>
+	<packaging>pom</packaging>
+	<version>1.0-SNAPSHOT</version>
+
+	<name>stmms-parent</name>
+	<url>http://maven.apache.org</url>
+
+	<modules>
+		<module>stmms-common</module>
+		<module>stmms-biz</module>
+		<module>stmms-web</module>
+	</modules>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<spring.version>3.2.14.RELEASE</spring.version>
+		<hibernate.version>4.2.1.Final</hibernate.version>
+		<log4j.version>1.2.17</log4j.version>
+		<aspectj.version>1.6.5</aspectj.version>
+		<junit.version>4.11</junit.version>
+		<java.version>1.7</java.version>
+		<spring-data-redis.version>1.2.1.RELEASE</spring-data-redis.version>
+		<poi.version>3.9</poi.version>
+		<guava.version>14.0.1</guava.version>
+		<commons-lang3.version>3.1</commons-lang3.version>
+	</properties>
+
+	<dependencyManagement>
+		<dependencies>
+			<!-- ======================================== -->
+			<!-- 子项目依赖 -->
+			<!-- ======================================== -->
+			<dependency>
+				<groupId>cn.com.qmth.stmms</groupId>
+				<artifactId>stmms-common</artifactId>
+				<version>${project.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>cn.com.qmth.stmms</groupId>
+				<artifactId>stmms-orm</artifactId>
+				<version>${project.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>cn.com.qmth.stmms</groupId>
+				<artifactId>stmms-biz</artifactId>
+				<version>${project.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>cn.com.qmth.stmms</groupId>
+				<artifactId>stmms-web</artifactId>
+				<version>${project.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>cn.com.qmth.stmms</groupId>
+				<artifactId>remote-interface</artifactId>
+				<version>${project.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>cn.com.qmth.stmms</groupId>
+				<artifactId>remote-service</artifactId>
+				<version>${project.version}</version>
+			</dependency>
+			<!-- ================================================= -->
+			<!-- 日志及相关依赖(用slf4j+logback代替jcl+log4j) -->
+			<!-- ================================================= -->
+			<dependency>
+				<groupId>org.slf4j</groupId>
+				<artifactId>slf4j-api</artifactId>
+				<version>1.6.1</version>
+			</dependency>
+			<dependency>
+				<groupId>org.slf4j</groupId>
+				<artifactId>jcl-over-slf4j</artifactId>
+				<version>1.6.1</version>
+			</dependency>
+			<dependency>
+				<groupId>ch.qos.logback</groupId>
+				<artifactId>logback-classic</artifactId>
+				<version>0.9.29</version>
+				<scope>runtime</scope>
+			</dependency>
+			<dependency>
+				<groupId>com.caucho</groupId>
+				<artifactId>hessian</artifactId>
+				<version>4.0.7</version>
+			</dependency>
+			<dependency>
+				<groupId>commons-logging</groupId>
+				<artifactId>commons-logging</artifactId>
+				<version>1.1.1</version>
+				<scope>provided</scope>
+			</dependency>
+			<!-- ================================================= -->
+			<!-- Spring框架 -->
+			<!-- ================================================= -->
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-core</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-beans</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-aop</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-aspects</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-context</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-context-support</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-tx</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-jdbc</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-orm</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-web</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-webmvc</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-test</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-instrument</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework.data</groupId>
+				<artifactId>spring-data-jpa</artifactId>
+				<version>1.6.6.RELEASE</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework.data</groupId>
+				<artifactId>spring-data-redis</artifactId>
+				<version>${spring-data-redis.version}</version>
+			</dependency>
+			<!-- ======================================== -->
+			<!-- 其它第三方依赖 -->
+			<!-- ======================================== -->
+			<dependency>
+				<groupId>javax.servlet</groupId>
+				<artifactId>javax.servlet-api</artifactId>
+				<version>3.0.1</version>
+				<scope>provided</scope>
+			</dependency>
+			<dependency>
+				<groupId>org.mortbay.jetty</groupId>
+				<artifactId>jetty</artifactId>
+				<version>6.1.26</version>
+			</dependency>
+			<dependency>
+				<groupId>jstl</groupId>
+				<artifactId>jstl</artifactId>
+				<version>1.2</version>
+			</dependency>
+			<dependency>
+				<groupId>junit</groupId>
+				<artifactId>junit</artifactId>
+				<version>${junit.version}</version>
+				<scope>test</scope>
+			</dependency>
+			<dependency>
+				<groupId>commons-fileupload</groupId>
+				<artifactId>commons-fileupload</artifactId>
+				<version>1.2.2</version>
+			</dependency>
+			<dependency>
+				<groupId>commons-io</groupId>
+				<artifactId>commons-io</artifactId>
+				<version>2.1</version>
+			</dependency>
+			<dependency>
+				<groupId>commons-net</groupId>
+				<artifactId>commons-net</artifactId>
+				<version>2.0</version>
+			</dependency>
+			<dependency>
+				<groupId>commons-collections</groupId>
+				<artifactId>commons-collections</artifactId>
+				<version>20040616</version>
+			</dependency>
+			<dependency>
+				<groupId>org.hibernate</groupId>
+				<artifactId>hibernate-entitymanager</artifactId>
+				<version>${hibernate.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.hibernate</groupId>
+				<artifactId>hibernate-ehcache</artifactId>
+				<version>${hibernate.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.hibernate.javax.persistence</groupId>
+				<artifactId>hibernate-jpa-2.0-api</artifactId>
+				<version>1.0.1.Final</version>
+			</dependency>
+			<dependency>
+				<groupId>org.eclipse.persistence</groupId>
+				<artifactId>javax.persistence</artifactId>
+				<version>2.1.0</version>
+			</dependency>
+			<dependency>
+				<groupId>org.slf4j</groupId>
+				<artifactId>slf4j-api</artifactId>
+				<version>1.7.5</version>
+			</dependency>
+			<dependency>
+				<groupId>commons-dbcp</groupId>
+				<artifactId>commons-dbcp</artifactId>
+				<version>1.4</version>
+			</dependency>
+			<dependency>
+				<groupId>commons-pool</groupId>
+				<artifactId>commons-pool</artifactId>
+				<version>20030825.183949</version>
+			</dependency>
+			<dependency>
+				<groupId>mysql</groupId>
+				<artifactId>mysql-connector-java</artifactId>
+				<version>5.1.21</version>
+			</dependency>
+			<dependency>
+				<groupId>org.codehaus.jackson</groupId>
+				<artifactId>jackson-mapper-asl</artifactId>
+				<version>1.9.12</version>
+			</dependency>
+			<dependency>
+				<groupId>org.codehaus.jackson</groupId>
+				<artifactId>jackson-core-asl</artifactId>
+				<version>1.9.12</version>
+			</dependency>
+			<dependency>
+				<groupId>com.fasterxml.jackson.core</groupId>
+				<artifactId>jackson-databind</artifactId>
+				<version>2.8.8</version>
+			</dependency>
+			<dependency>
+				<groupId>log4j</groupId>
+				<artifactId>log4j</artifactId>
+				<version>${log4j.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>net.sourceforge.jexcelapi</groupId>
+				<artifactId>jxl</artifactId>
+				<version>2.6.12</version>
+			</dependency>
+			<dependency>
+				<groupId>net.sf.json-lib</groupId>
+				<artifactId>json-lib-ext-spring</artifactId>
+				<version>1.0.2</version>
+			</dependency>
+			<dependency>
+				<groupId>redis.clients</groupId>
+				<artifactId>jedis</artifactId>
+				<version>2.4.1</version>
+			</dependency>
+			<dependency>
+				<groupId>org.aspectj</groupId>
+				<artifactId>aspectjweaver</artifactId>
+				<version>1.8.0</version>
+			</dependency>
+			<dependency>
+				<groupId>com.google.guava</groupId>
+				<artifactId>guava</artifactId>
+				<version>18.0</version>
+			</dependency>
+			<dependency>
+				<groupId>junit</groupId>
+				<artifactId>junit</artifactId>
+				<version>4.12</version>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.3.2</version>
+				<configuration>
+					<source>${java.version}</source>
+					<target>${java.version}</target>
+					<encoding>UTF-8</encoding>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<version>2.14.1</version>
+				<configuration>
+					<skipTests>true</skipTests>
+					<additionalClasspathElements>
+						<additionalClasspathElement>src/main/resources</additionalClasspathElement>
+					</additionalClasspathElements>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>

+ 67 - 0
stmms-biz/pom.xml

@@ -0,0 +1,67 @@
+<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>
+	<parent>
+		<groupId>cn.com.qmth.stmms</groupId>
+		<artifactId>stmms-parent</artifactId>
+		<version>1.0-SNAPSHOT</version>
+	</parent>
+	<groupId>cn.com.qmth.stmms</groupId>
+	<artifactId>stmms-biz</artifactId>
+	<version>1.0-SNAPSHOT</version>
+	<packaging>jar</packaging>
+	<name>stmms-biz</name>
+	<url>http://maven.apache.org</url>
+
+	<dependencies>
+		<dependency>
+			<groupId>cn.com.qmth.stmms</groupId>
+			<artifactId>stmms-common</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.data</groupId>
+			<artifactId>spring-data-jpa</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-entitymanager</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-ehcache</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.persistence</groupId>
+			<artifactId>javax.persistence</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.hibernate.javax.persistence</groupId>
+			<artifactId>hibernate-jpa-2.0-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>commons-dbcp</groupId>
+			<artifactId>commons-dbcp</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>commons-pool</groupId>
+			<artifactId>commons-pool</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.json-lib</groupId>
+			<artifactId>json-lib-ext-spring</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+</project>

+ 30 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/annotation/AuthValidate.java

@@ -0,0 +1,30 @@
+package cn.com.qmth.stmms.biz.api.auth.annotation;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * API方法权限验证器定义
+ * 
+ * @author LS
+ * 
+ */
+@Target({ METHOD })
+@Retention(RUNTIME)
+public @interface AuthValidate {
+
+    /**
+     * 指定权限验证器的名称
+     * 
+     * @return
+     */
+    String[] value() default {};
+
+    /**
+     * true-与 false-或
+     */
+    boolean nand() default false;
+}

+ 10 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/interfaces/AuthValidator.java

@@ -0,0 +1,10 @@
+package cn.com.qmth.stmms.biz.api.auth.interfaces;
+
+import cn.com.qmth.stmms.biz.api.auth.model.AuthInfo;
+
+public interface AuthValidator {
+
+    public String getName();
+
+    public boolean validate(AuthInfo auth);
+}

+ 9 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/model/AuthInfo.java

@@ -0,0 +1,9 @@
+package cn.com.qmth.stmms.biz.api.auth.model;
+
+import cn.com.qmth.stmms.biz.user.model.User;
+
+public interface AuthInfo {
+
+    public User getLoginUser();
+
+}

+ 36 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/model/BasicAuthInfo.java

@@ -0,0 +1,36 @@
+package cn.com.qmth.stmms.biz.api.auth.model;
+
+import cn.com.qmth.stmms.biz.user.model.User;
+
+public class BasicAuthInfo implements AuthInfo {
+
+    private User loginUser;
+
+    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;
+    }
+
+    public User getLoginUser() {
+        return loginUser;
+    }
+
+    public void setLoginUser(User loginUser) {
+        this.loginUser = loginUser;
+    }
+}

+ 40 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/AuthInfoService.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.stmms.biz.api.auth.service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.stmms.biz.api.auth.model.AuthInfo;
+import cn.com.qmth.stmms.biz.api.auth.model.BasicAuthInfo;
+
+@Service("authInfoService")
+public class AuthInfoService {
+
+    private static final String ENTRY_SPLITE = ";";
+
+    private static final String KV_SPLITE = "=";
+
+    public AuthInfo getAuthInfo(String infoString) {
+        Map<String, String> infoMap = buildInfoMap(infoString);
+        BasicAuthInfo info = new BasicAuthInfo();
+        info.setLoginName(infoMap.get("loginname"));
+        info.setPassword(infoMap.get("password"));
+        return info;
+    }
+
+    private Map<String, String> buildInfoMap(String infoString) {
+        Map<String, String> infoMap = new HashMap<String, String>();
+        String[] values = StringUtils.split(infoString, ENTRY_SPLITE);
+        if (values != null && values.length > 0) {
+            for (String value : values) {
+                String[] pair = StringUtils.split(value, KV_SPLITE);
+                if (pair != null && pair.length == 2) {
+                    infoMap.put(pair[0].trim(), pair[1].trim());
+                }
+            }
+        }
+        return infoMap;
+    }
+}

+ 35 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/validator/AdminUserValidator.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.stmms.biz.api.auth.service.validator;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.stmms.biz.api.auth.interfaces.AuthValidator;
+import cn.com.qmth.stmms.biz.api.auth.model.AuthInfo;
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.common.enums.Role;
+
+@Component
+public class AdminUserValidator implements AuthValidator {
+
+    @Autowired
+    private AuthValidateService validateService;
+
+    @PostConstruct
+    protected void init() {
+        validateService.addValidator(this);
+    }
+
+    @Override
+    public boolean validate(AuthInfo auth) {
+        User user = auth.getLoginUser();
+        return user != null && user.isEnable() && user.getRole() == Role.SCHOOL_ADMIN;
+    }
+
+    @Override
+    public String getName() {
+        return "adminUser";
+    }
+
+}

+ 41 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/validator/AuthValidateService.java

@@ -0,0 +1,41 @@
+package cn.com.qmth.stmms.biz.api.auth.service.validator;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.stmms.biz.api.auth.interfaces.AuthValidator;
+
+@Service("authValidateService")
+public class AuthValidateService {
+
+    private Map<String, AuthValidator> map = new HashMap<String, AuthValidator>();
+
+    public List<AuthValidator> getValidators(String[] names) {
+        List<AuthValidator> list = new LinkedList<AuthValidator>();
+        list.add(getValidator("default"));
+
+        if (names != null && names.length > 0) {
+            for (String name : names) {
+                AuthValidator v = getValidator(name);
+                if (v != null) {
+                    list.add(v);
+                }
+            }
+        }
+        return list;
+    }
+
+    public AuthValidator getValidator(String name) {
+        return map.get(name);
+    }
+
+    protected void addValidator(AuthValidator validator) {
+        if (validator != null) {
+            map.put(validator.getName(), validator);
+        }
+    }
+}

+ 45 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/validator/DefaultValidator.java

@@ -0,0 +1,45 @@
+package cn.com.qmth.stmms.biz.api.auth.service.validator;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.stmms.biz.api.auth.interfaces.AuthValidator;
+import cn.com.qmth.stmms.biz.api.auth.model.AuthInfo;
+import cn.com.qmth.stmms.biz.api.auth.model.BasicAuthInfo;
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.biz.user.service.UserService;
+import cn.com.qmth.stmms.common.utils.Md5EncryptUtils;
+
+@Component
+public class DefaultValidator implements AuthValidator {
+
+    @Autowired
+    private AuthValidateService validateService;
+
+    @Autowired
+    private UserService userService;
+
+    @PostConstruct
+    protected void init() {
+        validateService.addValidator(this);
+    }
+
+    @Override
+    public String getName() {
+        return "default";
+    }
+
+    @Override
+    public boolean validate(AuthInfo auth) {
+        BasicAuthInfo info = (BasicAuthInfo) auth;
+        User user = userService.findByLoginName(info.getLoginName());
+        if (user != null && user.isEnable() && user.getPassword().equals(Md5EncryptUtils.md5(info.getPassword()))) {
+            info.setLoginUser(user);
+            return true;
+        }
+        return false;
+    }
+
+}

+ 35 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/api/auth/service/validator/ScannerValidator.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.stmms.biz.api.auth.service.validator;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.stmms.biz.api.auth.interfaces.AuthValidator;
+import cn.com.qmth.stmms.biz.api.auth.model.AuthInfo;
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.common.enums.Role;
+
+@Component
+public class ScannerValidator implements AuthValidator {
+
+    @Autowired
+    private AuthValidateService validateService;
+
+    @PostConstruct
+    protected void init() {
+        validateService.addValidator(this);
+    }
+
+    @Override
+    public boolean validate(AuthInfo auth) {
+        User user = auth.getLoginUser();
+        return user != null && user.isEnable() && user.getRole() == Role.SCANNER;
+    }
+
+    @Override
+    public String getName() {
+        return "scanner";
+    }
+
+}

+ 16 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/dao/CampusDao.java

@@ -0,0 +1,16 @@
+package cn.com.qmth.stmms.biz.campus.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.campus.model.Campus;
+
+public interface CampusDao extends PagingAndSortingRepository<Campus, Integer>, JpaSpecificationExecutor<Campus> {
+
+    public List<Campus> findBySchoolId(int schoolId);
+
+    public List<Campus> findBySchoolIdAndName(int schoolId, String name);
+
+}

+ 137 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/model/Campus.java

@@ -0,0 +1,137 @@
+package cn.com.qmth.stmms.biz.campus.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "b_campus")
+public class Campus implements Serializable {
+
+    private static final long serialVersionUID = -1056886453298677825L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    /**
+     * 所属学校ID
+     */
+    @Column(name = "school_id")
+    private Integer schoolId;
+
+    /**
+     * 学习中心名称
+     */
+    private String name;
+
+    /**
+     * 省份
+     */
+    private String province;
+
+    /**
+     * 城市
+     */
+    private String city;
+
+    /**
+     * 地区
+     */
+    private String district;
+
+    /**
+     * 地址
+     */
+    private String address;
+
+    /**
+     * 电话
+     */
+    private String phone;
+
+    /**
+     * 描述
+     */
+    private String description;
+
+    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 String getProvince() {
+        return province;
+    }
+
+    public void setProvince(String province) {
+        this.province = province;
+    }
+
+    public String getCity() {
+        return city;
+    }
+
+    public void setCity(String city) {
+        this.city = city;
+    }
+
+    public String getDistrict() {
+        return district;
+    }
+
+    public void setDistrict(String district) {
+        this.district = district;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Integer getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Integer schoolId) {
+        this.schoolId = schoolId;
+    }
+
+}

+ 58 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/query/CampusSearchQuery.java

@@ -0,0 +1,58 @@
+package cn.com.qmth.stmms.biz.campus.query;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.campus.model.Campus;
+
+public class CampusSearchQuery extends BaseQuery<Campus> {
+
+    private Integer schoolId;
+
+    private String name;
+
+    private String province;
+
+    private String city;
+
+    private String district;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getProvince() {
+        return province;
+    }
+
+    public void setProvince(String province) {
+        this.province = province;
+    }
+
+    public String getCity() {
+        return city;
+    }
+
+    public void setCity(String city) {
+        this.city = city;
+    }
+
+    public String getDistrict() {
+        return district;
+    }
+
+    public void setDistrict(String district) {
+        this.district = district;
+    }
+
+    public Integer getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Integer schoolId) {
+        this.schoolId = schoolId;
+    }
+
+}

+ 27 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/service/CampusService.java

@@ -0,0 +1,27 @@
+package cn.com.qmth.stmms.biz.campus.service;
+
+import java.util.List;
+import java.util.Map;
+
+import cn.com.qmth.stmms.biz.campus.model.Campus;
+import cn.com.qmth.stmms.biz.campus.query.CampusSearchQuery;
+
+public interface CampusService {
+
+    Campus save(Campus campus);
+
+    Campus findById(Integer id);
+
+    public Map<String, Campus> findBySchool(int schoolId);
+
+    List<Campus> findBySchoolId(int schoolId);
+
+    Campus findBySchoolAndName(int schoolId, String name);
+
+    public CampusSearchQuery findByQuery(final CampusSearchQuery query);
+
+    void deleteById(Integer id);
+
+    void delete(Campus campus);
+
+}

+ 117 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/campus/service/impl/CampusServiceImp.java

@@ -0,0 +1,117 @@
+package cn.com.qmth.stmms.biz.campus.service.impl;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.campus.dao.CampusDao;
+import cn.com.qmth.stmms.biz.campus.model.Campus;
+import cn.com.qmth.stmms.biz.campus.query.CampusSearchQuery;
+import cn.com.qmth.stmms.biz.campus.service.CampusService;
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+
+@Service("campusService")
+public class CampusServiceImp extends BaseQueryService<Campus> implements CampusService {
+
+    protected static Logger logger = LoggerFactory.getLogger(CampusServiceImp.class);
+
+    @Autowired
+    public CampusDao campusDao;
+
+    @Override
+    public Campus findById(Integer id) {
+        return campusDao.findOne(id);
+    }
+
+    public List<Campus> findBySchoolId(int schoolId) {
+        return campusDao.findBySchoolId(schoolId);
+    }
+
+    public Map<String, Campus> findBySchool(int schoolId) {
+        Map<String, Campus> map = new HashMap<String, Campus>();
+        List<Campus> list = findBySchoolId(schoolId);
+        if (list != null) {
+            for (Campus campus : list) {
+                map.put(campus.getName(), campus);
+            }
+        }
+        return map;
+    }
+
+    // @Cacheable(value = "campus_cache", key =
+    // "T(String).valueOf(#schoolId)+'-'+#name", condition = "#schoolId>0 &&
+    // #name!=null")
+    public Campus findBySchoolAndName(int schoolId, String name) {
+        List<Campus> list = campusDao.findBySchoolIdAndName(schoolId, name);
+        return list != null && list.size() > 0 ? list.get(0) : null;
+    }
+
+    public CampusSearchQuery findByQuery(final CampusSearchQuery query) {
+        checkQuery(query);
+        Page<Campus> result = campusDao.findAll(new Specification<Campus>() {
+
+            @Override
+            public Predicate toPredicate(Root<Campus> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (query.getSchoolId() != null) {
+                    predicates.add(cb.equal(root.get("schoolId"), query.getSchoolId()));
+                }
+                if (StringUtils.isNotBlank(query.getName())) {
+                    predicates.add(cb.like(root.get("name").as(String.class), query.getName() + "%"));
+                }
+                if (StringUtils.isNotBlank(query.getProvince())) {
+                    predicates.add(cb.equal(root.get("province"), query.getProvince()));
+                }
+                if (StringUtils.isNotBlank(query.getCity())) {
+                    predicates.add(cb.equal(root.get("city"), query.getCity()));
+                }
+                if (StringUtils.isNotBlank(query.getDistrict())) {
+                    predicates.add(cb.equal(root.get("district"), query.getDistrict()));
+                }
+                return predicates.isEmpty() ? cb.conjunction()
+                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+
+        }, query);
+
+        fillResult(result, query);
+        return query;
+    }
+
+    @Transactional
+    // @CachePut(value = "campus_cache", key =
+    // "T(String).valueOf(#campus.schoolId)+'-'+#campus.name", condition =
+    // "#campus!=null && #campus.schoolId!=null && #campus.name!=null")
+    public Campus save(Campus campus) {
+        return campusDao.save(campus);
+    }
+
+    @Transactional
+    // @CacheEvict(value = "campus_cache", allEntries = true, beforeInvocation =
+    // true)
+    public void deleteById(Integer id) {
+        campusDao.delete(id);
+    }
+
+    @Transactional
+    // @CacheEvict(value = "campus_cache", allEntries = true, beforeInvocation =
+    // true)
+    public void delete(Campus campus) {
+        campusDao.delete(campus);
+    }
+}

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

@@ -0,0 +1,296 @@
+package cn.com.qmth.stmms.biz.common;
+
+import java.util.List;
+
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+
+public class BaseQuery<T> implements Pageable {
+
+    public static final int DEFAULT_PAGE_SIZE = 10;
+
+    private int pageNumber = 1;
+
+    private int pageSize = 10;
+
+    private Sort sort;
+
+    private List<T> result;
+
+    private long currentCount;
+
+    private int totalPage;
+
+    private long totalCount;
+
+    private int first;// 首页索引
+
+    private int last;// 尾页索引
+
+    private int prev;// 上一页索引
+
+    private int next;// 下一页索引
+
+    private boolean firstPage;// 是否是第一页
+
+    private boolean lastPage;// 是否是最后一页
+
+    private int length = 8;// 显示页面长度
+
+    private int slider = 1;// 前后显示页面长度
+
+    private String funcName = "page"; // 设置点击页码调用的js函数名称,默认为page,在一页有多个分页对象时使用。
+
+    private String message = ""; // 设置提示消息,显示在“共n条”之后
+
+    public BaseQuery() {
+
+    }
+
+    public BaseQuery(int pageNumber, int pageSize, Sort sort) {
+        this.pageNumber = pageNumber;
+        this.pageSize = pageSize;
+        this.sort = sort;
+    }
+
+    public List<T> getResult() {
+        return result;
+    }
+
+    public void setResult(List<T> result) {
+        this.result = result;
+    }
+
+    @Override
+    public int getOffset() {
+        return (pageNumber - 1) * pageSize;
+    }
+
+    public void setPageNumber(int pageNumber) {
+        this.pageNumber = pageNumber;
+    }
+
+    @Override
+    public int getPageNumber() {
+        return pageNumber;
+    }
+
+    public void setPageSize(int pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    @Override
+    public int getPageSize() {
+        return pageSize;
+    }
+
+    public void setSort(Sort sort) {
+        this.sort = sort;
+    }
+
+    @Override
+    public Sort getSort() {
+        return sort;
+    }
+
+    public int getTotalPage() {
+        return totalPage;
+    }
+
+    public void setTotalPage(int totalPage) {
+        this.totalPage = totalPage;
+    }
+
+    public long getTotalCount() {
+        return totalCount;
+    }
+
+    public void setTotalCount(long totalCount) {
+        this.totalCount = totalCount;
+    }
+
+    public long getCurrentCount() {
+        return currentCount;
+    }
+
+    public void setCurrentCount(long currentCount) {
+        this.currentCount = currentCount;
+    }
+
+    @Override
+    public Pageable next() {
+        return new BaseQuery<T>(pageNumber + 1, pageSize, sort);
+    }
+
+    @Override
+    public Pageable previousOrFirst() {
+        return new BaseQuery<T>(pageNumber > 1 ? (pageNumber - 1) : 1, pageSize, sort);
+    }
+
+    @Override
+    public Pageable first() {
+        return new BaseQuery<T>(1, pageSize, sort);
+    }
+
+    @Override
+    public boolean hasPrevious() {
+        return pageNumber > 1;
+    }
+
+    /**
+     * 初始化参数
+     */
+    public void initialize() {
+
+        // 1
+        this.first = 1;
+
+        this.last = (int) (totalCount / (this.pageSize < 1 ? 20 : this.pageSize) + first - 1);
+
+        if (this.totalCount % this.pageSize != 0 || this.last == 0) {
+            this.last++;
+        }
+
+        if (this.last < this.first) {
+            this.last = this.first;
+        }
+
+        if (this.pageNumber <= 1) {
+            this.pageNumber = this.first;
+            this.firstPage = true;
+        }
+
+        if (this.pageNumber >= this.last) {
+            this.pageNumber = this.last;
+            this.lastPage = true;
+        }
+
+        if (this.pageNumber < this.last - 1) {
+            this.next = this.pageNumber + 1;
+        } else {
+            this.next = this.last;
+        }
+
+        if (this.pageNumber > 1) {
+            this.prev = this.pageNumber - 1;
+        } else {
+            this.prev = this.first;
+        }
+
+        // 2
+        if (this.pageNumber < this.first) {// 如果当前页小于首页
+            this.pageNumber = this.first;
+        }
+
+        if (this.pageNumber > this.last) {// 如果当前页大于尾页
+            this.pageNumber = this.last;
+        }
+
+    }
+
+    /**
+     * 默认输出当前分页标签 <div class="page">${page}</div>
+     */
+    @Override
+    public String toString() {
+
+        initialize();
+
+        StringBuilder sb = new StringBuilder();
+
+        if (pageNumber == first) {// 如果是首页
+            sb.append("<li class=\"disabled\"><a href=\"javascript:\">&#171; 上一页</a></li>\n");
+        } else {
+            sb.append("<li><a href=\"javascript:\" onclick=\"" + funcName + "(" + prev + "," + pageSize
+                    + ");\">&#171; 上一页</a></li>\n");
+        }
+
+        int begin = pageNumber - (length / 2);
+
+        if (begin < first) {
+            begin = first;
+        }
+
+        int end = begin + length - 1;
+
+        if (end >= last) {
+            end = last;
+            begin = end - length + 1;
+            if (begin < first) {
+                begin = first;
+            }
+        }
+
+        if (begin > first) {
+            int i = 0;
+            for (i = first; i < first + slider && i < begin; i++) {
+                sb.append("<li><a href=\"javascript:\" onclick=\"" + funcName + "(" + i + "," + pageSize + ");\">"
+                        + (i + 1 - first) + "</a></li>\n");
+            }
+            if (i < begin) {
+                sb.append("<li class=\"disabled\"><a href=\"javascript:\">...</a></li>\n");
+            }
+        }
+
+        for (int i = begin; i <= end; i++) {
+            if (i == pageNumber) {
+                sb.append("<li class=\"active\"><a href=\"javascript:\">" + (i + 1 - first) + "</a></li>\n");
+            } else {
+                sb.append("<li><a href=\"javascript:\" onclick=\"" + funcName + "(" + i + "," + pageSize + ");\">"
+                        + (i + 1 - first) + "</a></li>\n");
+            }
+        }
+
+        if (last - end > slider) {
+            sb.append("<li class=\"disabled\"><a href=\"javascript:\">...</a></li>\n");
+            end = last - slider;
+        }
+
+        for (int i = end + 1; i <= last; i++) {
+            sb.append("<li><a href=\"javascript:\" onclick=\"" + funcName + "(" + i + "," + pageSize + ");\">"
+                    + (i + 1 - first) + "</a></li>\n");
+        }
+
+        if (pageNumber == last) {
+            sb.append("<li class=\"disabled\"><a href=\"javascript:\">下一页 &#187;</a></li>\n");
+        } else {
+            sb.append("<li><a href=\"javascript:\" onclick=\"" + funcName + "(" + next + "," + pageSize + ");\">"
+                    + "下一页 &#187;</a></li>\n");
+        }
+
+        sb.append("<li class=\"disabled controls\"><a href=\"javascript:\">当前 ");
+        sb.append("<input type=\"text\" value=\"" + pageNumber
+                + "\" onkeypress=\"var e=window.event||this;var c=e.keyCode||e.which;if(c==13)");
+        sb.append(funcName + "(this.value," + pageSize + ");\" onclick=\"this.select();\"/> / ");
+        sb.append("<input type=\"text\" value=\"" + pageSize
+                + "\" onkeypress=\"var e=window.event||this;var c=e.keyCode||e.which;if(c==13)");
+        sb.append(funcName + "(" + pageNumber + ",this.value);\" onclick=\"this.select();\"/> 页,");
+        sb.append("共 " + totalCount + " 条" + (message != null ? message : "") + "</a><li>\n");
+
+        sb.insert(0, "<ul>\n").append("</ul>\n");
+
+        sb.append("<div style=\"clear:both;\"></div>");
+
+        // sb.insert(0,"<div class=\"page\">\n").append("</div>\n");
+
+        return sb.toString();
+    }
+
+    /**
+     * 获取分页HTML代码
+     * 
+     * @return
+     */
+    public String getHtml() {
+        return toString();
+    }
+
+    public boolean isFirstPage() {
+        return firstPage;
+    }
+
+    public boolean isLastPage() {
+        return lastPage;
+    }
+
+}

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

@@ -0,0 +1,28 @@
+package cn.com.qmth.stmms.biz.common;
+
+import org.springframework.data.domain.Page;
+
+public class BaseQueryService<T> {
+
+    public void checkQuery(BaseQuery<T> query) {
+        if (query.getPageNumber() < 1) {
+            query.setPageNumber(1);
+        }
+        if (query.getPageSize() < 1) {
+            query.setPageSize(10);
+        }
+    }
+
+    public void fillResult(Page<T> result, BaseQuery<T> query) {
+        if (result != null) {
+            query.setTotalCount(result.getTotalElements());
+            query.setTotalPage(result.getTotalPages());
+            query.setCurrentCount(result.getNumberOfElements());
+            query.setResult(result.getContent());
+        } else {
+            query.setTotalCount(0);
+            query.setTotalPage(0);
+            query.setCurrentCount(0);
+        }
+    }
+}

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

@@ -0,0 +1,29 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.List;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.Exam;
+import cn.com.qmth.stmms.common.enums.ExamStatus;
+
+public interface ExamDao extends PagingAndSortingRepository<Exam, Integer>, JpaSpecificationExecutor<Exam> {
+
+    public Page<Exam> findAll(Pageable pageable);
+
+    List<Exam> findByStatus(ExamStatus status);
+
+    @Query("select e from Exam e where e.creatorId=?1 and e.status=?2 order by e.examTime desc")
+    public List<Exam> findByCreatorAndStatus(Integer id, ExamStatus status);
+
+    @Modifying
+    @Query("update Exam e set e.status=?2 where e.id=?1")
+    public void updateStatus(int examId, ExamStatus status);
+
+    public List<Exam> findBySchoolIdOrderByIdDesc(Integer schoolId);
+}

+ 43 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamPackageDao.java

@@ -0,0 +1,43 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamPackage;
+import cn.com.qmth.stmms.biz.exam.model.ExamPackagePK;
+
+public interface ExamPackageDao
+        extends PagingAndSortingRepository<ExamPackage, ExamPackagePK>, JpaSpecificationExecutor<ExamPackage> {
+
+    @Query("select s from ExamPackage s where s.pk.examId=?1")
+    public List<ExamPackage> findByExamId(int examId);
+
+    @Query("select count(s) from ExamPackage s where s.pk.examId=?1")
+    public long countByExamId(int examId);
+
+    @Query("select count(s) from ExamPackage s where s.pk.examId=?1 and s.picCount>0")
+    public long countByExamIdAndUpload(int examId);
+
+    @Query("select count(s) from ExamPackage s where s.pk.examId=?1 and s.picCount=0")
+    public long countByExamIdAndUnUpload(int examId);
+
+    @Query("select s from ExamPackage s where s.pk.examId=?1 and s.pk.code=?2")
+    public ExamPackage findByExamIdAndCode(int examId, String code);
+
+    @Query("select s from ExamPackage s where s.pk.examId=?1 and s.picCount>0")
+    public List<ExamPackage> findByExamIdAndUpload(int examId);
+
+    @Query("select s from ExamPackage s where s.pk.examId=?1 and s.picCount=0")
+    public List<ExamPackage> findByExamIdAndUnUpload(int examId);
+
+    @Modifying
+    @Query("delete ExamPackage s where s.pk.examId=?1")
+    void deleteByExamId(int examId);
+
+    @Query("select COALESCE(sum(s.picCount),0) from ExamPackage s where s.pk.examId=?1")
+    public long sumByExamId(int examId);
+}

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

@@ -0,0 +1,48 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.QuestionPK;
+
+public interface ExamQuestionDao
+        extends JpaRepository<ExamQuestion, QuestionPK>, JpaSpecificationExecutor<ExamQuestion> {
+
+    @Query("select q from ExamQuestion q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.pk.objective=?3 order by q.pk.mainNumber, q.pk.subNumber")
+    public List<ExamQuestion> findByExamIdAndSubjectCodeAndObjective(int examId, String subjectCode, boolean objective);
+
+    @Query("select q from ExamQuestion q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.pk.objective=?3 and q.pk.mainNumber=?4 order by q.pk.subNumber")
+    public List<ExamQuestion> findByExamIdAndSubjectCodeAndObjectiveAndMainNumber(int examId, String subjectCode,
+            boolean objective, int mainNumber);
+
+    @Query("select sum(q.totalScore) from ExamQuestion q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.pk.objective=?3")
+    public Double sumScoreByExamIdAndSubjectCodeAndObjective(int examId, String subjectCode, boolean objective);
+
+    @Modifying
+    @Query("delete from ExamQuestion q where q.pk.examId=?1")
+    public void deleteByExamId(int examId);
+
+    @Modifying
+    @Query("delete from ExamQuestion q where q.pk.examId=?1 and q.pk.subjectCode=?2")
+    public void deleteByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    @Modifying
+    @Query("delete from ExamQuestion q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.pk.objective=?3")
+    public void deleteByExamIdAndSubjectCodeAndObjective(int examId, String subjectCode, boolean objective);
+
+    @Modifying
+    @Query("delete from ExamQuestion q where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.pk.objective=?3 and q.pk.mainNumber=?4")
+    public void deleteByExamIdAndSubjectCodeAndObjectiveAndMainNumber(int examId, String subjectCode, boolean objective,
+            int mainNumber);
+
+    @Modifying
+    @Query("update ExamQuestion q set q.mainTitle=?5 where q.pk.examId=?1 and q.pk.subjectCode=?2 and q.pk.objective=?3 and q.pk.mainNumber=?4")
+    public void updateMainTitleByExamIdAndSubjectCodeAndObjectiveAndMainNumber(int examId, String subjectCode,
+            boolean objective, int mainNumber, String mainTitle);
+
+}

+ 120 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamStudentDao.java

@@ -0,0 +1,120 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+
+public interface ExamStudentDao
+        extends PagingAndSortingRepository<ExamStudent, Integer>, JpaSpecificationExecutor<ExamStudent> {
+
+    public List<ExamStudent> findByExamId(int examId, Pageable pageable);
+
+    public List<ExamStudent> findByExamIdAndUploadAndAbsent(int examId, boolean upload, boolean absent,
+            Pageable pageable);
+
+    public List<ExamStudent> findByExamIdAndCampusName(int examId, String campusName, Pageable pageable);
+
+    public List<ExamStudent> findByExamIdAndExamNumber(int examId, String examNumber);
+
+    @Query("select count(s) from ExamStudent s where s.examId=?1 and s.campusName=?2")
+    public long countByExamIdAndCampusName(int examId, String campusName);
+
+    @Query("select count(distinct s.campusName) from ExamStudent s where s.examId=?1")
+    public long countCampusNameByExamId(int examId);
+
+    @Query("select s from ExamStudent s where s.examId=?1 group by s.subjectCode")
+    public List<ExamStudent> findDistinctSubjectByExamId(int examId, Pageable pageable);
+
+    @Query("select s from ExamStudent s where s.examId=?1 and s.campusName=?2 group by s.subjectCode")
+    public List<ExamStudent> findDistinctSubjectByExamIdAndCampusName(int examId, String campusName);
+
+    @Query("select s.campusName from ExamStudent s where s.examId=?1 group by s.campusName")
+    public List<String> findDistinctCampusName(int examId);
+
+    @Query("select s from ExamStudent s where s.examId=?1 group by s.campusName")
+    public List<ExamStudent> findDistinctCampusName(int examId, Pageable pageable);
+
+    @Query("select count(c) from Campus c where exists (select s.id from ExamStudent s where "
+            + "c.schoolId=s.schoolId and c.name=s.campusName and s.examId=?1)")
+    public long countDistinctCampusName(int examId);
+
+    @Query("select s.packageCode from ExamStudent s where s.examId=?1 group by s.packageCode")
+    public List<String> findDistinctPackageCode(int examId);
+
+    @Modifying
+    @Query("update ExamStudent s set s.subjectiveScore=?2, s.subjectiveScoreList=?3 where s.id=?1")
+    public void updateSubjectiveScore(int id, double score, String scoreList);
+
+    @Modifying
+    @Query("update ExamStudent s set s.subjectName=?3, s.subjectLevel=?4, s.subjectCategory=?5 where s.examId=?1 and s.subjectCode=?2")
+    public void updateSubjectInfo(int examId, String subjectCode, String subjectName, String subjectLevel,
+            String subjectCategory);
+
+    @Modifying
+    @Query("update ExamStudent s set s.exception=?2 where s.id=?1")
+    public void updateException(int id, boolean exception);
+
+    @Modifying
+    @Query("delete from ExamStudent s where s.examId=?1")
+    public void deleteByExamId(int examId);
+
+    @Modifying
+    @Query("delete from ExamStudent s where s.examId=?1 and s.campusName=?2")
+    public void deleteByExamIdAndCampusName(int examId, String campusName);
+
+    public ExamStudent findByExamIdAndSubjectCodeAndStudentCode(Integer id, String subjectCode, String studentCode);
+
+    public ExamStudent findBySchoolIdAndSubjectCodeAndStudentCodeAndRemark(Integer schoolId, String subjectCode,
+            String studentCode, String examSeqCode);
+
+    public List<ExamStudent> findByExamIdAndUploadTimeAfter(int examId, Date date);
+
+    public List<ExamStudent> findByExamIdAndSubjectCodeAndUploadTimeAfter(int examId, String code, Date date,
+            Pageable page);
+
+    @Query("select count(s) from ExamStudent s where s.examId=?1 and s.subjectiveScoreList != null ")
+    public long countByExamIdAndSubjectiveScoreListNotNull(Integer examId);
+
+    public List<ExamStudent> findByExamIdAndSubjectCodeAndUploadTimeNotNull(int examId, String code);
+
+    @Query("select s from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.absent=false and s.uploadTime!=null "
+            + "and not exists (select l.id from MarkLibrary l where l.studentId=s.id and l.groupNumber=?3)")
+    public List<ExamStudent> findUnLibraryStudent(int examId, String subjectCode, int groupNumber, Pageable page);
+
+    @Query("select s from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.absent=false and s.uploadTime!=null and s.uploadTime>=?4 "
+            + "and not exists (select l.id from MarkLibrary l where l.studentId=s.id and l.groupNumber=?3)")
+    public List<ExamStudent> findUnLibraryStudent(int examId, String subjectCode, int groupNumber, Date minUploadTime,
+            Pageable page);
+
+    @Query("select s.id from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.absent=true and "
+            + "exists (select l.id from MarkLibrary l where l.studentId=s.id)")
+    public List<Integer> findAbsentLibraryStudent(int examId, String subjectCode);
+    
+    @Query("select sum(case when (s.objectiveScore + s.subjectiveScore) between 0 and 49 then 1 else 0 end),"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 50 and 59 then 1 else 0 end) ,"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 60 and 69 then 1 else 0 end) ,"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 70 and 79 then 1 else 0 end) ,"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 80 and 89 then 1 else 0 end) ,"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 90 and 100 then 1 else 0 end) "
+    		+ " from ExamStudent s where s.examId=?1 and s.subjectCode=?2 and s.upload=?3  and s.absent=?4 ")
+	public List<Object[]> statisticsByExamIdAndSubjectCode(Integer examId,
+			String code, Boolean upload, boolean absent);
+
+    @Query("select sum(case when (s.objectiveScore + s.subjectiveScore) between 0 and 49 then 1 else 0 end),"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 50 and 59 then 1 else 0 end) ,"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 60 and 69 then 1 else 0 end) ,"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 70 and 79 then 1 else 0 end) ,"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 80 and 89 then 1 else 0 end) ,"
+    		+ "sum(case when (s.objectiveScore + s.subjectiveScore) between 90 and 100 then 1 else 0 end) "
+    		+ " from ExamStudent s where s.examId=?1 and s.subjectCode=?2 ")
+	public List<Object[]> statisticsByExamIdAndSubjectCode(Integer examId,
+			String code);
+
+}

+ 82 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ExamSubjectDao.java

@@ -0,0 +1,82 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.biz.exam.model.ExamSubjectPK;
+import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
+
+public interface ExamSubjectDao
+        extends PagingAndSortingRepository<ExamSubject, ExamSubjectPK>, JpaSpecificationExecutor<ExamSubject> {
+
+    @Query("select s from ExamSubject s where s.pk.examId=?1")
+    public List<ExamSubject> findByExamId(int examId);
+
+    @Query("select s.level from ExamSubject s where s.pk.examId=?1 and s.level is not null group by s.level")
+    public List<String> findDistinctLevel(int examId);
+
+    @Query("select s.category from ExamSubject s where s.pk.examId=?1 and s.category is not null group by s.category")
+    public List<String> findDistinctCategory(int examId);
+
+    @Query("select count(s) from ExamSubject s where s.pk.examId=?1")
+    public long countByExamId(int examId);
+
+    @Query("select s from ExamSubject s where s.pk.examId=?1 and s.pk.code=?2")
+    public ExamSubject findByExamIdAndCode(int examId, String code);
+
+    @Query("select s from ExamSubject s where s.pk.examId=?1 and s.uploadCount>?2")
+    public List<ExamSubject> findByExamIdAndUploadCountGt(int examId, int uploadCount);
+
+    @Query("select s from ExamSubject s where s.pk.examId=?1 and s.status=?2 and s.uploadCount>?3")
+    public List<ExamSubject> findByExamIdAndStatusAndUploadCountGt(int examId, ExamSubjectStatus status,
+            int uploadCount);
+
+    @Query("select s from ExamSubject s where s.pk.examId=?1 and s.status in ?2")
+    public List<ExamSubject> findByExamIdAndStatus(int examId, Set<ExamSubjectStatus> status);
+
+    @Query("select s from ExamSubject s where s.status in ?1")
+    public List<ExamSubject> findByStatus(Set<ExamSubjectStatus> status);
+
+    @Query("select count(s) from ExamSubject s where s.pk.examId=?1 and s.status in ?2")
+    public long countByExamIdAndStatus(int examId, Set<ExamSubjectStatus> status);
+
+    @Modifying
+    @Query("update ExamSubject s set s.status=?2 where s.pk.examId=?1")
+    public void updateStatusByExamId(int examId, ExamSubjectStatus status);
+
+    @Modifying
+    @Query("update ExamSubject s set s.totalScore=s.objectiveScore+s.subjectiveScore where s.pk.examId=?1")
+    public void updateTotalScoreByExamId(int examId);
+
+    @Modifying
+    @Query("update ExamSubject s set s.totalScore=s.objectiveScore+s.subjectiveScore where s.pk.examId=?1 and s.pk.code=?2")
+    public void updateTotalScoreByExamIdAndCode(int examId, String code);
+
+    @Modifying
+    @Query("update ExamSubject s set s.objectiveScore=?3 where s.pk.examId=?1 and s.pk.code=?2")
+    public void updateObjectiveScore(int examId, String code, double score);
+
+    @Modifying
+    @Query("update ExamSubject s set s.subjectiveScore=?3 where s.pk.examId=?1 and s.pk.code=?2")
+    public void updateSubjectiveScore(int examId, String code, double score);
+
+    @Modifying
+    @Query("delete ExamSubject s where s.pk.examId=?1")
+    void deleteByExamId(int examId);
+
+    @Modifying
+    @Query("update ExamSubject s set s.uploadCount=(select count(s) from ExamStudent es where es.examId=?1 "
+            + "and es.subjectCode=?2 and es.upload=true and es.absent=false) where s.pk.examId=?1 and s.pk.code=?2")
+    public void updateUploadByExamIdAndCode(Integer examId, String subjectCode);
+
+    @Modifying
+    @Query("update ExamSubject s set s.uploadCount=(select count(s) from ExamStudent es where es.examId=?1 "
+            + "and es.subjectCode=s.pk.code and es.upload=true and es.absent=false) where s.pk.examId=?1")
+    public void updateUploadByExamId(Integer examId);
+}

+ 97 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/MarkGroupDao.java

@@ -0,0 +1,97 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroupPK;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+
+public interface MarkGroupDao
+        extends PagingAndSortingRepository<MarkGroup, MarkGroupPK>, JpaSpecificationExecutor<MarkGroup> {
+
+    @Modifying
+    @Query("delete from MarkGroup q where q.pk.examId=?1")
+    void deleteByExamId(int examId);
+
+    @Modifying
+    @Query("delete from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2")
+    void deleteByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    @Query("select count(q) from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2")
+    long countByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    @Query("select q from MarkGroup q where q.pk.examId=?1 order by q.pk.number")
+    List<MarkGroup> findByExamId(int examId);
+
+    @Query("select q from MarkGroup q where q.pk.examId=?1 and q.pk.subjectCode=?2 order by q.pk.number")
+    List<MarkGroup> findByExamIdAndSubjectCode(int examId, String code);
+
+    @Query("select count(q) from MarkGroup q where q.pk.examId=?1")
+    long countByExamId(int examId);
+
+    @Modifying
+    @Query("update MarkGroup g set g.libraryCount=(select count(l) from MarkLibrary l "
+            + "where l.examId=?1 and l.subjectCode=?2 and l.groupNumber=g.pk.number) "
+            + "where g.pk.examId=?1 and g.pk.subjectCode=?2")
+    void updateLibraryCount(int examId, String subjectCode);
+
+    @Modifying
+    @Query("update MarkGroup g set g.markedCount=(select count(l) from MarkLibrary l "
+            + "where l.examId=?1 and l.subjectCode=?2 and l.groupNumber=g.pk.number and l.status=?3) "
+            + "where g.pk.examId=?1 and g.pk.subjectCode=?2")
+    void updateMarkedCount(int examId, String subjectCode, LibraryStatus status);
+
+    @Modifying
+    @Query("update MarkGroup g set g.leftCount = g.libraryCount - g.markedCount "
+            + "where g.pk.examId=?1 and g.pk.subjectCode=?2")
+    void updateLeftCount(int examId, String subjectCode);
+
+    @Modifying
+    @Query("update MarkGroup g set g.libraryCount=(select count(l) from MarkLibrary l "
+            + "where l.examId=?1 and l.subjectCode=?2 and l.groupNumber=?3) "
+            + "where g.pk.examId=?1 and g.pk.subjectCode=?2 and g.pk.number=?3")
+    void updateLibraryCount(int examId, String subjectCode, int number);
+
+    @Modifying
+    @Query("update MarkGroup g set g.markedCount=(select count(l) from MarkLibrary l "
+            + "where l.examId=?1 and l.subjectCode=?2 and l.groupNumber=?3 and l.status=?4 ) "
+            + "where g.pk.examId=?1 and g.pk.subjectCode=?2 and g.pk.number=?3")
+    void updateMarkedCount(int examId, String subjectCode, int number, LibraryStatus status);
+
+    @Modifying
+    @Query("update MarkGroup g set g.leftCount = g.libraryCount - g.markedCount "
+            + "where g.pk.examId=?1 and g.pk.subjectCode=?2 and g.pk.number=?3")
+    void updateLeftCount(int examId, String subjectCode, int number);
+
+    @Modifying
+    @Query("update MarkGroup g set g.leftCount = g.libraryCount, g.markedCount = 0 "
+            + "where g.pk.examId=?1 and g.pk.subjectCode=?2 and g.pk.number=?3")
+    void resetCount(int examId, String subjectCode, int number);
+
+    @Modifying
+    @Query("update MarkGroup g set g.picList=?4 where g.pk.examId=?1 and g.pk.subjectCode=?2 and g.pk.number=?3")
+    void updatePicList(int examId, String subjectCode, int number, String picList);
+
+    @Modifying
+    @Query("update MarkGroup g set g.title=?4 where g.pk.examId=?1 and g.pk.subjectCode=?2 and g.pk.number=?3")
+    void updateTitle(int examId, String subjectCode, int number, String title);
+
+    @Modifying
+    @Query("update MarkGroup g set g.totalScore=?4 where g.pk.examId=?1 and g.pk.subjectCode=?2 and g.pk.number=?3")
+    void updateTotalScore(int examId, String subjectCode, int number, Double score);
+
+    @Modifying
+    @Query("update MarkGroup g set g.buildTime=?4 where g.pk.examId=?1 and g.pk.subjectCode=?2 and g.pk.number=?3")
+    void updateBuildTime(int examId, String subjectCode, int number, Date time);
+
+    @Modifying
+    @Query("update MarkGroup g set g.buildTime=?3 where g.pk.examId=?1 and g.pk.subjectCode=?2")
+    void updateBuildTime(int examId, String subjectCode, Date time);
+
+}

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

@@ -0,0 +1,44 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.List;
+
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+
+public interface MarkerDao extends PagingAndSortingRepository<Marker, Integer>, JpaSpecificationExecutor<Marker> {
+
+    @Query("select count(m) from Marker m where m.examId=?1")
+    public long countByExamId(int examId);
+
+    @Query("select count(m) from Marker m where m.examId=?1 and m.subjectCode=?2 and m.groupNumber=?3")
+    public long countByExamIdAndSubjectCodeAndGroupNumber(int examId, String subjectCode, int number);
+
+    public List<Marker> findByExamId(int examId);
+
+    public List<Marker> findByExamIdAndSubjectCode(int examId, String subjectCode, Pageable page);
+
+    public List<Marker> findByExamIdAndSubjectCodeAndGroupNumber(int examId, String subjectCode, int number,
+            Pageable page);
+
+    public List<Marker> findByLoginName(String loginName);
+
+    public List<Marker> findByLoginNameAndPassword(String loginName, String password);
+
+    @Modifying
+    @Query("delete from Marker m where m.examId=?1 and m.subjectCode=?2 and m.groupNumber=?3")
+    public void deleteByExamIdAndSubjectCodeAndGroupNumber(int examId, String subjectCode, int number);
+
+    @Modifying
+    @Query("delete from Marker m where m.examId=?1 and m.subjectCode=?2")
+    public void deleteByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    @Modifying
+    @Query("delete from Marker m where m.examId=?1")
+    public void deleteByExamId(int examId);
+
+}

+ 12 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/ScoreRateDao.java

@@ -0,0 +1,12 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.ScoreRate;
+import cn.com.qmth.stmms.biz.exam.model.ScoreRatePK;
+
+public interface ScoreRateDao extends PagingAndSortingRepository<ScoreRate, ScoreRatePK>,
+        JpaSpecificationExecutor<ScoreRate> {
+
+}

+ 15 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/dao/TagDao.java

@@ -0,0 +1,15 @@
+package cn.com.qmth.stmms.biz.exam.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.exam.model.Tag;
+
+public interface TagDao extends PagingAndSortingRepository<Tag, Integer>, JpaSpecificationExecutor<Tag> {
+
+    @Query("select t from Tag t")
+    public List<Tag> list();
+}

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

@@ -0,0 +1,128 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import cn.com.qmth.stmms.common.enums.ExamStatus;
+
+@Entity
+@Table(name = "eb_exam")
+public class Exam implements Serializable {
+
+    private static final long serialVersionUID = 5179623303410999209L;
+
+    public static final String SUBJECT_ID_SPLIT = ",";
+
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    private String name;
+
+    @Column(name = "school_id")
+    private Integer schoolId;
+
+    @Temporal(TemporalType.DATE)
+    @Column(name = "exam_time")
+    private Date examTime;
+
+    @Enumerated(EnumType.STRING)
+    @Column(name = "status", length = 16, nullable = false)
+    private ExamStatus status;
+
+    private String description;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name = "create_time")
+    private Date createTime;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name = "update_time")
+    private Date updateTime;
+
+    @Column(name = "creator_id")
+    private Integer creatorId;
+
+    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 String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Date getExamTime() {
+        return examTime;
+    }
+
+    public void setExamTime(Date examTime) {
+        this.examTime = examTime;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Integer getCreatorId() {
+        return creatorId;
+    }
+
+    public void setCreatorId(Integer creatorId) {
+        this.creatorId = creatorId;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public ExamStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(ExamStatus status) {
+        this.status = status;
+    }
+
+    public Integer getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Integer schoolId) {
+        this.schoolId = schoolId;
+    }
+
+}

+ 73 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamPackage.java

@@ -0,0 +1,73 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import org.apache.commons.lang.StringUtils;
+
+@Entity
+@Table(name = "eb_exam_package")
+public class ExamPackage implements Serializable {
+
+    private static final long serialVersionUID = 1713850212826781261L;
+
+    @EmbeddedId
+    private ExamPackagePK pk;
+
+    @Column(name = "pic_count")
+    private Integer picCount;
+
+    @Transient
+    private List<String> urls;
+
+    public ExamPackage() {
+        this.pk = new ExamPackagePK();
+    }
+
+    public Integer getExamId() {
+        return pk.getExamId();
+    }
+
+    public void setExamId(Integer examId) {
+        pk.setExamId(examId);
+    }
+
+    public String getCode() {
+        return pk.getCode();
+    }
+
+    public void setCode(String code) {
+        pk.setCode(code);
+    }
+
+    public Integer getPicCount() {
+        return picCount;
+    }
+
+    public void setPicCount(Integer picCount) {
+        this.picCount = picCount;
+    }
+
+    public List<String> getUrls() {
+        return urls;
+    }
+
+    public void setUrls(List<String> urls) {
+        this.urls = urls;
+    }
+
+    public String getUrlString() {
+        if (urls != null) {
+            return StringUtils.join(urls, ",");
+        } else {
+            return "";
+        }
+    }
+
+}

+ 75 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamPackagePK.java

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

+ 206 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamQuestion.java

@@ -0,0 +1,206 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+@Entity
+@Table(name = "eb_exam_question")
+public class ExamQuestion implements Serializable {
+
+    private static final long serialVersionUID = -6614640229855098561L;
+
+    @EmbeddedId
+    private QuestionPK pk;
+
+    @Column(name = "main_title", length = 128)
+    private String mainTitle;
+
+    @Column(name = "answer")
+    private String answer;
+
+    @Column(name = "total_score")
+    private Double totalScore;
+
+    @Column(name = "interval_score")
+    private Double intervalScore;
+
+    /**
+     * 考生人数
+     */
+    @Column(name = "total_count")
+    private Integer totalCount;
+
+    /**
+     * 零分人数
+     */
+    @Column(name = "zero_count")
+    private Integer zeroCount;
+
+    /**
+     * 满分人数
+     */
+    @Column(name = "full_count")
+    private Integer fullCount;
+
+    @Transient
+    private ExamSubject subject;
+
+    @Transient
+    private String picList;
+
+    public ExamQuestion() {
+        this.pk = new QuestionPK();
+    }
+
+    public Integer getExamId() {
+        return pk.getExamId();
+    }
+
+    public void setExamId(Integer examId) {
+        pk.setExamId(examId);
+    }
+
+    public String getSubjectCode() {
+        return pk.getSubjectCode();
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        pk.setSubjectCode(subjectCode);
+    }
+
+    public Integer getMainNumber() {
+        return pk.getMainNumber();
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        pk.setMainNumber(mainNumber);
+    }
+
+    public Integer getSubNumber() {
+        return pk.getSubNumber();
+    }
+
+    public void setSubNumber(Integer subNumber) {
+        pk.setSubNumber(subNumber);
+    }
+
+    public String getMainTitle() {
+        return mainTitle;
+    }
+
+    public void setObjective(boolean objective) {
+        pk.setObjective(objective);
+    }
+
+    public boolean isObjective() {
+        return pk.isObjective();
+    }
+
+    public void setMainTitle(String mainTitle) {
+        this.mainTitle = mainTitle;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public String getName() {
+        if (mainTitle != null && getSubNumber() != null) {
+            return mainTitle + "-" + getSubNumber();
+        } else {
+            return "";
+        }
+    }
+
+    public List<Double> getScoreList() {
+        List<Double> list = new LinkedList<Double>();
+        if (totalScore != null && intervalScore != null) {
+            for (double score = 0; score <= totalScore; score += intervalScore) {
+                list.add(score);
+            }
+        }
+        return list;
+    }
+
+    public double[] getScoreListArray() {
+        List<Double> list = getScoreList();
+        int length = list.size();
+        double[] array = new double[length];
+        for (int i = 0; i < list.size(); i++) {
+            array[i] = list.get(i);
+        }
+        return array;
+    }
+
+    public String getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(String answer) {
+        this.answer = answer;
+    }
+
+    public Double getIntervalScore() {
+        return intervalScore;
+    }
+
+    public void setIntervalScore(Double intervalScore) {
+        this.intervalScore = intervalScore;
+    }
+
+    public Integer getZeroCount() {
+        return zeroCount;
+    }
+
+    public void setZeroCount(Integer zeroCount) {
+        this.zeroCount = zeroCount;
+    }
+
+    public Integer getFullCount() {
+        return fullCount;
+    }
+
+    public void setFullCount(Integer fullCount) {
+        this.fullCount = fullCount;
+    }
+
+    public Integer getTotalCount() {
+        return totalCount;
+    }
+
+    public void setTotalCount(Integer totalCount) {
+        this.totalCount = totalCount;
+    }
+
+    public ExamSubject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(ExamSubject subject) {
+        this.subject = subject;
+    }
+
+    public String getQuestionNumber() {
+        return getMainNumber() + "." + getSubNumber();
+    }
+
+    public String getPicList() {
+        return picList;
+    }
+
+    public void setPicList(String picList) {
+        this.picList = picList;
+    }
+
+}

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

@@ -0,0 +1,605 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+
+import org.apache.commons.lang.StringUtils;
+
+import cn.com.qmth.stmms.biz.utils.ScoreItem;
+import cn.com.qmth.stmms.common.annotation.ExcelField;
+
+/**
+ * 针对某次考试的考生信息
+ * 
+ * @author LS
+ * 
+ */
+@Entity
+@Table(name = "eb_exam_student")
+public class ExamStudent implements Serializable {
+
+    protected static final long serialVersionUID = 2944870647483950851L;
+
+    public static final String ANSWER_SPLIT = ",";
+
+    public static final String SPLIT = ";";
+
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    /**
+     * 考试ID
+     */
+    @Column(name = "exam_id")
+    private Integer examId;
+
+    /**
+     * 学校ID
+     */
+    @Column(name = "school_id")
+    private Integer schoolId;
+
+    /**
+     * 学习中心
+     */
+    @Column(name = "campus_name")
+    @ExcelField(title = "学习中心", align = 2, sort = 10)
+    private String campusName;
+
+    /**
+     * 科目代码
+     */
+    @Column(name = "subject_code")
+    @ExcelField(title = "课程代码", align = 2, sort = 20)
+    private String subjectCode;
+
+    /**
+     * 科目名称
+     */
+    @Column(name = "subject_name")
+    @ExcelField(title = "课程名称", align = 2, sort = 30)
+    private String subjectName;
+
+    /**
+     * 准考证号
+     */
+    @Column(name = "exam_number")
+    @ExcelField(title = "准考证号", align = 2, sort = 40)
+    private String examNumber;
+
+    /**
+     * 学号
+     */
+    @Column(name = "student_code")
+    @ExcelField(title = "学号", align = 2, sort = 50)
+    private String studentCode;
+
+    /**
+     * 姓名
+     */
+    @Column(name = "name")
+    @ExcelField(title = "姓名", align = 2, sort = 60)
+    private String name;
+
+    /**
+     * 试卷袋签到表编号
+     */
+    @Column(name = "package_code")
+    @ExcelField(title = "签到表编号", align = 2, sort = 70)
+    private String packageCode;
+
+    /**
+     * 考生考点信息
+     */
+    @Column(name = "exam_site")
+    @ExcelField(title = "考点信息", align = 2, sort = 80)
+    private String examSite;
+
+    /**
+     * 考生考场信息
+     */
+    @Column(name = "exam_room")
+    @ExcelField(title = "考场信息", align = 2, sort = 90)
+    private String examRoom;
+
+    /**
+     * 考生备注信息
+     */
+    @Column(name = "remark")
+    @ExcelField(title = "考生备注信息", align = 2, sort = 100)
+    private String remark;
+
+    /**
+     * 扫描批次编号
+     */
+    @Column(name = "batch_code")
+    private String batchCode;
+
+    /**
+     * 原图数量
+     */
+    @Column(name = "sheet_count")
+    private Integer sheetCount;
+
+    /**
+     * 小图数量
+     */
+    @Column(name = "slice_count")
+    private Integer sliceCount;
+
+    /**
+     * 客观答案
+     */
+    @Column(name = "answers")
+    private String answers;
+
+    /**
+     * 是否已上传
+     */
+    @Column(name = "is_upload")
+    private boolean upload;
+
+    /**
+     * 是否缺考
+     */
+    @Column(name = "is_absent")
+    private boolean absent;
+
+    /**
+     * 是否数据校验异常
+     */
+    @Column(name = "is_exception")
+    private boolean exception;
+
+    /**
+     * 上传时间
+     */
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name = "upload_time")
+    private Date uploadTime;
+
+    /**
+     * 客观总分
+     */
+    @Column(name = "objective_score")
+    private Double objectiveScore;
+
+    /**
+     * 客观题得分明细
+     */
+    @Column(name = "objective_score_list")
+    private String objectiveScoreList;
+
+    /**
+     * 主观总分
+     */
+    @Column(name = "subjective_score")
+    private Double subjectiveScore;
+
+    /**
+     * 主观题得分明细
+     */
+    @Column(name = "subjective_score_list")
+    private String subjectiveScoreList;
+
+    /**
+     * 科目层次信息
+     */
+    @ExcelField(title = "层次", align = 2, sort = 110)
+    @Column(name = "subject_level")
+    private String subjectLevel;
+
+    /**
+     * 专业类型信息
+     */
+    @ExcelField(title = "专业类型", align = 2, sort = 120)
+    @Column(name = "subject_category")
+    private String subjectCategory;
+
+    /**
+     * 科目备注信息
+     */
+    @ExcelField(title = "科目备注信息", align = 2, sort = 130)
+    @Transient
+    private String subjectRemark;
+
+    @Transient
+    private ExamSubject subject;
+
+    @Transient
+    private List<String> sheetUrls;
+
+    @Transient
+    private List<String> packageUrls;
+
+    @Transient
+    private String answerUrl;
+
+    @Transient
+    private String markTime;
+
+    @Transient
+    private Integer libraryId;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getCampusName() {
+        return campusName;
+    }
+
+    public void setCampusName(String campusName) {
+        this.campusName = campusName;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    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 getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public String getAnswers() {
+        return answers;
+    }
+
+    public void setAnswers(String answers) {
+        this.answers = answers;
+    }
+
+    public boolean isUpload() {
+        return upload;
+    }
+
+    public void setUpload(boolean upload) {
+        this.upload = upload;
+    }
+
+    public Date getUploadTime() {
+        return uploadTime;
+    }
+
+    public void setUploadTime(Date uploadTime) {
+        this.uploadTime = uploadTime;
+    }
+
+    public List<String> getAnswerList() {
+        String[] values = StringUtils.split(StringUtils.trimToNull(answers), ANSWER_SPLIT);
+        List<String> list = new ArrayList<String>();
+        if (values != null && values.length > 0) {
+            for (String answer : values) {
+                list.add(StringUtils.trim(answer));
+            }
+        }
+        return list;
+    }
+
+    public Double getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(Double objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
+
+    public Double getSubjectiveScore() {
+        return subjectiveScore;
+    }
+
+    public void setSubjectiveScore(Double subjectiveScore) {
+        this.subjectiveScore = subjectiveScore;
+    }
+
+    public String getObjectiveScoreList() {
+        return objectiveScoreList;
+    }
+
+    public void setObjectiveScoreList(String objectiveScoreList) {
+        this.objectiveScoreList = objectiveScoreList;
+    }
+
+    public String getSubjectiveScoreList() {
+        return subjectiveScoreList;
+    }
+
+    public void setSubjectiveScoreList(String subjectiveScoreList) {
+        this.subjectiveScoreList = subjectiveScoreList;
+    }
+
+    public static String buildScoreList(List<ScoreItem> scoreList) {
+        if (scoreList != null) {
+            return StringUtils.join(scoreList, SPLIT);
+        } else {
+            return null;
+        }
+    }
+
+    public void setScoreList(List<ScoreItem> scoreList, boolean objective) {
+        if (scoreList != null) {
+            if (objective) {
+                setObjectiveScoreList(StringUtils.join(scoreList, SPLIT));
+            } else {
+                setSubjectiveScoreList(StringUtils.join(scoreList, SPLIT));
+            }
+        }
+    }
+
+    public List<ScoreItem> getScoreList(boolean objective) {
+        List<ScoreItem> scoreList = new LinkedList<ScoreItem>();
+        try {
+            String[] values = StringUtils.split(objective ? objectiveScoreList : subjectiveScoreList, SPLIT);
+            for (String value : values) {
+                ScoreItem item = ScoreItem.parse(value, objective);
+                item.setObjective(objective);
+                if (item != null) {
+                    scoreList.add(item);
+                }
+            }
+        } catch (Exception e) {
+        }
+        return scoreList;
+    }
+
+    public List<String> getSheetUrls() {
+        return sheetUrls;
+    }
+
+    public void setSheetUrls(List<String> sheetUrls) {
+        this.sheetUrls = sheetUrls;
+    }
+
+    public boolean isAbsent() {
+        return absent;
+    }
+
+    public void setAbsent(boolean absent) {
+        this.absent = absent;
+    }
+
+    public Integer getSheetCount() {
+        return sheetCount;
+    }
+
+    public void setSheetCount(Integer sheetCount) {
+        this.sheetCount = sheetCount;
+    }
+
+    public Integer getSliceCount() {
+        return sliceCount;
+    }
+
+    public void setSliceCount(Integer sliceCount) {
+        this.sliceCount = sliceCount;
+    }
+
+    public double getTotalScore() {
+        double score = 0;
+        if (objectiveScore != null) {
+            score += objectiveScore;
+        }
+        if (subjectiveScore != null) {
+            score += subjectiveScore;
+        }
+        return score;
+    }
+
+    public Integer getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Integer schoolId) {
+        this.schoolId = schoolId;
+    }
+
+    public String getBatchCode() {
+        return batchCode;
+    }
+
+    public void setBatchCode(String batchCode) {
+        this.batchCode = batchCode;
+    }
+
+    public String getPackageCode() {
+        return packageCode;
+    }
+
+    public void setPackageCode(String packageCode) {
+        this.packageCode = packageCode;
+    }
+
+    public List<String> getPackageUrls() {
+        return packageUrls;
+    }
+
+    public void setPackageUrls(List<String> packageUrls) {
+        this.packageUrls = packageUrls;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public String getMarkTime() {
+        return markTime;
+    }
+
+    public void setMarkTime(String markTime) {
+        this.markTime = markTime;
+    }
+
+    public boolean isException() {
+        return exception;
+    }
+
+    public void setException(boolean exception) {
+        this.exception = exception;
+    }
+
+    public String getObjectiveScoreString() {
+        try {
+            return ScoreItem.NUMBER_FORMAT.format(objectiveScore);
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
+    public String getSubjectiveScoreString() {
+        try {
+            return ScoreItem.NUMBER_FORMAT.format(subjectiveScore);
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
+    public String getTotalScoreString() {
+        try {
+            return ScoreItem.NUMBER_FORMAT.format(getTotalScore());
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
+    public String getSubjectRemark() {
+        return subjectRemark;
+    }
+
+    public void setSubjectRemark(String subjectRemark) {
+        this.subjectRemark = subjectRemark;
+    }
+
+    public String getSheetUrlString() {
+        if (sheetUrls != null) {
+            return StringUtils.join(sheetUrls, ",");
+        } else {
+            return "";
+        }
+    }
+
+    public String getPackageUrlString() {
+        if (packageUrls != null) {
+            return StringUtils.join(packageUrls, ",");
+        } else {
+            return "";
+        }
+    }
+
+    public String getAnswerUrl() {
+        return answerUrl;
+    }
+
+    public void setAnswerUrl(String answerUrl) {
+        this.answerUrl = answerUrl;
+    }
+
+    public String getSubjectLevel() {
+        return subjectLevel;
+    }
+
+    public void setSubjectLevel(String subjectLevel) {
+        this.subjectLevel = subjectLevel;
+    }
+
+    public String getExamSite() {
+        return examSite;
+    }
+
+    public void setExamSite(String examSite) {
+        this.examSite = examSite;
+    }
+
+    public String getExamRoom() {
+        return examRoom;
+    }
+
+    public void setExamRoom(String examRoom) {
+        this.examRoom = examRoom;
+    }
+
+    public String getSubjectCategory() {
+        return subjectCategory;
+    }
+
+    public void setSubjectCategory(String subjectCategory) {
+        this.subjectCategory = subjectCategory;
+    }
+
+    public Integer getLibraryId() {
+        return libraryId;
+    }
+
+    public void setLibraryId(Integer libraryId) {
+        this.libraryId = libraryId;
+    }
+
+    public ExamSubject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(ExamSubject subject) {
+        this.subject = subject;
+    }
+
+}

+ 211 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamSubject.java

@@ -0,0 +1,211 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import org.apache.commons.lang.StringUtils;
+
+import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
+import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
+
+@Entity
+@Table(name = "eb_exam_subject")
+public class ExamSubject implements Serializable {
+
+    private static final long serialVersionUID = -6942849844435873366L;
+
+    @EmbeddedId
+    private ExamSubjectPK pk;
+
+    @Column(name = "name")
+    private String name;
+
+    @Column(name = "level")
+    private String level;
+
+    @Column(name = "category")
+    private String category;
+
+    @Enumerated(EnumType.ORDINAL)
+    @Column(name = "status")
+    private ExamSubjectStatus status;
+
+    @Column(name = "objective_score")
+    private Double objectiveScore;
+
+    @Column(name = "subjective_score")
+    private Double subjectiveScore;
+
+    @Column(name = "total_score")
+    private Double totalScore;
+
+    /**
+     * 上传学生数量
+     */
+    @Column(name = "upload_count")
+    private Integer uploadCount;
+
+    @Column(name = "has_paper")
+    private Boolean hasPaper;
+
+    @Column(name = "has_answer")
+    private Boolean hasAnswer;
+
+    @Column(name = "remark")
+    private String remark;
+
+    /**
+     * 大题数量
+     */
+    @Transient
+    private long groupCount;
+
+    public ExamSubject() {
+        this.pk = new ExamSubjectPK();
+    }
+
+    public Integer getExamId() {
+        return pk.getExamId();
+    }
+
+    public void setExamId(Integer examId) {
+        pk.setExamId(examId);
+    }
+
+    public String getCode() {
+        return pk.getCode();
+    }
+
+    public void setCode(String code) {
+        pk.setCode(code);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public ExamSubjectStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(ExamSubjectStatus status) {
+        this.status = status;
+    }
+
+    public Double getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(Double objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
+
+    public Double getSubjectiveScore() {
+        return subjectiveScore;
+    }
+
+    public void setSubjectiveScore(Double subjectiveScore) {
+        this.subjectiveScore = subjectiveScore;
+    }
+
+    public void setScore(double score, boolean objective) {
+        if (objective) {
+            setObjectiveScore(score);
+        } else {
+            setSubjectiveScore(score);
+        }
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public Boolean getHasPaper() {
+        return hasPaper;
+    }
+
+    public void setHasPaper(Boolean hasPaper) {
+        this.hasPaper = hasPaper;
+    }
+
+    public Boolean getHasAnswer() {
+        return hasAnswer;
+    }
+
+    public void setHasAnswer(Boolean hasAnswer) {
+        this.hasAnswer = hasAnswer;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public String getDisplayName() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(name);
+        if (StringUtils.isNotBlank(remark)) {
+            sb.append("_").append(remark);
+        }
+        return sb.toString();
+    }
+
+    public String getPaperUrl() {
+        return PictureUrlBuilder.getPaperUrl(getExamId(), getCode());
+    }
+
+    public String getAnswerUrl() {
+        return PictureUrlBuilder.getAnswerUrl(getExamId(), getCode());
+    }
+
+    public String getLevel() {
+        return level;
+    }
+
+    public void setLevel(String level) {
+        this.level = level;
+    }
+
+    public String getCategory() {
+        return category;
+    }
+
+    public void setCategory(String category) {
+        this.category = category;
+    }
+
+    public Integer getUploadCount() {
+        return uploadCount;
+    }
+
+    public void setUploadCount(Integer uploadCount) {
+        this.uploadCount = uploadCount;
+    }
+
+    public long getGroupCount() {
+        return groupCount;
+    }
+
+    public void setGroupCount(long groupCount) {
+        this.groupCount = groupCount;
+    }
+
+}

+ 75 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ExamSubjectPK.java

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

+ 231 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroup.java

@@ -0,0 +1,231 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+
+import org.apache.commons.lang.StringUtils;
+
+@Entity
+@Table(name = "eb_mark_group")
+public class MarkGroup implements Serializable {
+
+    private static final long serialVersionUID = 5228601490523811224L;
+
+    public static final String PIC_SPLIT = ",";
+
+    @EmbeddedId
+    private MarkGroupPK pk;
+
+    @Column(name = "title", length = 128, nullable = false)
+    private String title;
+
+    @Column(name = "pic_list", length = 32, nullable = false)
+    private String picList;
+
+    @Column(name = "total_score", nullable = false)
+    private Double totalScore;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column(name = "build_time", nullable = true)
+    private Date buildTime;
+
+    @Column(name = "library_count")
+    private Integer libraryCount;
+
+    @Column(name = "marked_count")
+    private Integer markedCount;
+
+    @Column(name = "left_count")
+    private Integer leftCount;
+
+    @Transient
+    private int currentCount;
+
+    @Transient
+    private String scoreList;
+
+    @Transient
+    private List<ExamQuestion> questionList;
+
+    @Transient
+    private long markerCount;
+
+    public MarkGroup() {
+        this.pk = new MarkGroupPK();
+    }
+
+    public MarkGroup(Integer examId, String subjectCode, Integer number, String title, List<Integer> picList,
+            Double totalScore) {
+        this.pk = new MarkGroupPK();
+        this.pk.setExamId(examId);
+        this.pk.setNumber(number);
+        this.pk.setSubjectCode(subjectCode);
+        this.title = title;
+        this.picList = picList != null && picList.size() > 0 ? StringUtils.join(picList, PIC_SPLIT) : null;
+        this.totalScore = totalScore;
+        this.libraryCount = 0;
+        this.markedCount = 0;
+        this.leftCount = 0;
+    }
+
+    public Integer getExamId() {
+        return pk.getExamId();
+    }
+
+    public void setExamId(Integer examId) {
+        pk.setExamId(examId);
+    }
+
+    public String getSubjectCode() {
+        return pk.getSubjectCode();
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        pk.setSubjectCode(subjectCode);
+    }
+
+    public Integer getNumber() {
+        return pk.getNumber();
+    }
+
+    public void setNumber(Integer number) {
+        pk.setNumber(number);
+    }
+
+    public String getPicList() {
+        return picList;
+    }
+
+    public void setPicList(String picList) {
+        this.picList = picList;
+    }
+
+    public void setPicList(List<Integer> picList) {
+        this.picList = picList != null && picList.size() > 0 ? StringUtils.join(picList, PIC_SPLIT) : null;
+    }
+
+    public List<String> getPicNumbers() {
+        List<String> list = new LinkedList<String>();
+        String[] values = StringUtils.split(StringUtils.trimToNull(picList), PIC_SPLIT);
+        if (values != null && values.length > 0) {
+            for (String pic : values) {
+                list.add(StringUtils.trim(pic));
+            }
+        }
+        return list;
+    }
+
+    public String[] getPicListArray() {
+        List<String> list = getPicNumbers();
+        int length = list.size();
+        String[] array = new String[length];
+        for (int i = 0; i < list.size(); i++) {
+            array[i] = list.get(i);
+        }
+        return array;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public Integer getLibraryCount() {
+        return libraryCount;
+    }
+
+    public void setLibraryCount(Integer libraryCount) {
+        this.libraryCount = libraryCount;
+    }
+
+    public Integer getMarkedCount() {
+        return markedCount;
+    }
+
+    public void setMarkedCount(Integer markedCount) {
+        this.markedCount = markedCount;
+    }
+
+    public Integer getLeftCount() {
+        return leftCount;
+    }
+
+    public void setLeftCount(Integer leftCount) {
+        this.leftCount = leftCount;
+    }
+
+    public String getScoreList() {
+        return scoreList;
+    }
+
+    public void setScoreList(String scoreList) {
+        this.scoreList = scoreList;
+    }
+
+    public void setScoreList(List<ExamQuestion> questionList) {
+        DecimalFormat format = new DecimalFormat("###.#");
+        StringBuilder score = new StringBuilder();
+        for (ExamQuestion question : questionList) {
+            if (score.length() > 0) {
+                score.append(",");
+            }
+            score.append(format.format(question.getTotalScore()));
+        }
+        this.scoreList = score.toString();
+    }
+
+    public long getMarkerCount() {
+        return markerCount;
+    }
+
+    public void setMarkerCount(long markerCount) {
+        this.markerCount = markerCount;
+    }
+
+    public Date getBuildTime() {
+        return buildTime;
+    }
+
+    public void setBuildTime(Date buildTime) {
+        this.buildTime = buildTime;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public List<ExamQuestion> getQuestionList() {
+        return questionList;
+    }
+
+    public void setQuestionList(List<ExamQuestion> questionList) {
+        this.questionList = questionList;
+    }
+
+    public int getCurrentCount() {
+        return currentCount;
+    }
+
+    public void setCurrentCount(int currentCount) {
+        this.currentCount = currentCount;
+    }
+
+}

+ 85 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/MarkGroupPK.java

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

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

@@ -0,0 +1,255 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import org.apache.commons.lang.StringUtils;
+
+import cn.com.qmth.stmms.common.annotation.ExcelField;
+
+@Entity
+@Table(name = "eb_marker")
+public class Marker implements Serializable {
+
+    public static final String LOGINNAME_SPLITE = "-";
+
+    private static final long serialVersionUID = -5728058071677581938L;
+
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    @Column(name = "exam_id")
+    private Integer examId;
+
+    @Column(name = "subject_code")
+    private String subjectCode;
+
+    @Column(name = "group_number")
+    private Integer groupNumber;
+
+    @Column(name = "login_name")
+    @ExcelField(title = "登录名", align = 2, sort = 30)
+    private String loginName;
+
+    @Column(name = "name")
+    private String name;
+
+    @Column(name = "password")
+    @ExcelField(title = "密码", align = 2, sort = 40)
+    private String password;
+
+    @Column(name = "enable")
+    private boolean enable;
+
+    @Column(name = "last_login_ip")
+    private String lastLoginIp;
+
+    @Column(name = "last_login_time")
+    private Date lastLoginTime;
+
+    @Column(name = "mode")
+    private String mode;
+
+    @Transient
+    @ExcelField(title = "科目", align = 2, sort = 10)
+    private String subjectName;
+
+    @Transient
+    @ExcelField(title = "大题", align = 2, sort = 20)
+    private String groupName;
+
+    @Transient
+    private int number;
+
+    @Transient
+    private ExamSubject subject;
+
+    @Transient
+    private MarkGroup group;
+
+    @Transient
+    private long markedCount;
+
+    @Transient
+    private long currentCount;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getLastLoginIp() {
+        return lastLoginIp;
+    }
+
+    public void setLastLoginIp(String lastLoginIp) {
+        this.lastLoginIp = lastLoginIp;
+    }
+
+    public Date getLastLoginTime() {
+        return lastLoginTime;
+    }
+
+    public void setLastLoginTime(Date lastLoginTime) {
+        this.lastLoginTime = lastLoginTime;
+    }
+
+    public String getLoginName() {
+        return loginName;
+    }
+
+    public void setLoginName(String loginName) {
+        this.loginName = loginName;
+    }
+
+    public boolean isEnable() {
+        return enable;
+    }
+
+    public void setEnable(boolean enable) {
+        this.enable = enable;
+    }
+
+    public int getNumber() {
+        return number;
+    }
+
+    public void setNumber(int number) {
+        this.number = number;
+    }
+
+    public void buildLoginName(int number) {
+        StringBuilder name = new StringBuilder();
+        name.append(examId).append(LOGINNAME_SPLITE);
+        name.append(subjectCode).append(LOGINNAME_SPLITE);
+        name.append(number);
+        setLoginName(name.toString());
+    }
+
+    public static Marker parseLoginName(String loginName) {
+        Marker marker = null;
+        try {
+            String[] values = StringUtils.split(loginName, LOGINNAME_SPLITE);
+            marker = new Marker();
+            marker.setExamId(Integer.valueOf(values[0]));
+            if (values.length == 2) {
+                marker.setSubjectCode("");
+                marker.setNumber(Integer.valueOf(values[1]));
+            } else {
+                marker.setSubjectCode(values[1]);
+                marker.setNumber(Integer.valueOf(values[2]));
+            }
+        } catch (Exception e) {
+            marker = null;
+        }
+        return marker;
+    }
+
+    public ExamSubject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(ExamSubject subject) {
+        this.subject = subject;
+    }
+
+    public long getMarkedCount() {
+        return markedCount;
+    }
+
+    public void setMarkedCount(long markedCount) {
+        this.markedCount = markedCount;
+    }
+
+    public long getCurrentCount() {
+        return currentCount;
+    }
+
+    public void setCurrentCount(long currentCount) {
+        this.currentCount = currentCount;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getMode() {
+        return mode;
+    }
+
+    public void setMode(String mode) {
+        this.mode = mode;
+    }
+
+    public Integer getGroupNumber() {
+        return groupNumber;
+    }
+
+    public void setGroupNumber(Integer groupNumber) {
+        this.groupNumber = groupNumber;
+    }
+
+    public String getGroupName() {
+        return groupName;
+    }
+
+    public void setGroupName(String groupName) {
+        this.groupName = groupName;
+    }
+
+    public MarkGroup getGroup() {
+        return group;
+    }
+
+    public void setGroup(MarkGroup group) {
+        this.group = group;
+    }
+
+}

+ 119 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/QuestionPK.java

@@ -0,0 +1,119 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class QuestionPK implements Serializable {
+
+    private static final long serialVersionUID = -4806329348030887113L;
+
+    @Column(name = "exam_id")
+    private Integer examId;
+
+    @Column(name = "subject_code")
+    private String subjectCode;
+
+    @Column(name = "main_number")
+    private Integer mainNumber;
+
+    @Column(name = "sub_number")
+    private Integer subNumber;
+
+    @Column(name = "is_objective")
+    private boolean objective;
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Integer getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public Integer getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(Integer subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public boolean isObjective() {
+        return objective;
+    }
+
+    public void setObjective(boolean objective) {
+        this.objective = objective;
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((examId == null) ? 0 : examId.hashCode());
+        result = PRIME * result + ((subjectCode == null) ? 0 : subjectCode.hashCode());
+        result = PRIME * result + ((mainNumber == null) ? 0 : mainNumber.hashCode());
+        result = PRIME * result + ((subNumber == null) ? 0 : subNumber.hashCode());
+        result = PRIME * result + (objective ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final QuestionPK other = (QuestionPK) obj;
+        if (examId == null) {
+            if (other.examId != null)
+                return false;
+        } else if (!examId.equals(other.examId))
+            return false;
+        if (subjectCode == null) {
+            if (other.subjectCode != null)
+                return false;
+        } else if (!subjectCode.equals(other.subjectCode))
+            return false;
+
+        if (mainNumber == null) {
+            if (other.mainNumber != null)
+                return false;
+        } else if (!mainNumber.equals(other.mainNumber))
+            return false;
+
+        if (subNumber == null) {
+            if (other.subNumber != null)
+                return false;
+        } else if (!subNumber.equals(other.subNumber))
+            return false;
+
+        if (objective != other.objective) {
+            return false;
+        }
+
+        return true;
+    }
+
+}

+ 144 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ScoreRate.java

@@ -0,0 +1,144 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+/**
+ * 统计得分率
+ *
+ */
+@Entity
+@Table(name = "s_score_rate")
+public class ScoreRate  implements Serializable {
+
+	private static final long serialVersionUID = 144070071029754523L;
+
+	@EmbeddedId
+    private ScoreRatePK pk;
+
+    @Column(name = "main_title")
+    private String mainTitle;
+
+    @Column(name = "total_score")
+    private Double totalScore;
+
+    @Column(name = "avg_score")
+    private Double avgScore;
+
+    @Transient
+    private ExamSubject subject;
+    
+    @Transient
+    private double rate;
+
+    public ScoreRate() {
+        this.pk = new ScoreRatePK();
+    }
+
+    public Integer getExamId() {
+        return pk.getExamId();
+    }
+
+    public void setExamId(Integer examId) {
+        pk.setExamId(examId);
+    }
+    
+    public String getCampusName() {
+		return pk.getCampusName();
+	}
+
+	public void setCampusName(String campusName) {
+		pk.setCampusName(campusName);
+	}
+
+    public String getSubjectCode() {
+        return pk.getSubjectCode();
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        pk.setSubjectCode(subjectCode);
+    }
+
+    public Integer getMainNumber() {
+        return pk.getMainNumber();
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        pk.setMainNumber(mainNumber);
+    }
+
+    public Integer getSubNumber() {
+        return pk.getSubNumber();
+    }
+
+    public void setSubNumber(Integer subNumber) {
+        pk.setSubNumber(subNumber);
+    }
+
+    public String getMainTitle() {
+        return mainTitle;
+    }
+
+    public void setObjective(boolean objective) {
+        pk.setObjective(objective);
+    }
+
+    public boolean isObjective() {
+        return pk.isObjective();
+    }
+
+    public void setMainTitle(String mainTitle) {
+        this.mainTitle = mainTitle;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public String getName() {
+        if (mainTitle != null && getSubNumber() != null) {
+            return mainTitle + "-" + getSubNumber();
+        } else {
+            return "";
+        }
+    }
+
+    public ExamSubject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(ExamSubject subject) {
+        this.subject = subject;
+    }
+
+    public String getQuestionNumber() {
+        return getMainNumber() + "-" + getSubNumber();
+    }
+
+	public Double getAvgScore() {
+		return avgScore;
+	}
+
+	public void setAvgScore(Double avgScore) {
+		this.avgScore = avgScore;
+	}
+
+	public double getRate() {
+		return new BigDecimal(getAvgScore()*100.00/getTotalScore()).setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
+	}
+
+	public void setRate(double rate) {
+		this.rate = rate;
+	}
+
+}

+ 136 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/ScoreRatePK.java

@@ -0,0 +1,136 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class ScoreRatePK implements Serializable {
+
+	private static final long serialVersionUID = 2278891125776938996L;
+
+	@Column(name = "exam_id")
+    private Integer examId;
+	
+    @Column(name = "campus_name")
+    private String campusName;
+
+    @Column(name = "subject_code")
+    private String subjectCode;
+
+    @Column(name = "main_number")
+    private Integer mainNumber;
+
+    @Column(name = "sub_number")
+    private Integer subNumber;
+
+    @Column(name = "is_objective")
+    private boolean objective;
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Integer getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public Integer getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(Integer subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public boolean isObjective() {
+        return objective;
+    }
+
+    public void setObjective(boolean objective) {
+        this.objective = objective;
+    }
+
+    public String getCampusName() {
+		return campusName;
+	}
+
+	public void setCampusName(String campusName) {
+		this.campusName = campusName;
+	}
+
+	@Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((examId == null) ? 0 : examId.hashCode());
+        result = PRIME * result + (campusName ==null ? 0 : campusName.hashCode());
+        result = PRIME * result + ((subjectCode == null) ? 0 : subjectCode.hashCode());
+        result = PRIME * result + ((mainNumber == null) ? 0 : mainNumber.hashCode());
+        result = PRIME * result + ((subNumber == null) ? 0 : subNumber.hashCode());
+        result = PRIME * result + (objective ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final ScoreRatePK other = (ScoreRatePK) obj;
+        if (examId == null) {
+            if (other.examId != null)
+                return false;
+        } else if (!examId.equals(other.examId))
+            return false;
+        if (campusName == null) {
+            if (other.campusName != null)
+                return false;
+        } else if (!campusName.equals(other.campusName))
+            return false;
+        if (subjectCode == null) {
+            if (other.subjectCode != null)
+                return false;
+        } else if (!subjectCode.equals(other.subjectCode))
+            return false;
+
+        if (mainNumber == null) {
+            if (other.mainNumber != null)
+                return false;
+        } else if (!mainNumber.equals(other.mainNumber))
+            return false;
+
+        if (subNumber == null) {
+            if (other.subNumber != null)
+                return false;
+        } else if (!subNumber.equals(other.subNumber))
+            return false;
+
+        if (objective != other.objective) {
+            return false;
+        }
+
+        return true;
+    }
+
+}

+ 38 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/Tag.java

@@ -0,0 +1,38 @@
+package cn.com.qmth.stmms.biz.exam.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "b_tag")
+public class Tag implements Serializable {
+
+    private static final long serialVersionUID = -8796053015319816326L;
+
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    private String 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;
+    }
+
+}

+ 37 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/ExamPackageSearchQuery.java

@@ -0,0 +1,37 @@
+package cn.com.qmth.stmms.biz.exam.query;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.exam.model.ExamPackage;
+
+public class ExamPackageSearchQuery extends BaseQuery<ExamPackage> {
+
+    private int examId;
+
+    private String code;
+
+    private Boolean upload;
+
+    public int getExamId() {
+        return examId;
+    }
+
+    public void setExamId(int examId) {
+        this.examId = examId;
+    }
+
+    public Boolean getUpload() {
+        return upload;
+    }
+
+    public void setUpload(Boolean upload) {
+        this.upload = upload;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+}

+ 82 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/ExamSearchQuery.java

@@ -0,0 +1,82 @@
+package cn.com.qmth.stmms.biz.exam.query;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.exam.model.Exam;
+import cn.com.qmth.stmms.common.enums.ExamStatus;
+
+public class ExamSearchQuery extends BaseQuery<Exam> {
+
+    private String name;
+
+    private Integer creatorId;
+
+    private Integer schoolId;
+
+    private Set<ExamStatus> statusSet;
+
+    private Set<Integer> ids;
+
+    private Boolean orderByCreateTimeDesc;
+
+    public Integer getCreatorId() {
+        return creatorId;
+    }
+
+    public void setCreatorId(Integer creatorId) {
+        this.creatorId = creatorId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Set<ExamStatus> getStatusSet() {
+        return statusSet;
+    }
+
+    public void addStatus(ExamStatus status) {
+        if (statusSet == null) {
+            statusSet = new HashSet<ExamStatus>();
+        }
+        if (status != null) {
+            statusSet.add(status);
+        }
+    }
+
+    public Set<Integer> getIds() {
+        return ids;
+    }
+
+    public void addId(Integer id) {
+        if (ids == null) {
+            ids = new HashSet<Integer>();
+        }
+        if (id != null) {
+            ids.add(id);
+        }
+    }
+
+    public Boolean getOrderByCreateTimeDesc() {
+        return orderByCreateTimeDesc;
+    }
+
+    public void setOrderByCreateTimeDesc(Boolean orderByCreateTimeDesc) {
+        this.orderByCreateTimeDesc = orderByCreateTimeDesc;
+    }
+
+    public Integer getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Integer schoolId) {
+        this.schoolId = schoolId;
+    }
+
+}

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

@@ -0,0 +1,287 @@
+package cn.com.qmth.stmms.biz.exam.query;
+
+import java.util.Date;
+
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+
+public class ExamStudentSearchQuery extends BaseQuery<ExamStudent> {
+
+    private Integer examId;
+
+    private String campusName;
+
+    private String name;
+    
+    private String examNumberIn;
+
+    private String examNumber;
+
+    private String studentCode;
+
+    private String subjectCode;
+
+    private String batchCode;
+
+    private String packageCode;
+
+    private String subjectLevel;
+
+    private String subjectCategory;
+
+    private Double objectiveScore;
+
+    private Double objectiveScoreGt;
+    
+    private Double objectiveScoreLt;
+
+    private Double subjectiveScore;
+
+    private Double subjectiveScoreGt;
+    
+    private Double subjectiveScoreLt;
+
+    private Boolean upload;
+
+    private Boolean absent;
+
+    private Boolean exception;
+
+    private Boolean uploadTimeNotNull;
+
+    private Date minUploadTime;
+    
+    private Date maxUploadTime;
+    
+    private String campusNameIn;
+
+    private String subjectCodeIn;
+
+    private String campusNameNotIn;
+
+    private String subjectCodeNotIn;
+
+    public void orderByExamNumber() {
+        setSort(new Sort(Direction.ASC, "examNumber"));
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public String getStudentCode() {
+        return studentCode;
+    }
+
+    public void setStudentCode(String studentCode) {
+        this.studentCode = studentCode;
+    }
+
+    public Boolean getUpload() {
+        return upload;
+    }
+
+    public void setUpload(Boolean upload) {
+        this.upload = upload;
+    }
+
+    public Boolean getAbsent() {
+        return absent;
+    }
+
+    public void setAbsent(Boolean absent) {
+        this.absent = absent;
+    }
+
+    public String getCampusName() {
+        return campusName;
+    }
+
+    public void setCampusName(String campusName) {
+        this.campusName = campusName;
+    }
+
+    public String getBatchCode() {
+        return batchCode;
+    }
+
+    public void setBatchCode(String batchCode) {
+        this.batchCode = batchCode;
+    }
+
+    public String getPackageCode() {
+        return packageCode;
+    }
+
+    public void setPackageCode(String packageCode) {
+        this.packageCode = packageCode;
+    }
+
+    public Boolean getException() {
+        return exception;
+    }
+
+    public void setException(Boolean exception) {
+        this.exception = exception;
+    }
+
+    public Double getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(Double objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
+
+    public Double getObjectiveScoreGt() {
+        return objectiveScoreGt;
+    }
+
+    public void setObjectiveScoreGt(Double objectiveScoreGt) {
+        this.objectiveScoreGt = objectiveScoreGt;
+    }
+
+    public Double getSubjectiveScore() {
+        return subjectiveScore;
+    }
+
+    public void setSubjectiveScore(Double subjectiveScore) {
+        this.subjectiveScore = subjectiveScore;
+    }
+
+    public Double getSubjectiveScoreGt() {
+        return subjectiveScoreGt;
+    }
+
+    public void setSubjectiveScoreGt(Double subjectiveScoreGt) {
+        this.subjectiveScoreGt = subjectiveScoreGt;
+    }
+
+    public String getSubjectLevel() {
+        return subjectLevel;
+    }
+
+    public void setSubjectLevel(String subjectLevel) {
+        this.subjectLevel = subjectLevel;
+    }
+
+    public String getSubjectCategory() {
+        return subjectCategory;
+    }
+
+    public void setSubjectCategory(String subjectCategory) {
+        this.subjectCategory = subjectCategory;
+    }
+
+    public Boolean getUploadTimeNotNull() {
+        return uploadTimeNotNull;
+    }
+
+    public void setUploadTimeNotNull(Boolean uploadTimeNotNull) {
+        this.uploadTimeNotNull = uploadTimeNotNull;
+    }
+
+    public Date getMinUploadTime() {
+        return minUploadTime;
+    }
+
+    public void setMinUploadTime(Date minUploadTime) {
+        this.minUploadTime = minUploadTime;
+    }
+
+	public Date getMaxUploadTime() {
+		return maxUploadTime;
+	}
+
+	public void setMaxUploadTime(Date maxUploadTime) {
+		this.maxUploadTime = maxUploadTime;
+	}
+
+	public String getExamNumberIn() {
+		return examNumberIn;
+	}
+
+	public void setExamNumberIn(String examNumberIn) {
+		this.examNumberIn = examNumberIn;
+	}
+
+	public Double getObjectiveScoreLt() {
+		return objectiveScoreLt;
+	}
+
+	public void setObjectiveScoreLt(Double objectiveScoreLt) {
+		this.objectiveScoreLt = objectiveScoreLt;
+	}
+
+	public Double getSubjectiveScoreLt() {
+		return subjectiveScoreLt;
+	}
+
+	public void setSubjectiveScoreLt(Double subjectiveScoreLt) {
+		this.subjectiveScoreLt = subjectiveScoreLt;
+	}
+
+	public String getCampusNameIn() {
+		return campusNameIn;
+	}
+
+	public void setCampusNameIn(String campusNameIn) {
+		this.campusNameIn = campusNameIn;
+	}
+
+	public String getSubjectCodeIn() {
+		return subjectCodeIn;
+	}
+
+	public void setSubjectCodeIn(String subjectCodeIn) {
+		this.subjectCodeIn = subjectCodeIn;
+	}
+
+	public String getCampusNameNotIn() {
+		return campusNameNotIn;
+	}
+
+	public void setCampusNameNotIn(String campusNameNotIn) {
+		this.campusNameNotIn = campusNameNotIn;
+	}
+
+	public String getSubjectCodeNotIn() {
+		return subjectCodeNotIn;
+	}
+
+	public void setSubjectCodeNotIn(String subjectCodeNotIn) {
+		this.subjectCodeNotIn = subjectCodeNotIn;
+	}
+
+}

+ 59 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/query/MarkerSearchQuery.java

@@ -0,0 +1,59 @@
+package cn.com.qmth.stmms.biz.exam.query;
+
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+
+public class MarkerSearchQuery extends BaseQuery<Marker> {
+
+    private int examId;
+
+    private String subjectCode;
+
+    private String loginName;
+
+    private int groupNumber;
+
+    public void orderByLoginName() {
+        setSort(new Sort(Direction.ASC, "loginName"));
+    }
+
+    public void orderById() {
+        setSort(new Sort(Direction.ASC, "id"));
+    }
+
+    public int getExamId() {
+        return examId;
+    }
+
+    public void setExamId(int examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getLoginName() {
+        return loginName;
+    }
+
+    public void setLoginName(String loginName) {
+        this.loginName = loginName;
+    }
+
+    public int getGroupNumber() {
+        return groupNumber;
+    }
+
+    public void setGroupNumber(int groupNumber) {
+        this.groupNumber = groupNumber;
+    }
+
+}

+ 32 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamPackageService.java

@@ -0,0 +1,32 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamPackage;
+import cn.com.qmth.stmms.biz.exam.query.ExamPackageSearchQuery;
+
+public interface ExamPackageService {
+
+    ExamPackage save(ExamPackage examPackage);
+
+    ExamPackage find(int examId, String code);
+
+    List<ExamPackage> list(int examId);
+
+    List<ExamPackage> list(int examId, boolean upload);
+
+    ExamPackageSearchQuery findByQuery(ExamPackageSearchQuery query);
+
+    void delete(ExamPackage examPackage);
+
+    void deleteByExamId(int examId);
+
+    long count(int examId);
+
+    long count(int examId, boolean upload);
+
+    long countByQuery(ExamPackageSearchQuery query);
+
+    long sumByExam(int examId);
+
+}

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

@@ -0,0 +1,40 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.service.query.ExamQuestionSearchQuery;
+
+public interface ExamQuestionService {
+
+    ExamQuestion save(ExamQuestion question);
+
+    void deleteByExam(int examId);
+
+    void deleteByExamAndSubject(int examId, String subjectCode);
+
+    void deleteByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective);
+
+    void deleteByExamAndSubjectAndObjectiveAndMainNumber(int examId, String subjectCode, boolean objective,
+            int mainNumber);
+
+    ExamQuestion findOne(int examId, String subjectCode, boolean objective, int mainNumber, int subNumber);
+
+    List<ExamQuestion> findByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective);
+
+    List<ExamQuestion> findByExamAndSubjectAndObjectiveAndMainNumber(int examId, String subjectCode, boolean objective,
+            int mainNumber);
+
+    long countByExamAndSubject(int examId, String subjectCode);
+
+    long countByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective);
+
+    ExamQuestionSearchQuery findByQuery(ExamQuestionSearchQuery query);
+
+    long countByQuery(ExamQuestionSearchQuery query);
+
+    void updateMainTitle(int examId, String subjectCode, boolean objective, int mainNumber, String mainTitle);
+
+    double sumScoreByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective);
+
+}

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

@@ -0,0 +1,28 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.Exam;
+import cn.com.qmth.stmms.biz.exam.query.ExamSearchQuery;
+import cn.com.qmth.stmms.common.enums.ExamStatus;
+
+public interface ExamService {
+
+    Exam save(Exam exam);
+
+    Exam findById(Integer id);
+
+    void updateStatus(int id, ExamStatus status);
+
+    void deleteById(Integer id);
+
+    void delete(Exam exam);
+
+    ExamSearchQuery findByQuery(ExamSearchQuery query);
+
+    List<Exam> findByStatus(ExamStatus status);
+
+    List<Exam> findByCreatorAndStatus(Integer id, ExamStatus status);
+
+	List<Exam> findBySchoolId(Integer schoolId);
+}

+ 90 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ExamStudentService.java

@@ -0,0 +1,90 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.Date;
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
+
+public interface ExamStudentService {
+
+    public ExamStudent findById(int id);
+
+    public int batchSave(List<ExamStudent> list);
+
+    public ExamStudent save(ExamStudent student);
+
+    public void deleteById(int id);
+
+    public void delete(ExamStudent student);
+
+    public void deleteByExamId(int examId);
+
+    public ExamStudentSearchQuery findByQuery(ExamStudentSearchQuery query);
+
+    public long countByQuery(final ExamStudentSearchQuery query);
+
+    List<ExamStudent> findByExamId(int examId);
+
+    List<ExamStudent> findByExamIdAndUploadAndAbsent(int examId, boolean upload, boolean absent, int pageNumber,
+            int pageSize);
+
+    ExamStudent findByExamIdAndExamNumber(int examId, String examNumber);
+
+    public long countByExamId(int examId);
+
+    public long countByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    public long countByExamIdAndSubjectCode(int examId, String subjectCode, boolean upload);
+
+    List<String> findDistinctCampusName(int examId);
+
+    ExamStudentSearchQuery findDistinctCampusName(ExamStudentSearchQuery query);
+
+    List<ExamStudent> findByExamIdAndCampusName(int examId, String campusCode, int pageNumber, int pageSize);
+
+    List<String> findDistinctPackageCode(int examId);
+
+    long countByExamIdAndCampusName(int examId, String campusName);
+
+    long countByExamIdAndCampusName(int examId, String campusName, boolean upload);
+
+    long countByExamIdAndSubjectCode(int examId, String subjectCode, boolean upload, boolean absent);
+
+    long countCampusByExam(int examId);
+
+    long countByExamIdAndUpload(int examId, boolean upload);
+
+    void updateSubjectInfo(ExamSubject subject);
+
+    void updateSubjectiveScore(int id, double score, String scoreList);
+
+    void updateException(int id, boolean exception);
+
+    public ExamStudent findBySchoolIdAndSubjectCodeAndStudentCode(Integer schoolId, String subjectCode,
+            String studentCode);
+
+    public ExamStudent findBySchoolIdAndSubjectCodeAndStudentCodeAndRemark(Integer schoolId, String subjectCode,
+            String studentCode, String examSeqCode);
+
+    public ExamStudent findByExamIdAndSubjectCodeAndUploadTimeAfter(int examId, String code, Date date);
+
+    public List<ExamStudent> findByExamIdAndUploadTimeAfter(int examId, Date date);
+
+    public long countByExamIdAndSubjectiveScoreListIsNotNull(Integer examId);
+
+    List<ExamStudent> findUploadedByExamIdAndSubjectCode(int examId, String code);
+
+    ExamStudent findUnLibraryStudent(int examId, String subjectCode, int groupNumber, Date minUploadTime);
+
+    List<Integer> findAbsentLibraryStudent(int examId, String subjectCode);
+
+	public List<Object[]> statisticsByExamIdAndSubjectCode(Integer examId,String subjectCode);
+
+	public List<Object[]> statisticsByExamIdAndSubjectCode(Integer examId,String subjectCode, boolean upload, boolean absent);
+
+	public Long countByExamIdAndSubjectCodeAndCampus(Integer examId, String code,
+			String campusName, boolean upload, boolean absent);
+
+}

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

@@ -0,0 +1,56 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.List;
+import java.util.Set;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.biz.exam.service.query.ExamSubjectSearchQuery;
+import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
+
+public interface ExamSubjectService {
+
+    ExamSubject save(ExamSubject subject);
+
+    ExamSubject find(int examId, String code);
+
+    List<ExamSubject> list(int examId);
+
+    List<ExamSubject> list(int examId, ExamSubjectStatus status);
+
+    List<ExamSubject> list(int examId, Set<ExamSubjectStatus> statusSet);
+
+    void delete(ExamSubject markSubject);
+
+    List<ExamSubject> list(Set<ExamSubjectStatus> statusSet);
+
+    long count(int examId);
+
+    long count(int examId, Set<ExamSubjectStatus> statusSet);
+
+    long count(int examId, ExamSubjectStatus status);
+
+    ExamSubjectSearchQuery findByQuery(ExamSubjectSearchQuery query);
+
+    long countByQuery(ExamSubjectSearchQuery query);
+
+    void changeStatus(int examId, ExamSubjectStatus status);
+
+    void deleteByExamId(int examId);
+
+    List<ExamSubject> list(int examId, int uploadCountGt);
+
+    List<ExamSubject> list(int examId, ExamSubjectStatus status, int uploadCountGt);
+
+    List<String> listLevel(int examId);
+
+    List<String> listCategory(int examId);
+
+    void updateUploadCount(Integer examId);
+
+    void updateUploadCount(Integer examId, String subjectCode);
+
+    void updateTotalScore(int examId);
+
+    void updateScore(int examId, String code);
+
+}

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

@@ -0,0 +1,44 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.Date;
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+
+public interface MarkGroupService {
+
+    MarkGroup save(MarkGroup markGroup);
+
+    void deleteByExam(int examId);
+
+    void deleteByExamAndSubject(int examId, String subjectCode);
+
+    MarkGroup findOne(int examId, String subjectCode, int number);
+
+    long countByExamAndSubject(int examId, String subjectCode);
+
+    List<MarkGroup> findByExam(int examId);
+
+    List<MarkGroup> findByExamAndSubject(int examId, String code);
+
+    long countByExam(int examId);
+
+    void updatePicList(int examId, String subjectCode, int number, List<Integer> picList);
+
+    void updateTitle(int examId, String subjectCode, int number, String title);
+
+    void updateTotalScore(int examId, String subjectCode, int number, Double score);
+
+    void updateBuildTime(int examId, String subjectCode, int number, Date time);
+
+    void updateLibraryCount(int examId, String subjectCode, int number);
+
+    void updateLibraryCount(int examId, String subjectCode);
+
+    void reset(MarkGroup group);
+
+    void delete(MarkGroup group);
+
+    void resetBuildTime(int examId, String subjectCode);
+
+}

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

@@ -0,0 +1,42 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.biz.exam.query.MarkerSearchQuery;
+
+public interface MarkerService {
+
+    Marker save(Marker marker);
+
+    Marker findById(Integer id);
+
+    Marker findByLoginName(String loginName);
+
+    List<Marker> findByExamAndSubjectAndGroup(int examId, String subjectCode, int groupNumber);
+
+    long countByExam(int examId);
+
+    void delete(Marker marker);
+
+    void deleteById(Integer markerId);
+
+    void deleteByExamAndSubject(int examId, String subjectCode);
+
+    void deleteByExam(int examId);
+
+    int batchCreate(ExamSubject subject, int groupNumber, int count, String password);
+
+    MarkerSearchQuery findByQuery(MarkerSearchQuery query);
+
+    List<Marker> getMarkCount(int examId);
+
+    long countByExamAndSubjectAndGroup(int examId, String subjectCode, int number);
+
+    void deleteByGroup(MarkGroup group);
+
+    List<Marker> getMarkCount(int examId, String subjectCode);
+
+}

+ 14 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/service/ScoreRateService.java

@@ -0,0 +1,14 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import cn.com.qmth.stmms.biz.exam.model.ScoreRate;
+import cn.com.qmth.stmms.biz.exam.service.query.ScoreRateSearchQuery;
+
+public interface ScoreRateService {
+
+	ScoreRate save(ScoreRate scoreRate);
+
+	ScoreRate findOne(int examId, String subjectCode,String campusName, boolean objective, int mainNumber, int subNumber);
+
+	ScoreRateSearchQuery findByQuery(ScoreRateSearchQuery query);
+
+}

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

@@ -0,0 +1,19 @@
+package cn.com.qmth.stmms.biz.exam.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.Tag;
+
+/**
+ * 试卷标记基础信息类
+ * 
+ * @author LS
+ * 
+ */
+public interface TagService {
+
+    List<Tag> findAll();
+
+    Tag findById(Integer id);
+
+}

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

@@ -0,0 +1,124 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.ExamPackageDao;
+import cn.com.qmth.stmms.biz.exam.model.ExamPackage;
+import cn.com.qmth.stmms.biz.exam.query.ExamPackageSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.ExamPackageService;
+
+@Service("examPackageService")
+public class ExamPackageServiceImpl extends BaseQueryService<ExamPackage> implements ExamPackageService {
+
+    @Autowired
+    private ExamPackageDao packageDao;
+
+    @Transactional
+    @Override
+    public ExamPackage save(ExamPackage examPackage) {
+        return packageDao.save(examPackage);
+    }
+
+    @Override
+    public ExamPackage find(int examId, String code) {
+        return packageDao.findByExamIdAndCode(examId, code);
+    }
+
+    @Override
+    public List<ExamPackage> list(int examId) {
+        return packageDao.findByExamId(examId);
+    }
+
+    @Override
+    public List<ExamPackage> list(int examId, boolean upload) {
+        if (upload) {
+            return packageDao.findByExamIdAndUpload(examId);
+        } else {
+            return packageDao.findByExamIdAndUnUpload(examId);
+        }
+    }
+
+    @Override
+    public ExamPackageSearchQuery findByQuery(ExamPackageSearchQuery query) {
+        checkQuery(query);
+        Page<ExamPackage> result = packageDao.findAll(buildSpecification(query), query);
+        fillResult(result, query);
+        return query;
+    }
+
+    @Override
+    public long sumByExam(int examId) {
+        return packageDao.sumByExamId(examId);
+    }
+
+    @Override
+    public long count(int examId) {
+        return packageDao.countByExamId(examId);
+    }
+
+    @Override
+    public long count(int examId, boolean upload) {
+        if (upload) {
+            return packageDao.countByExamIdAndUpload(examId);
+        } else {
+            return packageDao.countByExamIdAndUnUpload(examId);
+        }
+    }
+
+    @Override
+    public long countByQuery(ExamPackageSearchQuery query) {
+        return packageDao.count(buildSpecification(query));
+    }
+
+    @Transactional
+    @Override
+    public void delete(ExamPackage examPackage) {
+        packageDao.delete(examPackage);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamId(int examId) {
+        packageDao.deleteByExamId(examId);
+    }
+
+    private Specification<ExamPackage> buildSpecification(final ExamPackageSearchQuery query) {
+        return new Specification<ExamPackage>() {
+
+            @Override
+            public Predicate toPredicate(Root<ExamPackage> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (query.getExamId() > 0) {
+                    predicates.add(cb.equal(root.get("pk").get("examId"), query.getExamId()));
+                }
+                if (StringUtils.isNotEmpty(query.getCode())) {
+                    predicates.add(cb.equal(root.get("pk").get("code"), query.getCode()));
+                }
+                if (query.getUpload() != null) {
+                    if (query.getUpload().booleanValue()) {
+                        predicates.add(cb.greaterThan(root.get("picCount").as(Integer.class), 0));
+                    } else {
+                        predicates.add(cb.equal(root.get("picCount"), 0));
+                    }
+                }
+                return predicates.isEmpty() ? cb.conjunction()
+                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        };
+    }
+
+}

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

@@ -0,0 +1,165 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.ExamQuestionDao;
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.QuestionPK;
+import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
+import cn.com.qmth.stmms.biz.exam.service.query.ExamQuestionSearchQuery;
+
+@Service
+public class ExamQuestionServiceImpl extends BaseQueryService<ExamQuestion> implements ExamQuestionService {
+
+    @Autowired
+    private ExamQuestionDao questionDao;
+
+    @Transactional
+    @Override
+    public ExamQuestion save(ExamQuestion question) {
+        return questionDao.saveAndFlush(question);
+    }
+
+    @Transactional
+    @Override
+    public void updateMainTitle(int examId, String subjectCode, boolean objective, int mainNumber, String mainTitle) {
+        questionDao.updateMainTitleByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective,
+                mainNumber, mainTitle);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExam(int examId) {
+        questionDao.deleteByExamId(examId);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamAndSubject(int examId, String subjectCode) {
+        questionDao.deleteByExamIdAndSubjectCode(examId, subjectCode);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective) {
+        questionDao.deleteByExamIdAndSubjectCodeAndObjective(examId, subjectCode, objective);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamAndSubjectAndObjectiveAndMainNumber(int examId, String subjectCode, boolean objective,
+            int mainNumber) {
+        questionDao.deleteByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective, mainNumber);
+    }
+
+    @Override
+    public ExamQuestion findOne(int examId, String subjectCode, boolean objective, int mainNumber, int subNumber) {
+        QuestionPK pk = new QuestionPK();
+        pk.setExamId(examId);
+        pk.setSubjectCode(subjectCode);
+        pk.setMainNumber(mainNumber);
+        pk.setSubNumber(subNumber);
+        pk.setObjective(objective);
+        return questionDao.findOne(pk);
+    }
+
+    @Override
+    public List<ExamQuestion> findByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective) {
+        return questionDao.findByExamIdAndSubjectCodeAndObjective(examId, subjectCode, objective);
+    }
+
+    @Override
+    public List<ExamQuestion> findByExamAndSubjectAndObjectiveAndMainNumber(int examId, String subjectCode,
+            boolean objective, int mainNumber) {
+        return questionDao.findByExamIdAndSubjectCodeAndObjectiveAndMainNumber(examId, subjectCode, objective,
+                mainNumber);
+    }
+
+    @Override
+    public long countByExamAndSubject(int examId, String subjectCode) {
+        ExamQuestionSearchQuery query = new ExamQuestionSearchQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        return countByQuery(query);
+    }
+
+    @Override
+    public long countByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective) {
+        ExamQuestionSearchQuery query = new ExamQuestionSearchQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        query.setObjective(objective);
+        return countByQuery(query);
+    }
+
+    @Override
+    public double sumScoreByExamAndSubjectAndObjective(int examId, String subjectCode, boolean objective) {
+        long count = countByExamAndSubjectAndObjective(examId, subjectCode, objective);
+        if (count > 0) {
+            Double score = questionDao.sumScoreByExamIdAndSubjectCodeAndObjective(examId, subjectCode, objective);
+            return score != null ? score.doubleValue() : 0;
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public ExamQuestionSearchQuery findByQuery(ExamQuestionSearchQuery query) {
+        checkQuery(query);
+        Page<ExamQuestion> result = questionDao.findAll(buildSpecification(query), query);
+        fillResult(result, query);
+        return query;
+    }
+
+    @Override
+    public long countByQuery(ExamQuestionSearchQuery query) {
+        return questionDao.count(buildSpecification(query));
+    }
+
+    private Specification<ExamQuestion> buildSpecification(final ExamQuestionSearchQuery query) {
+        return new Specification<ExamQuestion>() {
+
+            @Override
+            public Predicate toPredicate(Root<ExamQuestion> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (query.getExamId() > 0) {
+                    predicates.add(cb.equal(root.get("pk").get("examId"), query.getExamId()));
+                }
+                if (StringUtils.isNotEmpty(query.getSubjectCode())) {
+                    predicates.add(cb.equal(root.get("pk").get("subjectCode"), query.getSubjectCode()));
+                }
+                if (query.getObjective() != null) {
+                    predicates.add(cb.equal(root.get("pk").get("objective"), query.getObjective()));
+                }
+                if (query.getTotalCountGt() != null) {
+                    predicates.add(cb.gt(root.get("totalCount").as(Integer.class), query.getTotalCountGt()));
+                }
+                if (query.getTotalScoreGt() != null) {
+                    predicates.add(cb.gt(root.get("totalScore").as(Double.class), query.getTotalScoreGt()));
+                }
+                if (query.getZeroRateGt() != null) {
+                    predicates.add(cb.ge(root.get("zeroCount").as(Integer.class),
+                            cb.prod(root.get("totalCount").as(Integer.class), query.getZeroRateGt())));
+                }
+                return predicates.isEmpty() ? cb.conjunction()
+                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        };
+    }
+
+}

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

@@ -0,0 +1,139 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.ExamDao;
+import cn.com.qmth.stmms.biz.exam.model.Exam;
+import cn.com.qmth.stmms.biz.exam.query.ExamSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.ExamService;
+import cn.com.qmth.stmms.common.enums.ExamStatus;
+
+@Service
+public class ExamServiceImpl extends BaseQueryService<Exam> implements ExamService {
+
+    @Autowired
+    private ExamDao examDao;
+
+    @Transactional
+    // @CachePut(value = "exam_cache", key = "#exam.id", condition =
+    // "#exam!=null && #exam.id!=null")
+    public Exam save(Exam exam) {
+        Integer id = exam.getId();
+        if (id != null) {
+            exam.setUpdateTime(new Date());
+        } else {
+            exam.setCreateTime(new Date());
+        }
+        return examDao.save(exam);
+    }
+
+    // @Cacheable(value = "exam_cache", key = "#id", condition = "#id!=null")
+    public Exam findById(Integer id) {
+        return examDao.findOne(id);
+    }
+
+    @Transactional
+    // @CacheEvict(value = "exam_cache", beforeInvocation = true, allEntries =
+    // true)
+    public void updateStatus(int id, ExamStatus status) {
+        examDao.updateStatus(id, status);
+    }
+
+    @Transactional
+    // @CacheEvict(value = "exam_cache", beforeInvocation = true, allEntries =
+    // true)
+    public void deleteById(Integer id) {
+        examDao.delete(id);
+    }
+
+    @Override
+    // @CacheEvict(value = "exam_cache", beforeInvocation = true, allEntries =
+    // true)
+    public void delete(Exam exam) {
+        examDao.delete(exam);
+    }
+
+    @Override
+    public ExamSearchQuery findByQuery(final ExamSearchQuery query) {
+        checkQuery(query);
+        if (query.getOrderByCreateTimeDesc() != null) {
+            query.setSort(new Sort(query.getOrderByCreateTimeDesc() ? Direction.DESC : Direction.ASC, "createTime"));
+        }
+
+        Page<Exam> result = examDao.findAll(new Specification<Exam>() {
+
+            @Override
+            public Predicate toPredicate(Root<Exam> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+
+                if (query.getSchoolId() != null) {
+                    predicates.add(cb.equal(root.get("schoolId"), query.getSchoolId()));
+                }
+                if (query.getCreatorId() != null) {
+                    predicates.add(cb.equal(root.get("creatorId"), query.getCreatorId()));
+                }
+                if (StringUtils.isNotBlank(query.getName())) {
+                    predicates.add(cb.like(root.get("name").as(String.class), query.getName() + "%"));
+                }
+
+                if (query.getStatusSet() != null && query.getStatusSet().size() > 0) {
+                    List<Predicate> statusPredicates = new LinkedList<Predicate>();
+                    for (ExamStatus status : query.getStatusSet()) {
+                        statusPredicates.add(cb.equal(root.get("status"), status));
+                    }
+                    if (!statusPredicates.isEmpty()) {
+                        predicates.add(cb.or(statusPredicates.toArray(new Predicate[statusPredicates.size()])));
+                    }
+                }
+
+                if (query.getIds() != null && query.getIds().size() > 0) {
+                    List<Predicate> idsPredicates = new LinkedList<Predicate>();
+                    for (Integer id : query.getIds()) {
+                        idsPredicates.add(cb.equal(root.get("id"), id));
+                    }
+                    if (!idsPredicates.isEmpty()) {
+                        predicates.add(cb.or(idsPredicates.toArray(new Predicate[idsPredicates.size()])));
+                    }
+                }
+
+                return predicates.isEmpty() ? cb.conjunction()
+                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        }, query);
+        fillResult(result, query);
+        return query;
+    }
+
+    @Override
+    public List<Exam> findByStatus(ExamStatus status) {
+        return examDao.findByStatus(status);
+    }
+
+    @Override
+    public List<Exam> findByCreatorAndStatus(Integer id, ExamStatus status) {
+        return examDao.findByCreatorAndStatus(id, status);
+    }
+
+    @Override
+    public List<Exam> findBySchoolId(Integer schoolId) {
+        return examDao.findBySchoolIdOrderByIdDesc(schoolId);
+    }
+
+}

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

@@ -0,0 +1,574 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.campus.model.Campus;
+import cn.com.qmth.stmms.biz.campus.service.CampusService;
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.ExamStudentDao;
+import cn.com.qmth.stmms.biz.exam.model.Exam;
+import cn.com.qmth.stmms.biz.exam.model.ExamPackage;
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.biz.exam.query.ExamStudentSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.ExamPackageService;
+import cn.com.qmth.stmms.biz.exam.service.ExamService;
+import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
+import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
+import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
+
+@Service
+public class ExamStudentServiceImpl extends BaseQueryService<ExamStudent> implements ExamStudentService {
+
+    @Autowired
+    private ExamStudentDao studentDao;
+
+    @Autowired
+    private CampusService campusService;
+
+    @Autowired
+    private ExamPackageService packageService;
+
+    @Autowired
+    private ExamSubjectService subjectService;
+
+    @Autowired
+    private ExamService examService;
+
+    public static final String LOGINNAME_SPLITE = "-";
+
+    public static final String USER_PASSWORD = "123456";
+
+    public ExamStudent findById(int id) {
+        return studentDao.findOne(id);
+    }
+
+    /**
+     * 批量添加考生
+     * 
+     * @param list
+     * @return
+     */
+    @Transactional
+    public int batchSave(List<ExamStudent> list) {
+        if (list == null || list.isEmpty()) {
+            return 0;
+        }
+        int success = 0;
+        int examId = list.get(0).getExamId();
+        int schoolId = list.get(0).getSchoolId();
+        Map<String, ExamSubject> subjectMap = new HashMap<String, ExamSubject>();
+        Set<String> campusSet = new HashSet<String>();
+        Set<String> packageSet = new HashSet<String>();
+
+        for (ExamStudent student : list) {
+            if (!subjectMap.containsKey(student.getSubjectCode())) {
+                ExamSubject subject = new ExamSubject();
+                subject.setCode(student.getSubjectCode());
+                subject.setName(student.getSubjectName());
+                subject.setLevel(StringUtils.trimToNull(student.getSubjectLevel()));
+                subject.setCategory(StringUtils.trimToNull(student.getSubjectCategory()));
+                subject.setRemark(StringUtils.trimToNull(student.getSubjectRemark()));
+                subjectMap.put(subject.getCode(), subject);
+            }
+            campusSet.add(student.getCampusName());
+            if (StringUtils.isNotBlank(student.getPackageCode())) {
+                packageSet.add(student.getPackageCode());
+            }
+            success++;
+        }
+
+        for (ExamSubject es : subjectMap.values()) {
+            ExamSubject subject = subjectService.find(examId, es.getCode());
+            if (subject == null) {
+                subject = new ExamSubject();
+                subject.setExamId(examId);
+                subject.setCode(es.getCode());
+                subject.setName(es.getName());
+                subject.setLevel(es.getLevel());
+                subject.setCategory(es.getCategory());
+                subject.setStatus(ExamSubjectStatus.MARKING);
+                subject.setObjectiveScore(0d);
+                subject.setSubjectiveScore(0d);
+                subject.setTotalScore(0d);
+                subject.setUploadCount(0);
+                subject.setHasAnswer(false);
+                subject.setHasPaper(false);
+                subject.setRemark(es.getRemark());
+                subjectService.save(subject);
+            } else {
+                es.setName(subject.getName());
+                es.setLevel(subject.getLevel());
+                es.setCategory(subject.getCategory());
+            }
+        }
+
+        for (String name : campusSet) {
+            Campus campus = campusService.findBySchoolAndName(schoolId, name);
+            if (campus == null) {
+                campus = new Campus();
+                campus.setSchoolId(schoolId);
+                campus.setName(name);
+                campusService.save(campus);
+            }
+        }
+
+        for (String code : packageSet) {
+            ExamPackage examPackage = packageService.find(examId, code);
+            if (examPackage == null) {
+                examPackage = new ExamPackage();
+                examPackage.setExamId(examId);
+                examPackage.setCode(code);
+                examPackage.setPicCount(0);
+                packageService.save(examPackage);
+            }
+        }
+
+        for (ExamStudent student : list) {
+            ExamSubject subject = subjectMap.get(student.getSubjectCode());
+            student.setSubjectName(subject.getName());
+            student.setSubjectLevel(subject.getLevel());
+            student.setSubjectCategory(subject.getCategory());
+        }
+        studentDao.save(list);
+        return success;
+    }
+
+    @Transactional
+    public ExamStudent save(ExamStudent student) {
+        ExamSubject subject = subjectService.find(student.getExamId(), student.getSubjectCode());
+        if (subject == null) {
+            subject = new ExamSubject();
+            subject.setExamId(student.getExamId());
+            subject.setCode(student.getSubjectCode());
+            subject.setName(student.getSubjectName());
+            subject.setLevel(StringUtils.trimToNull(student.getSubjectLevel()));
+            subject.setCategory(StringUtils.trimToNull(student.getSubjectCategory()));
+            subject.setStatus(ExamSubjectStatus.MARKING);
+            subject.setObjectiveScore(0d);
+            subject.setSubjectiveScore(0d);
+            subject.setTotalScore(0d);
+            subject.setUploadCount(0);
+            subject.setHasAnswer(false);
+            subject.setHasPaper(false);
+            subject.setRemark(StringUtils.trimToNull(student.getSubjectRemark()));
+            subjectService.save(subject);
+        } else {
+            student.setSubjectName(subject.getName());
+            student.setSubjectLevel(subject.getLevel());
+            student.setSubjectCategory(subject.getCategory());
+        }
+
+        Campus campus = campusService.findBySchoolAndName(student.getSchoolId(), student.getCampusName());
+        if (campus == null) {
+            campus = new Campus();
+            campus.setSchoolId(student.getSchoolId());
+            campus.setName(student.getCampusName());
+            campusService.save(campus);
+        }
+
+        if (StringUtils.isNotBlank(student.getPackageCode())) {
+            ExamPackage examPackage = packageService.find(student.getExamId(), student.getPackageCode());
+            if (examPackage == null) {
+                examPackage = new ExamPackage();
+                examPackage.setExamId(student.getExamId());
+                examPackage.setCode(student.getPackageCode());
+                examPackage.setPicCount(0);
+                packageService.save(examPackage);
+            }
+        }
+        return studentDao.save(student);
+    }
+
+    @Transactional
+    public void deleteById(int id) {
+        ExamStudent student = findById(id);
+        if (student != null) {
+            delete(student);
+        }
+    }
+
+    @Transactional
+    public void delete(ExamStudent student) {
+        studentDao.delete(student);
+    }
+
+    @Transactional
+    public void deleteByExamId(int examId) {
+        studentDao.deleteByExamId(examId);
+    }
+
+    public ExamStudentSearchQuery findByQuery(final ExamStudentSearchQuery query) {
+        checkQuery(query);
+        Page<ExamStudent> result = studentDao.findAll(buildSpecification(query), query);
+        fillResult(result, query);
+        return query;
+    }
+
+    public long countByQuery(final ExamStudentSearchQuery query) {
+        return studentDao.count(buildSpecification(query));
+    }
+
+    @Override
+    public List<ExamStudent> findByExamId(int examId) {
+        return studentDao.findByExamId(examId, null);
+    }
+
+    @Override
+    public List<ExamStudent> findByExamIdAndUploadAndAbsent(int examId, boolean upload, boolean absent, int pageNumber,
+            int pageSize) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setPageNumber(pageNumber);
+        query.setPageSize(pageSize);
+        return studentDao.findByExamIdAndUploadAndAbsent(examId, upload, absent, query);
+    }
+
+    @Override
+    public List<ExamStudent> findByExamIdAndCampusName(int examId, String campusName, int pageNumber, int pageSize) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setPageNumber(pageNumber);
+        query.setPageSize(pageSize);
+        return studentDao.findByExamIdAndCampusName(examId, campusName, query);
+    }
+
+    @Override
+    public ExamStudent findByExamIdAndExamNumber(int examId, String examNumber) {
+        List<ExamStudent> list = studentDao.findByExamIdAndExamNumber(examId, examNumber);
+        return list != null && list.size() > 0 ? list.get(0) : null;
+    }
+
+    public long countByExamId(int examId) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setExamId(examId);
+        return countByQuery(query);
+    }
+
+    @Override
+    public long countByExamIdAndUpload(int examId, boolean upload) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setExamId(examId);
+        query.setUpload(upload);
+        return countByQuery(query);
+    }
+
+    public long countByExamIdAndSubjectCode(int examId, String subjectCode) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        return countByQuery(query);
+    }
+
+    public long countByExamIdAndSubjectCode(int examId, String subjectCode, boolean upload) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        query.setUpload(upload);
+        return countByQuery(query);
+    }
+
+    public long countByExamIdAndSubjectCode(int examId, String subjectCode, boolean upload, boolean absent) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        query.setUpload(upload);
+        query.setAbsent(absent);
+        return countByQuery(query);
+    }
+
+    @Override
+    public long countByExamIdAndCampusName(int examId, String campusName) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setExamId(examId);
+        query.setCampusName(campusName);
+        return countByQuery(query);
+    }
+
+    @Override
+    public long countByExamIdAndCampusName(int examId, String campusName, boolean upload) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setExamId(examId);
+        query.setCampusName(campusName);
+        query.setUpload(upload);
+        return countByQuery(query);
+    }
+
+    @Override
+    public long countCampusByExam(int examId) {
+        return studentDao.countCampusNameByExamId(examId);
+    }
+
+    @Override
+    public List<String> findDistinctCampusName(int examId) {
+        return studentDao.findDistinctCampusName(examId);
+    }
+
+    @Override
+    public ExamStudentSearchQuery findDistinctCampusName(ExamStudentSearchQuery query) {
+        checkQuery(query);
+        query.setResult(studentDao.findDistinctCampusName(query.getExamId(), query));
+        query.setCurrentCount(query.getResult().size());
+        query.setTotalCount(studentDao.countDistinctCampusName(query.getExamId()));
+        query.setTotalPage((int) query.getTotalCount() / query.getPageSize());
+        return query;
+    }
+
+    @Override
+    public List<String> findDistinctPackageCode(int examId) {
+        return studentDao.findDistinctPackageCode(examId);
+    }
+
+    @Override
+    @Transactional
+    public void updateSubjectInfo(ExamSubject subject) {
+        if (subject != null) {
+            studentDao.updateSubjectInfo(subject.getExamId(), subject.getCode(), subject.getName(), subject.getLevel(),
+                    subject.getCategory());
+        }
+    }
+
+    @Override
+    @Transactional
+    public void updateSubjectiveScore(int id, double score, String scoreList) {
+        studentDao.updateSubjectiveScore(id, score, scoreList);
+    }
+
+    @Override
+    @Transactional
+    public void updateException(int id, boolean exception) {
+        studentDao.updateException(id, exception);
+    }
+
+    private Specification<ExamStudent> buildSpecification(final ExamStudentSearchQuery query) {
+        return new Specification<ExamStudent>() {
+
+            @Override
+            public Predicate toPredicate(Root<ExamStudent> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (query.getExamId() > 0) {
+                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
+                }
+                if (StringUtils.isNotBlank(query.getExamNumber())) {
+                    predicates.add(cb.equal(root.get("examNumber"), query.getExamNumber()));
+                } else if (StringUtils.isNotBlank(query.getExamNumberIn())) {
+                    String[] list = query.getExamNumberIn().split(",");
+                    if (list.length > 0) {
+                        Predicate[] sub = new Predicate[list.length];
+                        for (int i = 0; i < list.length; i++) {
+                            sub[i] = cb.equal(root.get("examNumber"), list[i]);
+                        }
+                        predicates.add(cb.or(sub));
+                    }
+                }
+                if (StringUtils.isNotEmpty(query.getStudentCode())) {
+                    predicates.add(cb.equal(root.get("studentCode"), query.getStudentCode()));
+                }
+                if (StringUtils.isNotBlank(query.getSubjectCode())) {
+                    predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
+                }
+                if (StringUtils.isNotBlank(query.getCampusName())) {
+                    predicates.add(cb.equal(root.get("campusName"), query.getCampusName()));
+                }
+                if (StringUtils.isNotBlank(query.getName())) {
+                    predicates.add(cb.like(root.get("name").as(String.class), query.getName() + "%"));
+                }
+                if (StringUtils.isNotBlank(query.getBatchCode())) {
+                    predicates.add(cb.equal(root.get("batchCode"), query.getBatchCode()));
+                }
+                if (StringUtils.isNotBlank(query.getPackageCode())) {
+                    predicates.add(cb.equal(root.get("packageCode"), query.getPackageCode()));
+                }
+                if (StringUtils.isNotBlank(query.getSubjectLevel())) {
+                    predicates.add(cb.equal(root.get("subjectLevel"), query.getSubjectLevel()));
+                }
+                if (StringUtils.isNotBlank(query.getSubjectCategory())) {
+                    predicates.add(cb.equal(root.get("subjectCategory"), query.getSubjectCategory()));
+                }
+                if (query.getObjectiveScore() != null) {
+                    predicates.add(cb.equal(root.get("objectiveScore"), query.getObjectiveScore()));
+                } else if (query.getObjectiveScoreGt() != null) {
+                    predicates.add(
+                            cb.greaterThan(root.get("objectiveScore").as(Double.class), query.getObjectiveScoreGt()));
+                } else if (query.getObjectiveScoreLt() != null) {
+                    predicates
+                            .add(cb.lessThan(root.get("objectiveScore").as(Double.class), query.getObjectiveScoreLt()));
+                }
+                if (query.getSubjectiveScore() != null) {
+                    predicates.add(cb.equal(root.get("subjectiveScore"), query.getSubjectiveScore()));
+                } else if (query.getSubjectiveScoreGt() != null) {
+                    predicates.add(
+                            cb.greaterThan(root.get("subjectiveScore").as(Double.class), query.getSubjectiveScoreGt()));
+                } else if (query.getSubjectiveScoreLt() != null) {
+                    predicates.add(
+                            cb.lessThan(root.get("subjectiveScore").as(Double.class), query.getSubjectiveScoreLt()));
+                }
+                if (query.getUpload() != null) {
+                    predicates.add(cb.equal(root.get("upload"), query.getUpload()));
+                }
+                if (query.getAbsent() != null) {
+                    predicates.add(cb.equal(root.get("absent"), query.getAbsent()));
+                }
+                if (query.getException() != null) {
+                    predicates.add(cb.equal(root.get("exception"), query.getException()));
+                }
+                if (query.getUploadTimeNotNull() != null) {
+                    predicates.add(cb.isNotNull(root.get("uploadTime")));
+                }
+                if (query.getMinUploadTime() != null) {
+                    predicates.add(cb.greaterThan(root.get("uploadTime").as(Date.class), query.getMinUploadTime()));
+                }
+                if (query.getMaxUploadTime() != null) {
+                    predicates.add(cb.lessThan(root.get("uploadTime").as(Date.class), query.getMaxUploadTime()));
+                }
+                if (StringUtils.isNotBlank(query.getSubjectCodeIn())) {
+                    String[] list = query.getSubjectCodeIn().split(",");
+                    if (list.length > 0) {
+                        Predicate[] sub = new Predicate[list.length];
+                        for (int i = 0; i < list.length; i++) {
+                            sub[i] = cb.equal(root.get("subjectCode"), list[i]);
+                        }
+                        predicates.add(cb.or(sub));
+                    }
+                }
+                if (StringUtils.isNotBlank(query.getCampusNameIn())) {
+                    String[] list = query.getCampusNameIn().split(",");
+                    if (list.length > 0) {
+                        Predicate[] sub = new Predicate[list.length];
+                        for (int i = 0; i < list.length; i++) {
+                            sub[i] = cb.equal(root.get("campusName"), list[i]);
+                        }
+                        predicates.add(cb.or(sub));
+                    }
+                }
+                if (StringUtils.isNotBlank(query.getSubjectCodeNotIn())) {
+                    String[] list = query.getSubjectCodeNotIn().split(",");
+                    if (list.length > 0) {
+                        Predicate[] sub = new Predicate[list.length];
+                        for (int i = 0; i < list.length; i++) {
+                            sub[i] = cb.notEqual(root.get("subjectCode"), list[i]);
+                        }
+                        predicates.add(cb.and(sub));
+                    }
+                }
+                if (StringUtils.isNotBlank(query.getCampusNameNotIn())) {
+                    String[] list = query.getCampusNameNotIn().split(",");
+                    if (list.length > 0) {
+                        Predicate[] sub = new Predicate[list.length];
+                        for (int i = 0; i < list.length; i++) {
+                            sub[i] = cb.notEqual(root.get("campusName"), list[i]);
+                        }
+                        predicates.add(cb.and(sub));
+                    }
+                }
+                return predicates.isEmpty() ? cb.conjunction()
+                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        };
+    }
+
+    @Override
+    public ExamStudent findBySchoolIdAndSubjectCodeAndStudentCode(Integer schoolId, String subjectCode,
+            String studentCode) {
+        List<Exam> exams = examService.findBySchoolId(schoolId);
+        if (exams != null && exams.size() > 0) {
+            return studentDao.findByExamIdAndSubjectCodeAndStudentCode(exams.get(0).getId(), subjectCode, studentCode);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public ExamStudent findBySchoolIdAndSubjectCodeAndStudentCodeAndRemark(Integer schoolId, String subjectCode,
+            String studentCode, String examSeqCode) {
+        return studentDao.findBySchoolIdAndSubjectCodeAndStudentCodeAndRemark(schoolId, subjectCode, studentCode,
+                examSeqCode);
+    }
+
+    @Override
+    public List<ExamStudent> findByExamIdAndUploadTimeAfter(int examId, Date date) {
+        return studentDao.findByExamIdAndUploadTimeAfter(examId, date);
+    }
+
+    @Override
+    public List<ExamStudent> findUploadedByExamIdAndSubjectCode(int examId, String code) {
+        return studentDao.findByExamIdAndSubjectCodeAndUploadTimeNotNull(examId, code);
+    }
+
+    @Override
+    public ExamStudent findByExamIdAndSubjectCodeAndUploadTimeAfter(int examId, String code, Date date) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(code);
+        query.setMinUploadTime(date);
+        query.setUploadTimeNotNull(true);
+        query.setPageNumber(1);
+        query.setPageSize(1);
+        query.setSort(new Sort(Direction.ASC, "uploadTime"));
+        query = findByQuery(query);
+        return query.getCurrentCount() > 0 ? query.getResult().get(0) : null;
+    }
+
+    @Override
+    public ExamStudent findUnLibraryStudent(int examId, String subjectCode, int groupNumber, Date minUploadTime) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setPageNumber(1);
+        query.setPageSize(1);
+        query.setSort(new Sort(Direction.ASC, "uploadTime"));
+        List<ExamStudent> list = minUploadTime != null
+                ? studentDao.findUnLibraryStudent(examId, subjectCode, groupNumber, minUploadTime, query)
+                : studentDao.findUnLibraryStudent(examId, subjectCode, groupNumber, query);
+        return list.isEmpty() ? null : list.get(0);
+    }
+
+    @Override
+    public List<Integer> findAbsentLibraryStudent(int examId, String subjectCode) {
+        return studentDao.findAbsentLibraryStudent(examId, subjectCode);
+    }
+
+    @Override
+    public long countByExamIdAndSubjectiveScoreListIsNotNull(Integer examId) {
+        return studentDao.countByExamIdAndSubjectiveScoreListNotNull(examId);
+    }
+
+	@Override
+	public List<Object[]> statisticsByExamIdAndSubjectCode(Integer examId,String subjectCode) {
+		return studentDao.statisticsByExamIdAndSubjectCode(examId,subjectCode);
+	}
+
+	@Override
+	public List<Object[]> statisticsByExamIdAndSubjectCode(Integer examId,String subjectCode, boolean upload, boolean absent) {
+		return studentDao.statisticsByExamIdAndSubjectCode(examId,subjectCode,upload,absent);
+	}
+
+	@Override
+	public Long countByExamIdAndSubjectCodeAndCampus(Integer examId,
+			String subjectCode, String campusName, boolean upload, boolean absent) {
+        ExamStudentSearchQuery query = new ExamStudentSearchQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        query.setCampusName(campusName);
+        query.setUpload(upload);
+        query.setAbsent(absent);
+        return countByQuery(query);
+	}
+
+}

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

@@ -0,0 +1,240 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.ExamSubjectDao;
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
+import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
+import cn.com.qmth.stmms.biz.exam.service.query.ExamSubjectSearchQuery;
+import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
+
+@Service("examSubjectService")
+public class ExamSubjectServiceImpl extends BaseQueryService<ExamSubject> implements ExamSubjectService {
+
+    @Autowired
+    private ExamSubjectDao subjectDao;
+
+    @Autowired
+    private ExamQuestionService questionService;
+
+    @Transactional
+    @Override
+    // @CachePut(value = "exam_subject_cache", key =
+    // "T(String).valueOf(#subject.examId)+'-'+#subject.code", condition =
+    // "#subject!=null && #subject.examId!=null && #subject.code!=null")
+    public ExamSubject save(ExamSubject subject) {
+        return subjectDao.save(subject);
+    }
+
+    @Override
+    // @Cacheable(value = "exam_subject_cache", key =
+    // "T(String).valueOf(#examId)+'-'+#code", condition =
+    // "#examId>0 && #code!=null")
+    public ExamSubject find(int examId, String code) {
+        return subjectDao.findByExamIdAndCode(examId, code);
+    }
+
+    @Override
+    public List<ExamSubject> list(int examId) {
+        return subjectDao.findByExamId(examId);
+    }
+
+    @Override
+    public List<String> listLevel(int examId) {
+        return subjectDao.findDistinctLevel(examId);
+    }
+
+    @Override
+    public List<String> listCategory(int examId) {
+        return subjectDao.findDistinctCategory(examId);
+    }
+
+    @Override
+    public List<ExamSubject> list(int examId, int uploadCountGt) {
+        return subjectDao.findByExamIdAndUploadCountGt(examId, uploadCountGt);
+    }
+
+    @Override
+    public List<ExamSubject> list(int examId, ExamSubjectStatus status, int uploadCountGt) {
+        return subjectDao.findByExamIdAndStatusAndUploadCountGt(examId, status, uploadCountGt);
+    }
+
+    @Override
+    public List<ExamSubject> list(int examId, ExamSubjectStatus status) {
+        if (status != null) {
+            Set<ExamSubjectStatus> statusSet = new HashSet<ExamSubjectStatus>();
+            statusSet.add(status);
+            return subjectDao.findByExamIdAndStatus(examId, statusSet);
+        } else {
+            return list(examId);
+        }
+    }
+
+    @Override
+    public List<ExamSubject> list(int examId, Set<ExamSubjectStatus> statusSet) {
+        if (statusSet != null && statusSet.size() > 0) {
+            return subjectDao.findByExamIdAndStatus(examId, statusSet);
+        } else {
+            return list(examId);
+        }
+    }
+
+    @Override
+    public List<ExamSubject> list(Set<ExamSubjectStatus> statusSet) {
+        if (statusSet != null && statusSet.size() > 0) {
+            return subjectDao.findByStatus(statusSet);
+        } else {
+            return new LinkedList<ExamSubject>();
+        }
+    }
+
+    @Override
+    public long count(int examId) {
+        return subjectDao.countByExamId(examId);
+    }
+
+    @Override
+    public long count(int examId, Set<ExamSubjectStatus> statusSet) {
+        if (statusSet != null && statusSet.size() > 0) {
+            return subjectDao.countByExamIdAndStatus(examId, statusSet);
+        } else {
+            return subjectDao.countByExamId(examId);
+        }
+    }
+
+    @Override
+    public long count(int examId, ExamSubjectStatus status) {
+        if (status != null) {
+            Set<ExamSubjectStatus> statusSet = new HashSet<ExamSubjectStatus>();
+            statusSet.add(status);
+            return subjectDao.countByExamIdAndStatus(examId, statusSet);
+        } else {
+            return subjectDao.countByExamId(examId);
+        }
+    }
+
+    @Override
+    public ExamSubjectSearchQuery findByQuery(ExamSubjectSearchQuery query) {
+        checkQuery(query);
+        Page<ExamSubject> result = subjectDao.findAll(buildSpecification(query), query);
+        fillResult(result, query);
+        return query;
+    }
+
+    @Override
+    public long countByQuery(ExamSubjectSearchQuery query) {
+        return subjectDao.count(buildSpecification(query));
+    }
+
+    @Transactional
+    @Override
+    // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
+    // allEntries = true)
+    public void delete(ExamSubject markSubject) {
+        subjectDao.delete(markSubject);
+    }
+
+    @Transactional
+    @Override
+    // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
+    // allEntries = true)
+    public void deleteByExamId(int examId) {
+        subjectDao.deleteByExamId(examId);
+    }
+
+    @Transactional
+    @Override
+    // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
+    // allEntries = true)
+    public void changeStatus(int examId, ExamSubjectStatus status) {
+        subjectDao.updateStatusByExamId(examId, status);
+    }
+
+    @Transactional
+    @Override
+    // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
+    // allEntries = true)
+    public void updateTotalScore(int examId) {
+        subjectDao.updateTotalScoreByExamId(examId);
+    }
+
+    @Transactional
+    @Override
+    // @CacheEvict(value = "exam_subject_cache", beforeInvocation = true,
+    // allEntries = true)
+    public void updateScore(int examId, String code) {
+        subjectDao.updateObjectiveScore(examId, code,
+                questionService.sumScoreByExamAndSubjectAndObjective(examId, code, true));
+        subjectDao.updateSubjectiveScore(examId, code,
+                questionService.sumScoreByExamAndSubjectAndObjective(examId, code, false));
+        subjectDao.updateTotalScoreByExamIdAndCode(examId, code);
+    }
+
+    private Specification<ExamSubject> buildSpecification(final ExamSubjectSearchQuery query) {
+        return new Specification<ExamSubject>() {
+
+            @Override
+            public Predicate toPredicate(Root<ExamSubject> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (query.getExamId() > 0) {
+                    predicates.add(cb.equal(root.get("pk").get("examId"), query.getExamId()));
+                }
+                if (StringUtils.isNotEmpty(query.getCode())) {
+                    predicates.add(cb.equal(root.get("pk").get("code"), query.getCode()));
+                }
+                if (StringUtils.isNotBlank(query.getLevel())) {
+                    predicates.add(cb.equal(root.get("level"), query.getLevel()));
+                }
+                if (StringUtils.isNotBlank(query.getCategory())) {
+                    predicates.add(cb.equal(root.get("category"), query.getCategory()));
+                }
+                if (query.getStatus() != null) {
+                    predicates.add(cb.equal(root.get("status"), query.getStatus()));
+                }
+                if (query.getTotalScoreNotEqual() != null) {
+                    predicates.add(cb.notEqual(root.get("totalScore"), query.getTotalScoreNotEqual()));
+                }
+                if (query.getSubjectiveScoreNotEqual() != null) {
+                    predicates.add(cb.notEqual(root.get("subjectiveScore"), query.getSubjectiveScoreNotEqual()));
+                }
+                if (query.getUploadCountGt() != null) {
+                    predicates.add(cb.gt(root.get("uploadCount").as(Integer.class), query.getUploadCountGt()));
+                }
+                if (query.getUploadCountEqual() != null) {
+                    predicates.add(cb.equal(root.get("uploadCount").as(Integer.class), query.getUploadCountEqual()));
+                }
+                return predicates.isEmpty() ? cb.conjunction()
+                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        };
+    }
+
+    @Override
+    @Transactional
+    public void updateUploadCount(Integer examId, String subjectCode) {
+        subjectDao.updateUploadByExamIdAndCode(examId, subjectCode);
+    }
+
+    @Override
+    @Transactional
+    public void updateUploadCount(Integer examId) {
+        subjectDao.updateUploadByExamId(examId);
+    }
+}

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

@@ -0,0 +1,169 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.MarkGroupDao;
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroupPK;
+import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
+import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
+import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
+import cn.com.qmth.stmms.biz.exam.service.MarkerService;
+import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
+import cn.com.qmth.stmms.biz.mark.service.TaskService;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+
+@Service("markGroupService")
+public class MarkGroupServiceImpl extends BaseQueryService<MarkGroup> implements MarkGroupService {
+
+    @Autowired
+    private MarkGroupDao groupDao;
+
+    @Autowired
+    private ExamSubjectService subjectService;
+
+    @Autowired
+    private ExamQuestionService questionService;
+
+    @Autowired
+    private MarkerService markerService;
+
+    @Autowired
+    private MarkLibraryService libraryService;
+
+    @Autowired
+    private TaskService taskService;
+
+    @Transactional
+    @Override
+    public MarkGroup save(MarkGroup group) {
+        if (group.getQuestionList() != null && !group.getQuestionList().isEmpty()) {
+            questionService.deleteByExamAndSubjectAndObjectiveAndMainNumber(group.getExamId(), group.getSubjectCode(),
+                    false, group.getNumber());
+            for (ExamQuestion question : group.getQuestionList()) {
+                questionService.save(question);
+            }
+        }
+        return groupDao.save(group);
+    }
+
+    @Transactional
+    @Override
+    public void reset(MarkGroup group) {
+        groupDao.resetCount(group.getExamId(), group.getSubjectCode(), group.getNumber());
+
+        libraryService.resetByGroup(group);
+        taskService.clearCurrent(group.getExamId(), group.getSubjectCode(), group.getNumber());
+    }
+
+    @Transactional
+    @Override
+    public void resetBuildTime(int examId, String subjectCode) {
+        groupDao.updateBuildTime(examId, subjectCode, null);
+    }
+
+    @Transactional
+    @Override
+    public void delete(MarkGroup group) {
+        groupDao.delete(group);
+
+        taskService.clearCurrent(group.getExamId(), group.getSubjectCode(), group.getNumber());
+        questionService.deleteByExamAndSubjectAndObjectiveAndMainNumber(group.getExamId(), group.getSubjectCode(),
+                false, group.getNumber());
+        libraryService.deleteByGroup(group);
+        markerService.deleteByGroup(group);
+        subjectService.updateScore(group.getExamId(), group.getSubjectCode());
+    }
+
+    @Transactional
+    @Override
+    public void updateLibraryCount(int examId, String subjectCode, int number) {
+        groupDao.updateLibraryCount(examId, subjectCode, number);
+        groupDao.updateMarkedCount(examId, subjectCode, number, LibraryStatus.MARKED);
+        groupDao.updateLeftCount(examId, subjectCode, number);
+    }
+
+    @Transactional
+    @Override
+    public void updateLibraryCount(int examId, String subjectCode) {
+        groupDao.updateLibraryCount(examId, subjectCode);
+        groupDao.updateMarkedCount(examId, subjectCode, LibraryStatus.MARKED);
+        groupDao.updateLeftCount(examId, subjectCode);
+    }
+
+    @Transactional
+    @Override
+    public void updatePicList(int examId, String subjectCode, int number, List<Integer> picList) {
+        groupDao.updatePicList(examId, subjectCode, number,
+                picList != null && picList.size() > 0 ? StringUtils.join(picList, MarkGroup.PIC_SPLIT) : "");
+    }
+
+    @Transactional
+    @Override
+    public void updateTitle(int examId, String subjectCode, int number, String title) {
+        groupDao.updateTitle(examId, subjectCode, number, title);
+        questionService.updateMainTitle(examId, subjectCode, false, number, title);
+    }
+
+    @Transactional
+    @Override
+    public void updateTotalScore(int examId, String subjectCode, int number, Double score) {
+        groupDao.updateTotalScore(examId, subjectCode, number, score);
+    }
+
+    @Transactional
+    @Override
+    public void updateBuildTime(int examId, String subjectCode, int number, Date time) {
+        groupDao.updateBuildTime(examId, subjectCode, number, time);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExam(int examId) {
+        groupDao.deleteByExamId(examId);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamAndSubject(int examId, String subjectCode) {
+        groupDao.deleteByExamIdAndSubjectCode(examId, subjectCode);
+    }
+
+    @Override
+    public MarkGroup findOne(int examId, String subjectCode, int number) {
+        MarkGroupPK pk = new MarkGroupPK();
+        pk.setExamId(examId);
+        pk.setSubjectCode(subjectCode);
+        pk.setNumber(number);
+        return groupDao.findOne(pk);
+    }
+
+    @Override
+    public long countByExamAndSubject(int examId, String subjectCode) {
+        return groupDao.countByExamIdAndSubjectCode(examId, subjectCode);
+    }
+
+    @Override
+    public List<MarkGroup> findByExam(int examId) {
+        return groupDao.findByExamId(examId);
+    }
+
+    @Override
+    public List<MarkGroup> findByExamAndSubject(int examId, String code) {
+        return groupDao.findByExamIdAndSubjectCode(examId, code);
+    }
+
+    @Override
+    public long countByExam(int examId) {
+        return groupDao.countByExamId(examId);
+    }
+
+}

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

@@ -0,0 +1,233 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.MarkerDao;
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.biz.exam.query.MarkerSearchQuery;
+import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
+import cn.com.qmth.stmms.biz.exam.service.MarkerService;
+import cn.com.qmth.stmms.biz.mark.dao.MarkLibraryDao;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+
+@Service("markerService")
+public class MarkerServiceImpl extends BaseQueryService<Marker> implements MarkerService {
+
+    @Autowired
+    private MarkerDao markerDao;
+
+    @Autowired
+    private MarkLibraryDao libraryDao;
+
+    @Autowired
+    private MarkGroupService groupService;
+
+    @Transactional
+    @Override
+    public Marker save(Marker marker) {
+        Marker previous = findByLoginName(marker.getLoginName());
+        if (previous == null || (marker.getId() != null && previous.getId().equals(marker.getId()))) {
+            return markerDao.save(marker);
+        } else {
+            return null;
+        }
+    }
+
+    @Transactional
+    @Override
+    public void delete(Marker marker) {
+        markerDao.delete(marker);
+    }
+
+    @Transactional
+    @Override
+    public void deleteById(Integer markerId) {
+        markerDao.delete(markerId);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamAndSubject(int examId, String subjectCode) {
+        markerDao.deleteByExamIdAndSubjectCode(examId, subjectCode);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByGroup(MarkGroup group) {
+        markerDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
+                group.getNumber());
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExam(int examId) {
+        markerDao.deleteByExamId(examId);
+    }
+
+    @Override
+    public Marker findById(Integer id) {
+        return markerDao.findOne(id);
+    }
+
+    @Override
+    public Marker findByLoginName(String loginName) {
+        List<Marker> list = markerDao.findByLoginName(loginName);
+        return list != null && list.size() > 0 ? list.get(0) : null;
+    }
+
+    @Override
+    public List<Marker> findByExamAndSubjectAndGroup(int examId, String subjectCode, int number) {
+        return markerDao.findByExamIdAndSubjectCodeAndGroupNumber(examId, subjectCode, number, null);
+    }
+
+    @Override
+    public long countByExam(int examId) {
+        return markerDao.countByExamId(examId);
+    }
+
+    @Override
+    public long countByExamAndSubjectAndGroup(int examId, String subjectCode, int number) {
+        return markerDao.countByExamIdAndSubjectCodeAndGroupNumber(examId, subjectCode, number);
+    }
+
+    @Transactional
+    @Override
+    public int batchCreate(ExamSubject subject, int groupNumber, int count, String password) {
+        int result = 0;
+        if (subject != null && count > 0) {
+            if (groupNumber > 0) {
+                result = saveMarker(subject, groupNumber, count, password);
+            } else {
+                List<MarkGroup> groups = groupService.findByExamAndSubject(subject.getExamId(), subject.getCode());
+                for (MarkGroup markGroup : groups) {
+                    result = result + saveMarker(subject, markGroup.getNumber(), count, password);
+                }
+            }
+        }
+        return result;
+    }
+
+    private int saveMarker(ExamSubject subject, int groupNumber, int count, String password) {
+        int result = 0;
+        int start = 1;
+        Marker previous = findLastMarker(subject.getExamId(), subject.getCode());
+        if (previous != null) {
+            start = previous.getNumber() + 1;
+        }
+        int end = start + count - 1;
+        for (; start <= end; start++) {
+            Marker marker = new Marker();
+            marker.setExamId(subject.getExamId());
+            marker.setSubjectCode(subject.getCode());
+            marker.setPassword(password);
+            marker.setEnable(true);
+            marker.buildLoginName(start);
+            marker.setLoginName(marker.getLoginName());
+            marker.setName(marker.getLoginName());
+            marker.setGroupNumber(groupNumber);
+            if (save(marker) != null) {
+                result++;
+            }
+        }
+        return result;
+    }
+
+    private Marker findLastMarker(int examId, String subjectCode) {
+        Marker marker = null;
+        List<Marker> list = markerDao.findByExamIdAndSubjectCode(examId, subjectCode,
+                new BaseQuery<Marker>(1, 1, new Sort(Direction.DESC, "id")));
+        if (list != null && !list.isEmpty()) {
+            marker = list.get(0);
+        }
+        if (marker != null) {
+            return Marker.parseLoginName(marker.getLoginName());
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public List<Marker> getMarkCount(int examId) {
+        List<Marker> list = new LinkedList<Marker>();
+        List<Object[]> result = libraryDao.countByMarkerAndStatus(examId, LibraryStatus.MARKED);
+        if (result != null) {
+            for (Object[] array : result) {
+                try {
+                    Marker marker = findById((int) array[0]);
+                    marker.setMarkedCount((long) array[1]);
+                    list.add(marker);
+                } catch (Exception e) {
+                }
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public List<Marker> getMarkCount(int examId, String subjectCode) {
+        List<Marker> list = new LinkedList<Marker>();
+        List<Object[]> result = libraryDao.countByMarkerAndStatus(examId, subjectCode, LibraryStatus.MARKED);
+        if (result != null) {
+            for (Object[] array : result) {
+                try {
+                    Marker marker = findById((int) array[0]);
+                    marker.setMarkedCount((long) array[1]);
+                    list.add(marker);
+                } catch (Exception e) {
+                }
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public MarkerSearchQuery findByQuery(final MarkerSearchQuery query) {
+        checkQuery(query);
+        Page<Marker> result = markerDao.findAll(buildSpecification(query), query);
+        fillResult(result, query);
+        return query;
+    }
+
+    private Specification<Marker> buildSpecification(final MarkerSearchQuery query) {
+        return new Specification<Marker>() {
+
+            @Override
+            public Predicate toPredicate(Root<Marker> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (query.getExamId() > 0) {
+                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
+                }
+                if (StringUtils.isNotBlank(query.getSubjectCode())) {
+                    predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
+                }
+                if (StringUtils.isNotBlank(query.getLoginName())) {
+                    predicates.add(cb.equal(root.get("loginName"), query.getLoginName()));
+                }
+                if (query.getGroupNumber() > 0) {
+                    predicates.add(cb.equal(root.get("groupNumber"), query.getGroupNumber()));
+                }
+                return predicates.isEmpty() ? cb.conjunction()
+                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        };
+    }
+}

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

@@ -0,0 +1,84 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.ScoreRateDao;
+import cn.com.qmth.stmms.biz.exam.model.ScoreRate;
+import cn.com.qmth.stmms.biz.exam.model.ScoreRatePK;
+import cn.com.qmth.stmms.biz.exam.service.ScoreRateService;
+import cn.com.qmth.stmms.biz.exam.service.query.ScoreRateSearchQuery;
+
+@Service
+public class ScoreRateServiceImpl extends BaseQueryService<ScoreRate> implements ScoreRateService {
+
+    @Autowired
+    private ScoreRateDao scoreRateDao;
+
+    @Transactional
+    @Override
+    public ScoreRate save(ScoreRate scoreRate) {
+        return scoreRateDao.save(scoreRate);
+    }
+
+    @Override
+    public ScoreRate findOne(int examId, String subjectCode,String campusName, boolean objective, int mainNumber, int subNumber) {
+    	ScoreRatePK pk = new ScoreRatePK();
+        pk.setExamId(examId);
+        pk.setSubjectCode(subjectCode);
+        pk.setCampusName(campusName);
+        pk.setMainNumber(mainNumber);
+        pk.setSubNumber(subNumber);
+        pk.setObjective(objective);
+        return scoreRateDao.findOne(pk);
+    }
+
+    @Override
+    public ScoreRateSearchQuery findByQuery(ScoreRateSearchQuery query) {
+        checkQuery(query);
+        query.setSort(new Sort(Direction.ASC, "pk.subjectCode", "pk.campusName","pk.mainNumber", "pk.subNumber"));
+        Page<ScoreRate> result = scoreRateDao.findAll(buildSpecification(query), query);
+        fillResult(result, query);
+        return query;
+    }
+
+    private Specification<ScoreRate> buildSpecification(final ScoreRateSearchQuery query) {
+        return new Specification<ScoreRate>() {
+
+            @Override
+            public Predicate toPredicate(Root<ScoreRate> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (query.getExamId() > 0) {
+                    predicates.add(cb.equal(root.get("pk").get("examId"), query.getExamId()));
+                }
+                if (StringUtils.isNotEmpty(query.getCampusName())) {
+                	predicates.add(cb.equal(root.get("pk").get("campusName"), query.getCampusName()));
+                }
+                if (StringUtils.isNotEmpty(query.getSubjectCode())) {
+                    predicates.add(cb.equal(root.get("pk").get("subjectCode"), query.getSubjectCode()));
+                }
+                if (query.getObjective() != null) {
+                    predicates.add(cb.equal(root.get("pk").get("objective"), query.getObjective()));
+                }
+                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
+                        .size()]));
+            }
+        };
+    }
+}

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

@@ -0,0 +1,31 @@
+package cn.com.qmth.stmms.biz.exam.service.impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.dao.TagDao;
+import cn.com.qmth.stmms.biz.exam.model.Tag;
+import cn.com.qmth.stmms.biz.exam.service.TagService;
+
+@Service
+public class TagServiceImpl extends BaseQueryService<Tag> implements TagService {
+
+    @Autowired
+    private TagDao tagDao;
+
+    @Override
+    // @Cacheable(value = "tag_cache")
+    public List<Tag> findAll() {
+        return tagDao.list();
+    }
+
+    @Override
+    // @Cacheable(value = "tag_cache", key = "#id", condition = "#id!=null")
+    public Tag findById(Integer id) {
+        return tagDao.findOne(id);
+    }
+
+}

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

@@ -0,0 +1,75 @@
+package cn.com.qmth.stmms.biz.exam.service.query;
+
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+
+public class ExamQuestionSearchQuery extends BaseQuery<ExamQuestion> {
+
+    private int examId;
+
+    private String subjectCode;
+
+    private Boolean objective;
+
+    private Integer totalCountGt;
+
+    private Double zeroRateGt;
+
+    private Double totalScoreGt;
+
+    public void orderBySubjectAndNumber() {
+        setSort(new Sort(Direction.ASC, "pk.subjectCode", "pk.mainNumber", "pk.subNumber"));
+    }
+
+    public int getExamId() {
+        return examId;
+    }
+
+    public void setExamId(int examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Boolean getObjective() {
+        return objective;
+    }
+
+    public void setObjective(Boolean objective) {
+        this.objective = objective;
+    }
+
+    public Integer getTotalCountGt() {
+        return totalCountGt;
+    }
+
+    public void setTotalCountGt(Integer totalCountGt) {
+        this.totalCountGt = totalCountGt;
+    }
+
+    public Double getZeroRateGt() {
+        return zeroRateGt;
+    }
+
+    public void setZeroRateGt(Double zeroRateGt) {
+        this.zeroRateGt = zeroRateGt;
+    }
+
+    public Double getTotalScoreGt() {
+        return totalScoreGt;
+    }
+
+    public void setTotalScoreGt(Double totalScoreGt) {
+        this.totalScoreGt = totalScoreGt;
+    }
+
+}

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

@@ -0,0 +1,102 @@
+package cn.com.qmth.stmms.biz.exam.service.query;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.common.enums.ExamSubjectStatus;
+
+public class ExamSubjectSearchQuery extends BaseQuery<ExamSubject> {
+
+    private int examId;
+
+    private String code;
+
+    private String level;
+
+    private String category;
+
+    private ExamSubjectStatus status;
+
+    private Double totalScoreNotEqual;
+
+    private Double subjectiveScoreNotEqual;
+
+    private Integer uploadCountGt;
+
+    private Integer uploadCountEqual;
+
+    public int getExamId() {
+        return examId;
+    }
+
+    public void setExamId(int examId) {
+        this.examId = examId;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public ExamSubjectStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(ExamSubjectStatus status) {
+        this.status = status;
+    }
+
+    public Double getTotalScoreNotEqual() {
+        return totalScoreNotEqual;
+    }
+
+    public void setTotalScoreNotEqual(Double totalScoreNotEqual) {
+        this.totalScoreNotEqual = totalScoreNotEqual;
+    }
+
+    public Double getSubjectiveScoreNotEqual() {
+        return subjectiveScoreNotEqual;
+    }
+
+    public void setSubjectiveScoreNotEqual(Double subjectiveScoreNotEqual) {
+        this.subjectiveScoreNotEqual = subjectiveScoreNotEqual;
+    }
+
+    public String getLevel() {
+        return level;
+    }
+
+    public void setLeve(String level) {
+        this.level = level;
+    }
+
+    public String getCategory() {
+        return category;
+    }
+
+    public void setCategory(String category) {
+        this.category = category;
+    }
+
+    public void setLevel(String level) {
+        this.level = level;
+    }
+
+    public Integer getUploadCountGt() {
+        return uploadCountGt;
+    }
+
+    public void setUploadCountGt(Integer uploadCountGt) {
+        this.uploadCountGt = uploadCountGt;
+    }
+
+    public Integer getUploadCountEqual() {
+        return uploadCountEqual;
+    }
+
+    public void setUploadCountEqual(Integer uploadCountEqual) {
+        this.uploadCountEqual = uploadCountEqual;
+    }
+}

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

@@ -0,0 +1,56 @@
+package cn.com.qmth.stmms.biz.exam.service.query;
+
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.exam.model.ScoreRate;
+
+public class ScoreRateSearchQuery extends BaseQuery<ScoreRate> {
+
+    private int examId;
+    
+    private String campusName;
+
+    private String subjectCode;
+
+    private Boolean objective;
+    
+
+    public void orderBySubjectAndNumber() {
+        setSort(new Sort(Direction.ASC, "pk.subjectCode", "pk.campusName","pk.mainNumber", "pk.subNumber"));
+    }
+
+    public int getExamId() {
+        return examId;
+    }
+
+    public void setExamId(int examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Boolean getObjective() {
+        return objective;
+    }
+
+    public void setObjective(Boolean objective) {
+        this.objective = objective;
+    }
+
+	public String getCampusName() {
+		return campusName;
+	}
+
+	public void setCampusName(String campusName) {
+		this.campusName = campusName;
+	}
+
+}

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

@@ -0,0 +1,87 @@
+package cn.com.qmth.stmms.biz.mark.dao;
+
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+
+public interface MarkLibraryDao
+        extends PagingAndSortingRepository<MarkLibrary, Integer>, JpaSpecificationExecutor<MarkLibrary> {
+
+    List<MarkLibrary> findByExamId(int examId, Pageable page);
+
+    List<MarkLibrary> findByExamIdAndSubjectCode(int examId, String subjectCode, Pageable page);
+
+    List<MarkLibrary> findByExamIdAndStatus(int examId, LibraryStatus status, Pageable page);
+
+    List<MarkLibrary> findByExamIdAndSubjectCodeAndGroupNumberAndStatus(int examId, String subjectCode, int groupNumber,
+            LibraryStatus status, Pageable page);
+
+    List<MarkLibrary> findByExamIdAndSubjectCodeAndGroupNumberAndStatusIn(int examId, String subjectCode,
+            int groupNumber, Set<LibraryStatus> statusSet, Pageable page);
+
+    List<MarkLibrary> findByExamIdAndMarkerId(int examId, int markerId, Pageable page);
+
+    List<MarkLibrary> findByExamIdAndExamNumber(int examId, String examNumber);
+
+    @Query("select l from MarkLibrary l where l.studentId=?1 order by l.groupNumber ")
+    List<MarkLibrary> findByStudentId(int studentId);
+
+    List<MarkLibrary> findByStudentIdAndGroupNumber(int studentId, int groupNumber);
+
+    @Query("select distinct l.campusId from MarkLibrary l where l.examId=?1 and l.tags is not null")
+    List<Integer> findTagCampusId(int examId);
+
+    @Query("select distinct l.subjectCode from MarkLibrary l where l.examId=?1 and l.tags is not null")
+    List<String> findTagSubjectCode(int examId);
+
+    @Modifying
+    @Query("update MarkLibrary m set m.status=?2, m.tags=null, m.markerId=null, m.markerTime=null, m.markerScore=null, m.markerScoreList=null where m.examId=?1")
+    void resetByExamId(int examId, LibraryStatus status);
+
+    @Modifying
+    @Query("update MarkLibrary m set m.status=?4, m.tags=null, m.markerId=null, m.markerTime=null, m.markerScore=null, m.markerScoreList=null where m.examId=?1 and m.subjectCode=?2 and m.groupNumber=?3")
+    void resetByExamIdAndSubjectCodeAndNumber(int examId, String subjectCode, int number, LibraryStatus status);
+
+    @Modifying
+    @Query("update MarkLibrary m set m.status=?2, m.tags=null, m.markerId=null, m.markerTime=null, m.markerScore=null, m.markerScoreList=null where m.markerId=?1")
+    void resetByMarkerId(int markerId, LibraryStatus status);
+
+    @Modifying
+    @Query("update MarkLibrary m set m.status=?2, m.tags=null, m.markerId=null, m.markerTime=null, m.markerScore=null, m.markerScoreList=null where m.id=?1")
+    void resetById(int id, LibraryStatus status);
+
+    @Query("select count(*) from MarkLibrary f where f.examId=?1")
+    long countByExamId(int examId);
+
+    @Query("select count(*) from MarkLibrary f where f.examId=?1 and f.subjectCode=?2")
+    long countByExamIdAndSubjectCode(int examId, String subjectCode);
+
+    @Query("select count(*) from MarkLibrary f where f.examId=?1 and f.subjectCode=?2 and f.status=?3")
+    long countByExamIdAndSubjectCodeAndStatus(int examId, String subjectCode, LibraryStatus status);
+
+    @Query("select f.markerId, count(*) as markerCount from MarkLibrary f where f.examId=?1 and f.status=?2 group by f.markerId")
+    List<Object[]> countByMarkerAndStatus(int examId, LibraryStatus status);
+
+    @Query("select f.markerId, count(*) as markerCount from MarkLibrary f where f.examId=?1 and f.subjectCode=?2 and f.status=?3 group by f.markerId")
+    List<Object[]> countByMarkerAndStatus(int examId, String subjectCode, LibraryStatus status);
+
+    @Modifying
+    @Query("delete MarkLibrary m where m.examId=?1")
+    void deleteByExamId(int examId);
+
+    @Modifying
+    @Query("delete MarkLibrary m where m.examId=?1 and m.subjectCode=?2 and m.groupNumber=?3")
+    void deleteByExamIdAndSubjectCodeAndGroupNumber(int examId, String subjectCode, int groupNumber);
+
+    @Query("select l from MarkLibrary l where l.studentId=?1 and l.status=?2 order by l.groupNumber ")
+    List<MarkLibrary> findByStudentIdAndStatus(int studentId, LibraryStatus status);
+
+}

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

@@ -0,0 +1,39 @@
+package cn.com.qmth.stmms.biz.mark.dao;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import cn.com.qmth.stmms.biz.mark.model.MarkTrack;
+import cn.com.qmth.stmms.biz.mark.model.MarkTrackPK;
+
+public interface MarkTrackDao extends JpaRepository<MarkTrack, MarkTrackPK>, JpaSpecificationExecutor<MarkTrack> {
+
+    List<MarkTrack> findByPkStudentId(Integer studentId);
+
+    @Modifying
+    @Query("delete from MarkTrack t where t.pk.studentId=?1")
+    void deleteByStudentId(Integer studentId);
+
+    @Modifying
+    @Query("delete from MarkTrack t where t.pk.studentId=?1 and t.pk.questionNumber=?2")
+    void deleteByStudentIdAndQuestionNumber(Integer studentId, String questionNumber);
+
+    @Modifying
+    @Query("delete from MarkTrack t where t.examId=?1")
+    void deleteByExamId(Integer examId);
+
+    @Modifying
+    @Query("delete from MarkTrack t where t.examId=?1 and t.subjectCode=?2 and t.groupNumber=?3")
+    void deleteByExamIdAndSubjectCodeAndGroupNumber(Integer examId, String subjectCode, Integer number);
+
+    @Modifying
+    @Query("delete from MarkTrack t where t.markerId=?1")
+    void deleteByMarkerId(Integer markerId);
+
+    List<MarkTrack> findByPkStudentIdAndGroupNumber(Integer studentId, Integer number);
+
+}

+ 29 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkCount.java

@@ -0,0 +1,29 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import java.io.Serializable;
+
+/**
+ * 评卷数量统计
+ * 
+ * @author LS
+ * 
+ */
+public class MarkCount implements Serializable {
+
+    private static final long serialVersionUID = 5574518092870671752L;
+
+    private int totalCount;
+
+    public int getTotalCount() {
+        return totalCount;
+    }
+
+    public void setTotalCount(int totalCount) {
+        this.totalCount = totalCount;
+    }
+
+    public void incrTotalCount() {
+        this.totalCount++;
+    }
+
+}

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

@@ -0,0 +1,238 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+
+import org.apache.commons.lang.StringUtils;
+
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.biz.utils.ScoreItem;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+
+@Entity
+@Table(name = "m_library")
+public class MarkLibrary implements Serializable {
+
+    private static final long serialVersionUID = 7121951721670633060L;
+
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    /**
+     * 考试ID
+     */
+    @Column(name = "exam_id")
+    private Integer examId;
+
+    /**
+     * 科目CODE
+     */
+    @Column(name = "subject_code")
+    private String subjectCode;
+
+    /**
+     * 大题序号
+     */
+    @Column(name = "group_number")
+    private Integer groupNumber;
+
+    /**
+     * 学习中心
+     */
+    @Column(name = "campus_id")
+    private Integer campusId;
+
+    /**
+     * 考生编号
+     */
+    @Column(name = "student_id")
+    private Integer studentId;
+
+    /**
+     * 准考证号
+     */
+    @Column(name = "exam_number")
+    private String examNumber;
+
+    /**
+     * 评卷员
+     */
+    @Column(name = "marker_id")
+    private Integer markerId;
+
+    /**
+     * 评卷时间
+     */
+    @Column(name = "marker_time")
+    private Date markerTime;
+
+    /**
+     * 评卷员给分总分
+     */
+    @Column(name = "marker_score")
+    private Double markerScore;
+
+    /**
+     * 评卷员给分明细
+     */
+    @Column(name = "marker_score_list")
+    private String markerScoreList;
+
+    /**
+     * 试卷标记信息
+     */
+    @Column(name = "tags")
+    private String tags;
+
+    /**
+     * 任务状态
+     */
+    @Column(name = "status")
+    @Enumerated(EnumType.ORDINAL)
+    private LibraryStatus status;
+
+    @Transient
+    private Marker marker;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public Integer getMarkerId() {
+        return markerId;
+    }
+
+    public void setMarkerId(Integer markerId) {
+        this.markerId = markerId;
+    }
+
+    public Date getMarkerTime() {
+        return markerTime;
+    }
+
+    public void setMarkerTime(Date markerTime) {
+        this.markerTime = markerTime;
+    }
+
+    public Double getMarkerScore() {
+        return markerScore;
+    }
+
+    public void setMarkerScore(Double markerScore) {
+        this.markerScore = markerScore;
+    }
+
+    public String getMarkerScoreList() {
+        return markerScoreList;
+    }
+
+    public void setMarkerScoreList(String markerScoreList) {
+        this.markerScoreList = markerScoreList;
+    }
+
+    public LibraryStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(LibraryStatus status) {
+        this.status = status;
+    }
+
+    public List<ScoreItem> getScoreList() {
+        List<ScoreItem> list = new LinkedList<ScoreItem>();
+        if (StringUtils.isNotBlank(markerScoreList)) {
+            try {
+                String[] values = markerScoreList.split(",");
+                for (String value : values) {
+                    ScoreItem item = ScoreItem.parse(value, false);
+                    if (item != null) {
+                        list.add(item);
+                    }
+                }
+            } catch (Exception e) {
+            }
+        }
+        return list;
+    }
+
+    public Integer getCampusId() {
+        return campusId;
+    }
+
+    public void setCampusId(Integer campusId) {
+        this.campusId = campusId;
+    }
+
+    public String getTags() {
+        return tags;
+    }
+
+    public void setTags(String tags) {
+        this.tags = tags;
+    }
+
+    public Integer getGroupNumber() {
+        return groupNumber;
+    }
+
+    public void setGroupNumber(Integer groupNumber) {
+        this.groupNumber = groupNumber;
+    }
+
+    public Marker getMarker() {
+        return marker;
+    }
+
+    public void setMarker(Marker marker) {
+        this.marker = marker;
+    }
+
+}

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

@@ -0,0 +1,173 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+
+public class MarkStepDTO implements Serializable {
+
+    private static final long serialVersionUID = 3542801746602688750L;
+
+    private String questionNumber;
+
+    private int blockId;
+
+    private int number;
+
+    private String title;
+
+    private boolean hasLevel;
+
+    private double totalScore;
+
+    private double max;
+
+    private double min;
+
+    private double defaultScore;
+
+    private double interval;
+
+    private double[] scoreList;
+
+    private String remark;
+
+    private List<TrackDTO> trackList = new ArrayList<TrackDTO>();
+
+    public String getQuestionNumber() {
+        return questionNumber;
+    }
+
+    public void setQuestionNumber(String questionNumber) {
+        this.questionNumber = questionNumber;
+    }
+
+    public double[] getScoreArray() {
+        return scoreList;
+    }
+
+    public double[] getScoreList() {
+        return scoreList;
+    }
+
+    public void setScoreList(double[] scoreList) {
+        this.scoreList = scoreList;
+    }
+
+    public void setScoreList(String scoreListValue) {
+        String[] values = StringUtils.split(StringUtils.trimToEmpty(scoreListValue), ",");
+        if (values != null && values.length > 0) {
+            List<Double> list = new ArrayList<Double>(values.length);
+            for (String value : values) {
+                try {
+                    list.add(Double.valueOf(value));
+                } catch (Exception e) {
+                    continue;
+                }
+            }
+            int length = list.size();
+            if (length > 0) {
+                double[] array = new double[length];
+                for (int i = 0; i < length; i++) {
+                    array[i] = list.get(i);
+                }
+                this.scoreList = array;
+            }
+        }
+    }
+
+    public int getBlockId() {
+        return blockId;
+    }
+
+    public void setBlockId(int blockId) {
+        this.blockId = blockId;
+    }
+
+    public int getNumber() {
+        return number;
+    }
+
+    public void setNumber(int number) {
+        this.number = number;
+    }
+
+    public boolean isHasLevel() {
+        return hasLevel;
+    }
+
+    public void setHasLevel(boolean hasLevel) {
+        this.hasLevel = hasLevel;
+    }
+
+    public double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public double getMax() {
+        return max;
+    }
+
+    public void setMax(double max) {
+        this.max = max;
+    }
+
+    public double getMin() {
+        return min;
+    }
+
+    public void setMin(double min) {
+        this.min = min;
+    }
+
+    public double getDefaultScore() {
+        return defaultScore;
+    }
+
+    public void setDefaultScore(double defaultScore) {
+        this.defaultScore = defaultScore;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public double getInterval() {
+        return interval;
+    }
+
+    public void setInterval(double interval) {
+        this.interval = interval;
+    }
+
+    public List<TrackDTO> getTrackList() {
+        return trackList;
+    }
+
+    public void setTrackList(List<TrackDTO> trackList) {
+        this.trackList = trackList;
+    }
+
+    public void addTrack(TrackDTO track) {
+        this.trackList.add(track);
+    }
+
+}

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

@@ -0,0 +1,135 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * 阅卷轨迹
+ * 
+ * @author luoshi
+ * 
+ */
+@Entity
+@Table(name = "m_track")
+public class MarkTrack {
+
+    @EmbeddedId
+    private MarkTrackPK pk;
+
+    @Column(name = "exam_id", nullable = false)
+    private Integer examId;
+
+    @Column(name = "subject_code", nullable = false)
+    private String subjectCode;
+
+    @Column(name = "group_number", nullable = false)
+    private Integer groupNumber;
+
+    @Column(name = "marker_id", nullable = false)
+    private Integer markerId;
+
+    /**
+     * 轨迹分数
+     */
+    @Column(name = "score", nullable = false)
+    private Double score;
+
+    /**
+     * X轴相对位置,0~1
+     */
+    @Column(name = "position_x", nullable = false)
+    private Double positionX;
+
+    /**
+     * Y轴相对位置,0~1
+     */
+    @Column(name = "position_y", nullable = false)
+    private Double positionY;
+
+    public MarkTrack() {
+        this.pk = new MarkTrackPK();
+    }
+
+    public Integer getStudentId() {
+        return pk.getStudentId();
+    }
+
+    public void setStudentId(Integer studentId) {
+        pk.setStudentId(studentId);
+    }
+
+    public String getQuestionNumber() {
+        return pk.getQuestionNumber();
+    }
+
+    public void setQuestionNumber(String questionNumber) {
+        pk.setQuestionNumber(questionNumber);
+    }
+
+    public Integer getNumber() {
+        return pk.getNumber();
+    }
+
+    public void setNumber(Integer number) {
+        pk.setNumber(number);
+    }
+
+    public Double getScore() {
+        return score;
+    }
+
+    public void setScore(Double score) {
+        this.score = score;
+    }
+
+    public Double getPositionX() {
+        return positionX;
+    }
+
+    public void setPositionX(Double positionX) {
+        this.positionX = positionX;
+    }
+
+    public Double getPositionY() {
+        return positionY;
+    }
+
+    public void setPositionY(Double positionY) {
+        this.positionY = positionY;
+    }
+
+    public Integer getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Integer examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public Integer getMarkerId() {
+        return markerId;
+    }
+
+    public void setMarkerId(Integer markerId) {
+        this.markerId = markerId;
+    }
+
+    public Integer getGroupNumber() {
+        return groupNumber;
+    }
+
+    public void setGroupNumber(Integer groupNumber) {
+        this.groupNumber = groupNumber;
+    }
+
+}

+ 85 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/MarkTrackPK.java

@@ -0,0 +1,85 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class MarkTrackPK implements Serializable {
+
+    private static final long serialVersionUID = 9096523417236451724L;
+
+    @Column(name = "student_id", nullable = false)
+    private Integer studentId;
+
+    @Column(name = "question_number", nullable = false)
+    private String questionNumber;
+
+    @Column(name = "number", nullable = false)
+    private Integer number;
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public String getQuestionNumber() {
+        return questionNumber;
+    }
+
+    public void setQuestionNumber(String questionNumber) {
+        this.questionNumber = questionNumber;
+    }
+
+    public Integer getNumber() {
+        return number;
+    }
+
+    public void setNumber(Integer number) {
+        this.number = number;
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + ((studentId == null) ? 0 : studentId.hashCode());
+        result = PRIME * result + ((questionNumber == null) ? 0 : questionNumber.hashCode());
+        result = PRIME * result + ((number == null) ? 0 : number.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final MarkTrackPK other = (MarkTrackPK) obj;
+        if (studentId == null) {
+            if (other.studentId != null)
+                return false;
+        } else if (!studentId.equals(other.studentId))
+            return false;
+        if (questionNumber == null) {
+            if (other.questionNumber != null)
+                return false;
+        } else if (!questionNumber.equals(other.questionNumber))
+            return false;
+
+        if (number == null) {
+            if (other.number != null)
+                return false;
+        } else if (!number.equals(other.number))
+            return false;
+
+        return true;
+    }
+
+}

+ 317 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/model/Task.java

@@ -0,0 +1,317 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class Task implements Serializable {
+
+    private static final long serialVersionUID = 4912665442008033200L;
+
+    /**
+     * 考生编号
+     */
+    private String studentId;
+
+    /**
+     * 库ID
+     */
+    private int libraryId;
+
+    /**
+     * 评卷员Id
+     */
+    private int markId;
+
+    /**
+     * 题卡图片地址
+     */
+    private List<String> pictureUrls;
+
+    /**
+     * 题卡原图地址
+     */
+    private List<String> sheetUrls;
+
+    /**
+     * 答案文档地址
+     */
+    private String answerUrl;
+
+    /**
+     * 试卷文档地址
+     */
+    private String paperUrl;
+
+    /**
+     * 客观题总分
+     */
+    private Double objectiveScore;
+
+    /**
+     * 给分步骤
+     */
+    private List<MarkStepDTO> markStepList;
+
+    /**
+     * 是否自评
+     */
+    private boolean isSelf;
+
+    /**
+     * 是否回评
+     */
+    private boolean isPrevious;
+
+    /**
+     * 是否打回
+     */
+    private boolean isBack;
+
+    /**
+     * 是否问题卷
+     */
+    private boolean isProblem;
+
+    /**
+     * 总分
+     */
+    private double totalScore;
+
+    /**
+     * 分值列表
+     */
+    private String scoreList;
+
+    /**
+     * 阅卷轨迹列表
+     */
+    private TrackDTO[] trackList;
+
+    /**
+     * 所花时间
+     */
+    private long spent;
+
+    /**
+     * 问题类型
+     */
+    private int reason;
+
+    /**
+     * 评卷时间
+     */
+    private Date markTime;
+
+    /**
+     * 任务是否存在
+     */
+    private boolean isExist;
+
+    /**
+     * 试卷标记信息
+     */
+    private String tags;
+
+    private String message;
+
+    public Task() {
+
+    }
+
+    public String getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(String studentId) {
+        this.studentId = studentId;
+    }
+
+    public int getLibraryId() {
+        return libraryId;
+    }
+
+    public void setLibraryId(int libraryId) {
+        this.libraryId = libraryId;
+    }
+
+    public int getMarkId() {
+        return markId;
+    }
+
+    public void setMarkId(int markId) {
+        this.markId = markId;
+    }
+
+    public List<String> getPictureUrls() {
+        return pictureUrls;
+    }
+
+    public void setPictureUrls(List<String> pictureUrls) {
+        this.pictureUrls = pictureUrls;
+    }
+
+    public String getAnswerUrl() {
+        return answerUrl;
+    }
+
+    public void setAnswerUrl(String answerUrl) {
+        this.answerUrl = answerUrl;
+    }
+
+    public String getPaperUrl() {
+        return paperUrl;
+    }
+
+    public void setPaperUrl(String paperUrl) {
+        this.paperUrl = paperUrl;
+    }
+
+    public List<MarkStepDTO> getMarkStepList() {
+        return markStepList;
+    }
+
+    public void setMarkStepList(List<MarkStepDTO> markStepList) {
+        this.markStepList = markStepList;
+    }
+
+    public double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public String getScoreList() {
+        return scoreList;
+    }
+
+    public void setScoreList(String scoreList) {
+        this.scoreList = scoreList;
+    }
+
+    public long getSpent() {
+        return spent;
+    }
+
+    public void setSpent(long spent) {
+        this.spent = spent;
+    }
+
+    public int getReason() {
+        return reason;
+    }
+
+    public void setReason(int reason) {
+        this.reason = reason;
+    }
+
+    public Date getMarkTime() {
+        return markTime;
+    }
+
+    public void setMarkTime(Date markTime) {
+        this.markTime = markTime;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public Double getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(Double objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
+
+    public List<String> getSheetUrls() {
+        return sheetUrls;
+    }
+
+    public void setSheetUrls(List<String> sheetUrls) {
+        this.sheetUrls = sheetUrls;
+    }
+
+    public String getTags() {
+        return tags;
+    }
+
+    public void setTags(String tags) {
+        this.tags = tags;
+    }
+
+    public boolean isSelf() {
+        return isSelf;
+    }
+
+    public void setSelf(boolean isSelf) {
+        this.isSelf = isSelf;
+    }
+
+    public boolean isPrevious() {
+        return isPrevious;
+    }
+
+    public void setPrevious(boolean isPrevious) {
+        this.isPrevious = isPrevious;
+    }
+
+    public boolean isBack() {
+        return isBack;
+    }
+
+    public void setBack(boolean isBack) {
+        this.isBack = isBack;
+    }
+
+    public boolean isProblem() {
+        return isProblem;
+    }
+
+    public void setProblem(boolean isProblem) {
+        this.isProblem = isProblem;
+    }
+
+    public boolean isExist() {
+        return isExist;
+    }
+
+    public void setExist(boolean isExist) {
+        this.isExist = isExist;
+    }
+
+    public TrackDTO[] getTrackList() {
+        return trackList;
+    }
+
+    public void setTrackList(TrackDTO[] trackList) {
+        this.trackList = trackList;
+    }
+
+    public Map<String, List<TrackDTO>> getTrackMap() {
+        Map<String, List<TrackDTO>> map = new HashMap<String, List<TrackDTO>>();
+        if (trackList != null) {
+            for (TrackDTO dto : trackList) {
+                String questionNumber = dto.getQuestionNumber();
+                List<TrackDTO> list = map.get(questionNumber);
+                if (list == null) {
+                    list = new LinkedList<TrackDTO>();
+                    map.put(questionNumber, list);
+                }
+                list.add(dto);
+            }
+        }
+        return map;
+    }
+
+}

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

@@ -0,0 +1,92 @@
+package cn.com.qmth.stmms.biz.mark.model;
+
+import java.io.Serializable;
+
+/**
+ * 阅卷轨迹交换类
+ * 
+ * @author luoshi
+ * 
+ */
+public class TrackDTO implements Serializable {
+
+    private static final long serialVersionUID = 4336042741848228793L;
+
+    private String questionNumber;
+
+    private int number;
+
+    private double score;
+
+    private double positionX;
+
+    private double positionY;
+
+    public TrackDTO() {
+
+    }
+
+    public TrackDTO(MarkTrack track) {
+        setQuestionNumber(track.getQuestionNumber());
+        setNumber(track.getNumber());
+        setScore(track.getScore());
+        setPositionX(track.getPositionX());
+        setPositionY(track.getPositionY());
+    }
+
+    public MarkTrack transform(MarkLibrary library) {
+        MarkTrack track = new MarkTrack();
+        track.setStudentId(library.getStudentId());
+        track.setQuestionNumber(getQuestionNumber());
+        track.setNumber(getNumber());
+        track.setExamId(library.getExamId());
+        track.setSubjectCode(library.getSubjectCode());
+        track.setMarkerId(library.getMarkerId());
+        track.setScore(getScore());
+        track.setPositionX(getPositionX());
+        track.setPositionY(getPositionY());
+        track.setGroupNumber(library.getGroupNumber());
+        return track;
+    }
+
+    public String getQuestionNumber() {
+        return questionNumber;
+    }
+
+    public void setQuestionNumber(String questionNumber) {
+        this.questionNumber = questionNumber;
+    }
+
+    public int getNumber() {
+        return number;
+    }
+
+    public void setNumber(int number) {
+        this.number = number;
+    }
+
+    public double getScore() {
+        return score;
+    }
+
+    public void setScore(double score) {
+        this.score = score;
+    }
+
+    public double getPositionX() {
+        return positionX;
+    }
+
+    public void setPositionX(double positionX) {
+        this.positionX = positionX;
+    }
+
+    public double getPositionY() {
+        return positionY;
+    }
+
+    public void setPositionY(double positionY) {
+        this.positionY = positionY;
+    }
+
+}

+ 120 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/query/MarkLibrarySearchQuery.java

@@ -0,0 +1,120 @@
+package cn.com.qmth.stmms.biz.mark.query;
+
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+
+public class MarkLibrarySearchQuery extends BaseQuery<MarkLibrary> {
+
+    private int examId;
+
+    private String subjectCode;
+
+    private int campusId;
+
+    private int studentId;
+
+    private String examNumber;
+
+    private LibraryStatus status;
+
+    private int markerId;
+
+    private int tagId;
+
+    private Boolean tagNotNull;
+    
+    private int groupNumber;
+
+    public void orderByMarkerTimeDesc() {
+        setSort(new Sort(Direction.DESC, "markerTime"));
+    }
+
+    public void orderByExamNumber() {
+        setSort(new Sort(Direction.ASC, "examNumber"));
+    }
+
+    public int getExamId() {
+        return examId;
+    }
+
+    public void setExamId(int examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public int getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(int studentId) {
+        this.studentId = studentId;
+    }
+
+    public String getExamNumber() {
+        return examNumber;
+    }
+
+    public void setExamNumber(String examNumber) {
+        this.examNumber = examNumber;
+    }
+
+    public LibraryStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(LibraryStatus status) {
+        this.status = status;
+    }
+
+    public int getMarkerId() {
+        return markerId;
+    }
+
+    public void setMarkerId(int markerId) {
+        this.markerId = markerId;
+    }
+
+    public int getTagId() {
+        return tagId;
+    }
+
+    public void setTagId(int tagId) {
+        this.tagId = tagId;
+    }
+
+    public Boolean getTagNotNull() {
+        return tagNotNull;
+    }
+
+    public void setTagNotNull(Boolean tagNotNull) {
+        this.tagNotNull = tagNotNull;
+    }
+
+    public int getCampusId() {
+        return campusId;
+    }
+
+    public void setCampusId(int campusId) {
+        this.campusId = campusId;
+    }
+
+	public int getGroupNumber() {
+		return groupNumber;
+	}
+
+	public void setGroupNumber(int groupNumber) {
+		this.groupNumber = groupNumber;
+	}
+
+}

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

@@ -0,0 +1,254 @@
+package cn.com.qmth.stmms.biz.mark.service.Impl;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
+import cn.com.qmth.stmms.biz.mark.dao.MarkLibraryDao;
+import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
+import cn.com.qmth.stmms.biz.mark.query.MarkLibrarySearchQuery;
+import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
+import cn.com.qmth.stmms.biz.mark.service.MarkTrackService;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+
+@Service
+public class MarkLibraryServiceImpl extends BaseQueryService<MarkLibrary> implements MarkLibraryService {
+
+    @Autowired
+    private MarkLibraryDao libraryDao;
+
+    @Autowired
+    private MarkTrackService trackService;
+
+    @Autowired
+    private ExamQuestionService questionService;
+
+    @Transactional
+    @Override
+    public void delete(MarkLibrary library) {
+        libraryDao.delete(library);
+        if (library != null) {
+            List<ExamQuestion> examQuestions = questionService.findByExamAndSubjectAndObjectiveAndMainNumber(
+                    library.getExamId(), library.getSubjectCode(), false, library.getGroupNumber());
+            for (ExamQuestion examQuestion : examQuestions) {
+                trackService.deleteByStudentIdAndQuestionNumber(library.getStudentId(),
+                        examQuestion.getQuestionNumber());
+            }
+        }
+    }
+
+    @Transactional
+    @Override
+    public void deleteByStudent(int studentId) {
+        List<MarkLibrary> library = findByStudentId(studentId);
+        if (library != null) {
+            for (MarkLibrary markLibrary : library) {
+                this.delete(markLibrary);
+            }
+        }
+        trackService.deleteByStudentId(studentId);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByGroup(MarkGroup group) {
+        libraryDao.deleteByExamIdAndSubjectCodeAndGroupNumber(group.getExamId(), group.getSubjectCode(),
+                group.getNumber());
+        trackService.deleteByExamAndSubjectAndGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
+    }
+
+    @Transactional
+    @Override
+    public MarkLibrary save(MarkLibrary library) {
+        return libraryDao.save(library);
+    }
+
+    @Override
+    public MarkLibrary findById(int id) {
+        return libraryDao.findOne(id);
+    }
+
+    @Override
+    public MarkLibrary findByStudentAndGroup(int studentId, int groupNumber) {
+        List<MarkLibrary> list = libraryDao.findByStudentIdAndGroupNumber(studentId, groupNumber);
+        return list != null && list.size() > 0 ? list.get(0) : null;
+    }
+
+    @Override
+    public List<MarkLibrary> findByStudentId(int studentId) {
+        List<MarkLibrary> list = libraryDao.findByStudentId(studentId);
+        // return list != null && list.size() > 0 ? list.get(0) : null;
+        return list;
+    }
+
+    @Override
+    public List<MarkLibrary> findByStatus(int examId, String subjectCode, int groupNumber, LibraryStatus status,
+            int pageNumber, int pageSize) {
+        MarkLibrarySearchQuery query = new MarkLibrarySearchQuery();
+        query.setPageNumber(pageNumber);
+        query.setPageSize(pageSize);
+        return libraryDao.findByExamIdAndSubjectCodeAndGroupNumberAndStatus(examId, subjectCode, groupNumber, status,
+                query);
+    }
+
+    @Override
+    public List<MarkLibrary> findByStatusSet(int examId, String subjectCode, int groupNumber,
+            Set<LibraryStatus> statusSet, int pageNumber, int pageSize) {
+        MarkLibrarySearchQuery query = new MarkLibrarySearchQuery();
+        query.setPageNumber(pageNumber);
+        query.setPageSize(pageSize);
+        return libraryDao.findByExamIdAndSubjectCodeAndGroupNumberAndStatusIn(examId, subjectCode, groupNumber,
+                statusSet, query);
+    }
+
+    @Override
+    @Transactional
+    public void resetByGroup(MarkGroup group) {
+        libraryDao.resetByExamIdAndSubjectCodeAndNumber(group.getExamId(), group.getSubjectCode(), group.getNumber(),
+                LibraryStatus.WAITING);
+        trackService.deleteByExamAndSubjectAndGroup(group.getExamId(), group.getSubjectCode(), group.getNumber());
+    }
+
+    @Override
+    @Transactional
+    public void resetByMarker(Marker marker) {
+        libraryDao.resetByMarkerId(marker.getId(), LibraryStatus.WAITING);
+        trackService.deleteByMarkerId(marker.getId());
+    }
+
+    @Override
+    @Transactional
+    public void resetById(int id) {
+        libraryDao.resetById(id, LibraryStatus.WAITING);
+        MarkLibrary library = findById(id);
+        if (library != null) {
+            List<ExamQuestion> examQuestions = questionService.findByExamAndSubjectAndObjectiveAndMainNumber(
+                    library.getExamId(), library.getSubjectCode(), false, library.getGroupNumber());
+            for (ExamQuestion examQuestion : examQuestions) {
+                trackService.deleteByStudentIdAndQuestionNumber(library.getStudentId(),
+                        examQuestion.getQuestionNumber());
+            }
+        }
+    }
+
+    @Override
+    @Transactional
+    public void backById(int id) {
+        libraryDao.resetById(id, LibraryStatus.BACKED);
+        MarkLibrary library = findById(id);
+        if (library != null) {
+            List<ExamQuestion> examQuestions = questionService.findByExamAndSubjectAndObjectiveAndMainNumber(
+                    library.getExamId(), library.getSubjectCode(), false, library.getGroupNumber());
+            for (ExamQuestion examQuestion : examQuestions) {
+                trackService.deleteByStudentIdAndQuestionNumber(library.getStudentId(),
+                        examQuestion.getQuestionNumber());
+            }
+        }
+    }
+
+    @Override
+    public List<Integer> findTagCampusId(int examId) {
+        return libraryDao.findTagCampusId(examId);
+    }
+
+    @Override
+    public List<String> findTagSubjectCode(int examId) {
+        return libraryDao.findTagSubjectCode(examId);
+    }
+
+    @Override
+    public long countByExamAndSubjectAndGroupAndStatus(int examId, String subjectCode, int groupNumber,
+            LibraryStatus status) {
+        MarkLibrarySearchQuery query = new MarkLibrarySearchQuery();
+        query.setExamId(examId);
+        query.setSubjectCode(subjectCode);
+        query.setGroupNumber(groupNumber);
+        query.setStatus(status);
+        return countByQuery(query);
+    }
+
+    @Override
+    public long countByMarker(int markerId) {
+        MarkLibrarySearchQuery query = new MarkLibrarySearchQuery();
+        query.setMarkerId(markerId);
+        query.setStatus(LibraryStatus.MARKED);
+        return countByQuery(query);
+    }
+
+    @Override
+    public long countByQuery(final MarkLibrarySearchQuery query) {
+        return libraryDao.count(buildSpecification(query));
+    }
+
+    @Override
+    public MarkLibrarySearchQuery findByQuery(final MarkLibrarySearchQuery query) {
+        checkQuery(query);
+        Page<MarkLibrary> result = libraryDao.findAll(buildSpecification(query), query);
+        fillResult(result, query);
+        return query;
+    }
+
+    private Specification<MarkLibrary> buildSpecification(final MarkLibrarySearchQuery query) {
+        return new Specification<MarkLibrary>() {
+
+            @Override
+            public Predicate toPredicate(Root<MarkLibrary> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (query.getExamId() > 0) {
+                    predicates.add(cb.equal(root.get("examId"), query.getExamId()));
+                }
+                if (StringUtils.isNotBlank(query.getSubjectCode())) {
+                    predicates.add(cb.equal(root.get("subjectCode"), query.getSubjectCode()));
+                }
+                if (query.getCampusId() > 0) {
+                    predicates.add(cb.equal(root.get("campusId"), query.getCampusId()));
+                }
+                if (query.getGroupNumber() > 0) {
+                    predicates.add(cb.equal(root.get("groupNumber"), query.getGroupNumber()));
+                }
+                if (StringUtils.isNotBlank(query.getExamNumber())) {
+                    predicates.add(cb.equal(root.get("examNumber"), query.getExamNumber()));
+                }
+                if (query.getStudentId() > 0) {
+                    predicates.add(cb.equal(root.get("studentId"), query.getStudentId()));
+                }
+                if (query.getMarkerId() > 0) {
+                    predicates.add(cb.equal(root.get("markerId"), query.getMarkerId()));
+                }
+                if (query.getStatus() != null) {
+                    predicates.add(cb.equal(root.get("status").as(LibraryStatus.class), query.getStatus()));
+                }
+                if (query.getTagNotNull() != null && query.getTagNotNull().booleanValue()) {
+                    predicates.add(cb.isNotNull(root.get("tags")));
+                }
+                if (query.getTagId() > 0) {
+                    predicates.add(cb.like(root.get("tags").as(String.class), "%" + query.getTagId() + "%"));
+                }
+                return predicates.isEmpty() ? cb.conjunction()
+                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        };
+    }
+
+    @Override
+    public List<MarkLibrary> findByStudentIdAndStatus(int studentId, LibraryStatus status) {
+        return libraryDao.findByStudentIdAndStatus(studentId, status);
+    }
+}

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

@@ -0,0 +1,65 @@
+package cn.com.qmth.stmms.biz.mark.service.Impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.mark.dao.MarkTrackDao;
+import cn.com.qmth.stmms.biz.mark.model.MarkTrack;
+import cn.com.qmth.stmms.biz.mark.service.MarkTrackService;
+
+@Service("markTrackService")
+public class MarkTrackServiceImpl extends BaseQueryService<MarkTrack> implements MarkTrackService {
+
+    @Autowired
+    private MarkTrackDao markTrackDao;
+
+    @Override
+    public List<MarkTrack> findByStudentId(Integer studentId) {
+        return markTrackDao.findByPkStudentId(studentId);
+    }
+
+    @Transactional
+    @Override
+    public MarkTrack save(MarkTrack track) {
+        return markTrackDao.save(track);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByStudentId(Integer studentId) {
+        markTrackDao.deleteByStudentId(studentId);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByStudentIdAndQuestionNumber(Integer studentId, String questionNumber) {
+        markTrackDao.deleteByStudentIdAndQuestionNumber(studentId, questionNumber);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamId(Integer examId) {
+        markTrackDao.deleteByExamId(examId);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByExamAndSubjectAndGroup(Integer examId, String subjectCode, Integer number) {
+        markTrackDao.deleteByExamIdAndSubjectCodeAndGroupNumber(examId, subjectCode, number);
+    }
+
+    @Transactional
+    @Override
+    public void deleteByMarkerId(Integer markerId) {
+        markTrackDao.deleteByMarkerId(markerId);
+    }
+
+    @Override
+    public List<MarkTrack> findByStudentIdAndGroupNumber(Integer studentId, Integer number) {
+        return markTrackDao.findByPkStudentIdAndGroupNumber(studentId, number);
+    }
+}

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

@@ -0,0 +1,292 @@
+package cn.com.qmth.stmms.biz.mark.service.Impl;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
+import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
+import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
+import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
+import cn.com.qmth.stmms.biz.mark.model.MarkStepDTO;
+import cn.com.qmth.stmms.biz.mark.model.MarkTrack;
+import cn.com.qmth.stmms.biz.mark.model.Task;
+import cn.com.qmth.stmms.biz.mark.model.TrackDTO;
+import cn.com.qmth.stmms.biz.mark.query.MarkLibrarySearchQuery;
+import cn.com.qmth.stmms.biz.mark.service.MarkLibraryService;
+import cn.com.qmth.stmms.biz.mark.service.MarkTrackService;
+import cn.com.qmth.stmms.biz.mark.service.TaskService;
+import cn.com.qmth.stmms.biz.utils.CurrentTaskUtil;
+import cn.com.qmth.stmms.biz.utils.ScoreItem;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+import cn.com.qmth.stmms.common.utils.PictureUrlBuilder;
+
+/**
+ * 评卷任务服务实现
+ * 
+ * @author LS
+ * 
+ */
+@Service("taskService")
+public class TaskServiceImpl implements TaskService {
+
+    private static Logger log = LoggerFactory.getLogger(TaskServiceImpl.class);
+
+    @Autowired
+    private MarkLibraryService libraryService;
+
+    @Autowired
+    private ExamStudentService studentService;
+
+    @Autowired
+    private ExamQuestionService questionService;
+
+    @Autowired
+    private MarkTrackService trackService;
+
+    @Autowired
+    private MarkGroupService groupService;
+
+    @Override
+    public List<Task> findByQuery(MarkLibrarySearchQuery query) {
+        List<Task> list = new LinkedList<Task>();
+        query = libraryService.findByQuery(query);
+        if (query.getCurrentCount() > 0) {
+            for (MarkLibrary library : query.getResult()) {
+                list.add(build(library));
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public Task build(MarkLibrary library) {
+        ExamStudent student = studentService.findByExamIdAndExamNumber(library.getExamId(), library.getExamNumber());
+        MarkGroup group = groupService.findOne(library.getExamId(), library.getSubjectCode(), library.getGroupNumber());
+        Task task = new Task();
+        task.setExist(true);
+        task.setStudentId(library.getExamNumber());
+        task.setLibraryId(library.getId());
+        task.setMarkStepList(buildMarkStep(library));
+        task.setPictureUrls(PictureUrlBuilder.getSliceUrls(library.getExamId(), library.getCampusId(),
+                library.getSubjectCode(), library.getExamNumber(), group.getPicNumbers()));
+        task.setSheetUrls(PictureUrlBuilder.getSheetUrls(library.getExamId(), library.getCampusId(),
+                library.getSubjectCode(), library.getExamNumber(), student.getSheetCount()));
+        task.setAnswerUrl(PictureUrlBuilder.getAnswerUrl(library.getExamId(), library.getSubjectCode()));
+        task.setPaperUrl(PictureUrlBuilder.getPaperUrl(library.getExamId(), library.getSubjectCode()));
+        task.setObjectiveScore(student != null ? student.getObjectiveScore() : 0);
+        task.setMarkTime(library.getMarkerTime());
+        task.setTags(library.getTags());
+        if (library.getMarkerId() != null) {
+            task.setMarkId(library.getMarkerId());
+        }
+        if (library.getMarkerScore() != null) {
+            task.setTotalScore(library.getMarkerScore());
+        }
+        if (library.getMarkerScoreList() != null) {
+            task.setScoreList(library.getMarkerScoreList());
+        }
+        if (library.getStatus() == LibraryStatus.BACKED && library.getMarkerId() != null) {
+            task.setBack(true);
+        }
+        return task;
+    }
+
+    private List<MarkStepDTO> buildMarkStep(MarkLibrary library) {
+        List<MarkStepDTO> list = new LinkedList<MarkStepDTO>();
+        List<ExamQuestion> sList = questionService.findByExamAndSubjectAndObjectiveAndMainNumber(library.getExamId(),
+                library.getSubjectCode(), false, library.getGroupNumber());
+        int number = 0;
+        for (ExamQuestion question : sList) {
+            number++;
+
+            MarkStepDTO step = new MarkStepDTO();
+            step.setQuestionNumber(question.getQuestionNumber());
+            step.setBlockId(question.getMainNumber());
+            step.setNumber(number);
+            step.setTitle(question.getMainTitle() + "-" + question.getSubNumber());
+            step.setTotalScore(question.getTotalScore());
+            step.setDefaultScore(0d);
+            step.setHasLevel(false);
+            step.setMax(question.getTotalScore());
+            step.setMin(0d);
+            step.setInterval(question.getIntervalScore());
+            step.setScoreList(question.getScoreListArray());
+            // 增加阅卷轨迹列表获取
+            addTrack(step, question, trackService.findByStudentId(library.getStudentId()));
+            list.add(step);
+        }
+        return list;
+    }
+
+    private void addTrack(MarkStepDTO step, ExamQuestion question, List<MarkTrack> trackList) {
+        String questionNumber = question.getQuestionNumber();
+        for (MarkTrack track : trackList) {
+            if (track.getQuestionNumber().equals(questionNumber)) {
+                step.addTrack(new TrackDTO(track));
+            }
+        }
+    }
+
+    @Override
+    @Transactional
+    public boolean submit(Task task) {
+        if (task == null) {
+            return false;
+        }
+        try {
+            submitLibrary(task);
+            return true;
+        } catch (Exception e) {
+            log.error("task submit faile", e);
+            return false;
+        }
+    }
+
+    private void submitLibrary(Task task) {
+        MarkLibrary library = updateLibrary(task);
+        if (library == null) {
+            return;
+        }
+        // 同步操作
+        if (task.isProblem()) {
+            // ProblemLibrary library = new ProblemLibrary();
+            // library.setExamId(formallyLibrary.getExamId());
+            // library.setCampusCode(formallyLibrary.getCampusCode());
+            // library.setSubjectCode(formallyLibrary.getSubjectCode());
+            // library.setLibraryId(formallyLibrary.getId());
+            // library.setType(LibraryType.FORMALLY);
+            // library.setBlockId(formallyLibrary.getBlockId());
+            // library.setSecretNo(formallyLibrary.getSecretNo());
+            // library.setReason(task.getReason());
+            // library.setSubmitTime(new Date());
+            // library.setSubmitter(task.getMarkId());
+            // library.setStage(formallyLibrary.getMarkerCount());
+            // library.setStatus(LibraryStatus.WAITING);
+            // problemLibraryService.save(library);
+        } else {
+            // FormallyHistory history = new FormallyHistory();
+            // history.setLibraryId(task.getLibraryId());
+            // history.setScoreList(task.getScoreList());
+            // history.setScorer(task.getMarkId());
+            // history.setScoreTime(new Date());
+            // history.setSpent(task.getSpent());
+            // history.setStage(task.getMarkerCount());
+            // history.setTotalScore(task.getTotalScore());
+            // if (task.isSelf()) {
+            // history.setType(HistoryType.SELF);
+            // } else if (task.isBack()) {
+            // history.setType(HistoryType.BACK);
+            // } else {
+            // history.setType(HistoryType.COMMON);
+            // BlockTaskCountUtil.addBlockMarkedTask(stringRedisTemplate,
+            // task.getBlockId(), task.getLibraryId());
+            // }
+            // formallyHistoryService.save(history);
+
+            onTaskSubmit(library, task);
+        }
+    }
+
+    private void onTaskSubmit(MarkLibrary library, Task task) {
+        if (library.getStatus() == LibraryStatus.MARKED) {
+            // ExamStudent student =
+            // studentService.findById(library.getStudentId());
+            // if (student != null) {
+            // student.setSubjectiveScore(library.getMarkerScore());
+            // student.setScoreList(library.getScoreList(), false);
+            // studentService.save(student);
+            // }
+            List<MarkGroup> groups = groupService.findByExamAndSubject(library.getExamId(), library.getSubjectCode());
+            List<MarkLibrary> libraries = libraryService.findByStudentIdAndStatus(library.getStudentId(),
+                    LibraryStatus.MARKED);
+            if (libraries.size() == groups.size()) {
+                List<ScoreItem> scoreList = new ArrayList<ScoreItem>();
+                Double markerScore = 0.0;
+                for (MarkLibrary librarie : libraries) {
+                    scoreList.addAll(librarie.getScoreList());
+                    markerScore = markerScore + librarie.getMarkerScore();
+                }
+                studentService.updateSubjectiveScore(library.getStudentId(), markerScore,
+                        ExamStudent.buildScoreList(scoreList));
+            }
+
+            groupService.updateLibraryCount(library.getExamId(), library.getSubjectCode(), library.getGroupNumber());
+
+            Map<String, List<TrackDTO>> trackMap = task.getTrackMap();
+            for (String questionNumber : trackMap.keySet()) {
+                trackService.deleteByStudentIdAndQuestionNumber(library.getStudentId(), questionNumber);
+                List<TrackDTO> list = trackMap.get(questionNumber);
+                for (TrackDTO dto : list) {
+                    trackService.save(dto.transform(library));
+                }
+            }
+        }
+    }
+
+    /**
+     * 保存评卷任务
+     * 
+     * @param task
+     * @return
+     */
+    private MarkLibrary updateLibrary(Task task) {
+        MarkLibrary library = libraryService.findById(task.getLibraryId());
+        if (library != null) {
+            library.setMarkerId(task.getMarkId());
+            library.setMarkerTime(new Date());
+            library.setTags(StringUtils.trimToNull(task.getTags()));
+            library.setStatus(LibraryStatus.MARKED);
+            if (!task.isProblem()) {
+                library.setMarkerScore(task.getTotalScore());
+                library.setMarkerScoreList(task.getScoreList());
+            }
+            return libraryService.save(library);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public boolean setCurrent(Marker marker, int libraryId) {
+        return CurrentTaskUtil.add(marker, libraryId);
+    }
+
+    @Override
+    public void removeCurrent(Marker marker, int libraryId) {
+        CurrentTaskUtil.remove(marker, libraryId);
+    }
+
+    @Override
+    public int countCurrent(int examId, String subjectCode, int number) {
+        return CurrentTaskUtil.count(examId, subjectCode, number);
+    }
+
+    @Override
+    public int countCurrent(Marker marker) {
+        return CurrentTaskUtil.count(marker);
+    }
+
+    @Override
+    public void clearCurrent(int examId, String subjectCode, int number) {
+        CurrentTaskUtil.clear(examId, subjectCode, number);
+    }
+
+    @Override
+    public void clearCurrent(Marker marker) {
+        CurrentTaskUtil.clear(marker);
+    }
+}

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

@@ -0,0 +1,56 @@
+package cn.com.qmth.stmms.biz.mark.service;
+
+import java.util.List;
+import java.util.Set;
+
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
+import cn.com.qmth.stmms.biz.mark.query.MarkLibrarySearchQuery;
+import cn.com.qmth.stmms.common.enums.LibraryStatus;
+
+public interface MarkLibraryService {
+
+    MarkLibrary save(MarkLibrary library);
+
+    MarkLibrary findById(int id);
+
+    List<MarkLibrary> findByStudentId(int studentId);
+
+    long countByQuery(MarkLibrarySearchQuery query);
+
+    MarkLibrarySearchQuery findByQuery(MarkLibrarySearchQuery query);
+
+    List<MarkLibrary> findByStatus(int examId, String subjectCode, int groupNumber, LibraryStatus status,
+            int pageNumber, int pageSize);
+
+    List<MarkLibrary> findByStatusSet(int examId, String subjectCode, int groupNumber, Set<LibraryStatus> statusSet,
+            int pageNumber, int pageSize);
+
+    void resetByMarker(Marker marker);
+
+    void resetById(int id);
+
+    void backById(int id);
+
+    void delete(MarkLibrary library);
+
+    void deleteByStudent(int studentId);
+
+    long countByExamAndSubjectAndGroupAndStatus(int examId, String subjectCode, int groupNumber, LibraryStatus status);
+
+    long countByMarker(int markerId);
+
+    List<Integer> findTagCampusId(int examId);
+
+    List<String> findTagSubjectCode(int examId);
+
+    MarkLibrary findByStudentAndGroup(int studentId, int groupNumber);
+
+    List<MarkLibrary> findByStudentIdAndStatus(int studentId, LibraryStatus status);
+
+    void resetByGroup(MarkGroup group);
+
+    void deleteByGroup(MarkGroup group);
+
+}

+ 25 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/MarkTrackService.java

@@ -0,0 +1,25 @@
+package cn.com.qmth.stmms.biz.mark.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.mark.model.MarkTrack;
+
+public interface MarkTrackService {
+
+    MarkTrack save(MarkTrack track);
+
+    List<MarkTrack> findByStudentId(Integer studentId);
+
+    void deleteByStudentId(Integer studentId);
+
+    void deleteByStudentIdAndQuestionNumber(Integer studentId, String questionNumber);
+
+    void deleteByExamId(Integer examId);
+
+    void deleteByMarkerId(Integer markerId);
+
+    List<MarkTrack> findByStudentIdAndGroupNumber(Integer studentId, Integer number);
+
+    void deleteByExamAndSubjectAndGroup(Integer examId, String subjectCode, Integer number);
+
+}

+ 29 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/TaskService.java

@@ -0,0 +1,29 @@
+package cn.com.qmth.stmms.biz.mark.service;
+
+import java.util.List;
+
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.biz.mark.model.MarkLibrary;
+import cn.com.qmth.stmms.biz.mark.model.Task;
+import cn.com.qmth.stmms.biz.mark.query.MarkLibrarySearchQuery;
+
+public interface TaskService {
+
+    boolean submit(Task task);
+
+    List<Task> findByQuery(MarkLibrarySearchQuery query);
+
+    Task build(MarkLibrary library);
+
+    boolean setCurrent(Marker marker, int libraryId);
+
+    void removeCurrent(Marker marker, int libraryId);
+
+    int countCurrent(int examId, String subjectCode, int number);
+
+    int countCurrent(Marker marker);
+
+    void clearCurrent(int examId, String subjectCode, int number);
+
+    void clearCurrent(Marker marker);
+}

+ 10 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/dao/SchoolDao.java

@@ -0,0 +1,10 @@
+package cn.com.qmth.stmms.biz.school.dao;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.school.model.School;
+
+public interface SchoolDao extends PagingAndSortingRepository<School, Integer>,
+        JpaSpecificationExecutor<School> {
+}

+ 160 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/model/School.java

@@ -0,0 +1,160 @@
+package cn.com.qmth.stmms.biz.school.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "b_school")
+public class School implements Serializable {
+
+    private static final long serialVersionUID = -241744624240739912L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 省份
+     */
+    private String province;
+
+    /**
+     * 城市
+     */
+    private String city;
+
+    /**
+     * 地址
+     */
+    private String address;
+
+    /**
+     * 电话
+     */
+    private String phone;
+
+    /**
+     * 图片地址、名称
+     */
+    @Column(name = "logo_url")
+    private String logoUrl;
+
+    /**
+     * 描述
+     */
+    private String description;
+
+    /**
+     * 是否启用
+     */
+    private boolean enable;
+
+    @Column(name = "time_create")
+    private Date timeCreate;
+
+    @Column(name = "time_modified")
+    private Date timeModified;
+
+    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 String getProvince() {
+        return province;
+    }
+
+    public void setProvince(String province) {
+        this.province = province;
+    }
+
+    public String getCity() {
+        return city;
+    }
+
+    public void setCity(String city) {
+        this.city = city;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    public String getLogoUrl() {
+        return logoUrl;
+    }
+
+    public void setLogoUrl(String logoUrl) {
+        this.logoUrl = logoUrl;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public boolean isEnable() {
+        return enable;
+    }
+
+    public void setEnable(boolean enable) {
+        this.enable = enable;
+    }
+
+    public Date getTimeCreate() {
+        return timeCreate;
+    }
+
+    public void setTimeCreate(Date timeCreate) {
+        this.timeCreate = timeCreate;
+    }
+
+    public Date getTimeModified() {
+        return timeModified;
+    }
+
+    public void setTimeModified(Date timeModified) {
+        this.timeModified = timeModified;
+    }
+
+}

+ 37 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/query/SchoolSearchQuery.java

@@ -0,0 +1,37 @@
+package cn.com.qmth.stmms.biz.school.query;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.school.model.School;
+
+public class SchoolSearchQuery extends BaseQuery<School> {
+
+    private String name;
+
+    private String province;
+
+    private String city;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getProvince() {
+        return province;
+    }
+
+    public void setProvince(String province) {
+        this.province = province;
+    }
+
+    public String getCity() {
+        return city;
+    }
+
+    public void setCity(String city) {
+        this.city = city;
+    }
+}

+ 18 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/service/SchoolService.java

@@ -0,0 +1,18 @@
+package cn.com.qmth.stmms.biz.school.service;
+
+import cn.com.qmth.stmms.biz.school.model.School;
+import cn.com.qmth.stmms.biz.school.query.SchoolSearchQuery;
+
+public interface SchoolService {
+
+    School save(School school);
+
+    School findById(Integer id);
+
+    public SchoolSearchQuery findByQuery(final SchoolSearchQuery query);
+
+    void deleteById(Integer id);
+
+    void delete(School school);
+
+}

+ 80 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/school/service/impl/SchoolServiceImpl.java

@@ -0,0 +1,80 @@
+package cn.com.qmth.stmms.biz.school.service.impl;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.common.BaseQueryService;
+import cn.com.qmth.stmms.biz.school.dao.SchoolDao;
+import cn.com.qmth.stmms.biz.school.model.School;
+import cn.com.qmth.stmms.biz.school.query.SchoolSearchQuery;
+import cn.com.qmth.stmms.biz.school.service.SchoolService;
+
+@Service("schoolService")
+public class SchoolServiceImpl extends BaseQueryService<School> implements SchoolService {
+
+    @Autowired
+    public SchoolDao schoolDao;
+
+    @Override
+    public School findById(Integer id) {
+        return schoolDao.findOne(id);
+    }
+
+    public SchoolSearchQuery findByQuery(final SchoolSearchQuery query) {
+        checkQuery(query);
+        Page<School> result = schoolDao.findAll(new Specification<School>() {
+
+            @Override
+            public Predicate toPredicate(Root<School> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (StringUtils.isNotBlank(query.getName())) {
+                    predicates.add(cb.like(root.get("name").as(String.class), query.getName() + "%"));
+                }
+                if (StringUtils.isNotBlank(query.getProvince())) {
+                    predicates.add(cb.equal(root.get("province"), query.getProvince()));
+                }
+                if (StringUtils.isNotBlank(query.getCity())) {
+                    predicates.add(cb.equal(root.get("city"), query.getCity()));
+                }
+                return predicates.isEmpty() ? cb.conjunction() : cb.and(predicates.toArray(new Predicate[predicates
+                        .size()]));
+            }
+
+        }, query);
+        fillResult(result, query);
+        return query;
+    }
+
+    @Transactional
+    public School save(School school) {
+        if (school.getId() != null && school.getId() > 0) {
+            school.setTimeModified(new Date());
+        } else {
+            school.setTimeCreate(new Date());
+        }
+        return schoolDao.save(school);
+    }
+
+    @Transactional
+    public void deleteById(Integer id) {
+        schoolDao.delete(id);
+    }
+
+    @Transactional
+    public void delete(School school) {
+        schoolDao.delete(school);
+    }
+}

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

@@ -0,0 +1,23 @@
+package cn.com.qmth.stmms.biz.user.dao;
+
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.common.enums.Role;
+
+public interface UserDao extends PagingAndSortingRepository<User, Integer>, JpaSpecificationExecutor<User> {
+
+    public List<User> findByLoginName(String LoginName);
+
+    public List<User> findByLoginNameAndPassword(String LoginName, String password);
+
+    public List<User> findBySchoolId(int schoolId);
+
+    public List<User> findBySchoolIdAndRole(int schoolId, Role role);
+
+    public List<User> findBySchoolIdAndRoleIn(int schoolId, Set<Role> roleSet);
+}

+ 186 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/model/User.java

@@ -0,0 +1,186 @@
+package cn.com.qmth.stmms.biz.user.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import cn.com.qmth.stmms.common.enums.Role;
+
+@Entity
+@Table(name = "b_user")
+public class User implements Serializable {
+
+    private static final long serialVersionUID = -2094897723165518198L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue
+    private Integer id;
+
+    /**
+     * 登录名
+     */
+    @Column(name = "login_name")
+    private String loginName;
+
+    /**
+     * 名称
+     */
+    @Column(name = "name")
+    private String name;
+
+    /**
+     * 密码
+     */
+    @Column(name = "password")
+    private String password;
+
+    /**
+     * 角色
+     */
+    @Column(name = "role", length = 16, nullable = false)
+    @Enumerated(EnumType.STRING)
+    private Role role;
+
+    /**
+     * 状态
+     */
+    @Column(name = "enable")
+    private boolean enable;
+
+    /**
+     * 所属学校ID
+     */
+    @Column(name = "school_id")
+    private Integer schoolId;
+
+    /**
+     * 绑定科目代码
+     */
+    @Column(name = "subject_code")
+    private String subjectCode;
+
+    /**
+     * 最后一次登录时间
+     */
+    @Column(name = "last_login_time")
+    private Date lastLoginTime;
+
+    /**
+     * 最后一次登录IP
+     */
+    @Column(name = "last_login_ip")
+    private String lastLoginIp;
+
+    @Column(name = "created_time", nullable = false)
+    private Date createdTime;
+
+    @Column(name = "updated_time")
+    private Date updatedTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    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 Role getRole() {
+        return role;
+    }
+
+    public void setRole(Role role) {
+        this.role = role;
+    }
+
+    public Integer getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Integer schoolId) {
+        this.schoolId = schoolId;
+    }
+
+    public Date getLastLoginTime() {
+        return lastLoginTime;
+    }
+
+    public void setLastLoginTime(Date lastLoginTime) {
+        this.lastLoginTime = lastLoginTime;
+    }
+
+    public String getLastLoginIp() {
+        return lastLoginIp;
+    }
+
+    public void setLastLoginIp(String lastLoginIp) {
+        this.lastLoginIp = lastLoginIp;
+    }
+
+    public Date getCreatedTime() {
+        return createdTime;
+    }
+
+    public void setCreatedTime(Date createdTime) {
+        this.createdTime = createdTime;
+    }
+
+    public Date getUpdatedTime() {
+        return updatedTime;
+    }
+
+    public void setUpdatedTime(Date updatedTime) {
+        this.updatedTime = updatedTime;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public boolean isEnable() {
+        return enable;
+    }
+
+    public void setEnable(boolean enable) {
+        this.enable = enable;
+    }
+
+}

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

@@ -0,0 +1,34 @@
+package cn.com.qmth.stmms.biz.user.service;
+
+import java.util.List;
+import java.util.Set;
+
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.biz.user.service.query.UserSearchQuery;
+import cn.com.qmth.stmms.common.enums.Role;
+
+public interface UserService {
+
+    User findByLoginName(String loginName);
+
+    List<User> findByLoginNameAndPassword(String loginName, String password);
+
+    User findById(Integer id);
+
+    public List<User> findBySchoolIdAndRole(int schoolId, Role role);
+
+    public List<User> findBySchoolIdAndRoleSet(int schoolId, Set<Role> roleSet);
+
+    public UserSearchQuery findByQuery(final UserSearchQuery query);
+
+    public User save(User user);
+
+    public void deleteById(int id);
+
+    public void delete(User user);
+
+    public User findSchoolAdmin(int schoolId);
+
+	public User findSchoolViewer(Integer schoolId);
+
+}

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

@@ -0,0 +1,162 @@
+package cn.com.qmth.stmms.biz.user.service.impl;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import cn.com.qmth.stmms.biz.user.dao.UserDao;
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.biz.user.service.UserService;
+import cn.com.qmth.stmms.biz.user.service.query.UserSearchQuery;
+import cn.com.qmth.stmms.common.enums.Role;
+
+/**
+ * 用户Service
+ * 
+ * @author LS
+ * 
+ */
+@Service("userService")
+public class UserServiceImpl implements UserService {
+
+    @Autowired
+    private UserDao userDao;
+
+    @Override
+    public User findByLoginName(String loginName) {
+        List<User> list = userDao.findByLoginName(loginName);
+        return list != null && list.size() > 0 ? list.get(0) : null;
+    }
+
+    @Override
+    public List<User> findByLoginNameAndPassword(String loginName, String password) {
+        return userDao.findByLoginNameAndPassword(loginName, password);
+    }
+
+    public List<User> findBySchoolIdAndRole(int schoolId, Role role) {
+        return userDao.findBySchoolIdAndRole(schoolId, role);
+    }
+
+    public List<User> findBySchoolIdAndRoleSet(int schoolId, Set<Role> roleSet) {
+        return userDao.findBySchoolIdAndRoleIn(schoolId, roleSet);
+    }
+
+    public User findById(Integer id) {
+        return userDao.findOne(id);
+    }
+
+    public User findSchoolAdmin(int schoolId) {
+        UserSearchQuery query = new UserSearchQuery();
+        query.setSchoolId(schoolId);
+        query.addIncludeRole(Role.SCHOOL_ADMIN);
+        query.setPageNumber(1);
+        query.setPageSize(1);
+        query = findByQuery(query);
+        if (query.getCurrentCount() > 0) {
+            return query.getResult().get(0);
+        } else {
+            return null;
+        }
+    }
+
+    public UserSearchQuery findByQuery(final UserSearchQuery query) {
+        if (query.getPageNumber() < 1) {
+            query.setPageNumber(1);
+        }
+        if (query.getPageSize() < 1) {
+            query.setPageSize(10);
+        }
+
+        Page<User> result = userDao.findAll(new Specification<User>() {
+
+            @Override
+            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> cQuery, CriteriaBuilder cb) {
+                List<Predicate> predicates = new LinkedList<Predicate>();
+                if (query.getSchoolId() > 0) {
+                    predicates.add(cb.equal(root.get("schoolId"), query.getSchoolId()));
+                }
+                if (StringUtils.isNotBlank(query.getLoginName())) {
+                    predicates.add(cb.like(root.get("loginName").as(String.class), query.getLoginName() + "%"));
+                }
+                if (StringUtils.isNotBlank(query.getName())) {
+                    predicates.add(cb.like(root.get("name").as(String.class), query.getName() + "%"));
+                }
+                if (query.getEnable() != null) {
+                    predicates.add(cb.equal(root.get("enable"), query.getEnable()));
+                }
+                if (query.getRole() != null) {
+                    predicates.add(cb.equal(root.get("role"), query.getRole()));
+                }
+                if (query.getIncludeRoles() != null && query.getIncludeRoles().size() > 0) {
+                    for (Role role : query.getIncludeRoles()) {
+                        predicates.add(cb.equal(root.get("role"), role));
+                    }
+                }
+                return predicates.isEmpty() ? cb.conjunction()
+                        : cb.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        }, query);
+        if (result != null) {
+            query.setTotalCount(result.getTotalElements());
+            query.setTotalPage(result.getTotalPages());
+            query.setResult(result.getContent());
+            query.setCurrentCount(result.getNumberOfElements());
+        } else {
+            query.setTotalCount(0);
+            query.setTotalPage(0);
+            query.setCurrentCount(0);
+        }
+        return query;
+    }
+
+    @Transactional
+    public User save(User user) {
+        if (user.getId() != null && user.getId() > 0) {
+            user.setUpdatedTime(new Date());
+        } else {
+            user.setCreatedTime(new Date());
+        }
+        return userDao.save(user);
+    }
+
+    @Transactional
+    public void deleteById(int id) {
+        userDao.delete(id);
+    }
+
+    @Transactional
+    public void delete(User user) {
+        if (user != null) {
+            userDao.delete(user);
+        }
+    }
+
+	@Override
+	public User findSchoolViewer(Integer schoolId) {
+        UserSearchQuery query = new UserSearchQuery();
+        query.setSchoolId(schoolId);
+        query.addIncludeRole(Role.SCHOOL_VIEWER);
+        query.setPageNumber(1);
+        query.setPageSize(1);
+        query = findByQuery(query);
+        if (query.getCurrentCount() > 0) {
+            return query.getResult().get(0);
+        } else {
+            return null;
+        }
+	}
+
+}

+ 77 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/user/service/query/UserSearchQuery.java

@@ -0,0 +1,77 @@
+package cn.com.qmth.stmms.biz.user.service.query;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import cn.com.qmth.stmms.biz.common.BaseQuery;
+import cn.com.qmth.stmms.biz.user.model.User;
+import cn.com.qmth.stmms.common.enums.Role;
+
+public class UserSearchQuery extends BaseQuery<User> {
+
+    private int schoolId;
+
+    private String loginName;
+
+    private String name;
+
+    private Role role;
+
+    private Boolean enable;
+
+    private Set<Role> includeRoles;
+
+    public int getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(int schoolId) {
+        this.schoolId = schoolId;
+    }
+
+    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 Set<Role> getIncludeRoles() {
+        return includeRoles;
+    }
+
+    public void addIncludeRole(Role role) {
+        if (includeRoles == null) {
+            includeRoles = new HashSet<Role>();
+        }
+        if (role != null) {
+            includeRoles.add(role);
+        }
+    }
+
+    public Role getRole() {
+        return role;
+    }
+
+    public void setRole(Role role) {
+        this.role = role;
+    }
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+}

+ 52 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/AbstractTask.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.stmms.biz.utils;
+
+import java.util.Date;
+
+import org.apache.log4j.Logger;
+
+public abstract class AbstractTask implements Runnable {
+
+    protected static final Logger logger = Logger.getLogger(AbstractTask.class);
+
+    private Date start;
+
+    private Date finish;
+
+    private String status;
+
+    public AbstractTask() {
+        status("等待开始");
+    }
+
+    @Override
+    public void run() {
+        logger.info("运行中");
+        start = new Date();
+        status("运行中");
+
+        process();
+
+        status("任务结束");
+        finish = new Date();
+        logger.info("任务结束");
+    }
+
+    protected abstract void process();
+
+    protected void status(String status) {
+        this.status = status;
+    }
+
+    public Date getStart() {
+        return start;
+    }
+
+    public Date getFinish() {
+        return finish;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+}

+ 34 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/BlockTaskCountUtil.java

@@ -0,0 +1,34 @@
+package cn.com.qmth.stmms.biz.utils;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+import cn.com.qmth.stmms.common.redis.RedisKeyBuilder;
+
+public class BlockTaskCountUtil {
+
+    public static void incrBlockTotalCount(StringRedisTemplate redisTemplate, final int blockId) {
+        redisTemplate.execute(new RedisCallback<Long>() {
+
+            @Override
+            public Long doInRedis(RedisConnection conn) throws DataAccessException {
+                try {
+                    conn.incr(RedisKeyBuilder.getBlockTotalCountKey(blockId).getBytes("UTF-8"));
+                } catch (Exception e) {
+                }
+                return 0l;
+            }
+        });
+    }
+
+    public static void addBlockMarkedTask(StringRedisTemplate redisTemplate, final int blockId, final int libraryId) {
+        redisTemplate.opsForSet().add(RedisKeyBuilder.getBlockMarkedTaskKey(blockId), String.valueOf(libraryId));
+    }
+
+    public static int getBlockMarkedTaskCount(StringRedisTemplate redisTemplate, final int blockId) {
+        Long count = redisTemplate.opsForSet().size(RedisKeyBuilder.getBlockMarkedTaskKey(blockId));
+        return count != null ? count.intValue() : 0;
+    }
+}

+ 156 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/CurrentTaskUtil.java

@@ -0,0 +1,156 @@
+package cn.com.qmth.stmms.biz.utils;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
+
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+
+/**
+ * Redis zset替代方案,单JVM内部针对已领取未给分任务的管理工具
+ * 
+ * @author luoshi
+ * 
+ */
+public class CurrentTaskUtil {
+
+    private static SetMultimap<String, TaskEntry> taskMap = HashMultimap.create();
+
+    /**
+     * 尝试领取某个任务
+     * 
+     * @param marker
+     * @param libraryId
+     * @return
+     */
+    public static boolean add(Marker marker, int libraryId) {
+        String key = getKey(marker);
+        TaskEntry obj = new TaskEntry(marker.getId(), libraryId);
+
+        synchronized (CurrentTaskUtil.class) {
+            if (taskMap.containsEntry(key, obj)) {
+                return false;
+            } else {
+                taskMap.put(key, obj);
+                return true;
+            }
+        }
+    }
+
+    /**
+     * 删除某个已完成的任务
+     * 
+     * @param marker
+     * @param libraryId
+     */
+    public static void remove(Marker marker, int libraryId) {
+        TaskEntry obj = new TaskEntry(marker.getId(), libraryId);
+        synchronized (CurrentTaskUtil.class) {
+            taskMap.remove(getKey(marker), obj);
+        }
+    }
+
+    /**
+     * 某个科目已领取未给分的任务总数
+     * 
+     * @param examId
+     * @param subjectCode
+     * @return
+     */
+    public static int count(int examId, String subjectCode, int number) {
+        Set<TaskEntry> set = taskMap.get(getKey(examId, subjectCode, number));
+        return set != null ? set.size() : 0;
+    }
+
+    /**
+     * 某个评卷员已领取未给分的任务总数
+     * 
+     * @param marker
+     * @return
+     */
+    public static int count(Marker marker) {
+        Set<TaskEntry> set = taskMap.get(getKey(marker));
+        int count = 0;
+        if (set != null) {
+            for (TaskEntry obj : set) {
+                if (obj.markerId == marker.getId()) {
+                    count++;
+                }
+            }
+        }
+        return count;
+    }
+
+    /**
+     * 清除某个科目已领取未给分的任务
+     * 
+     * @param examId
+     * @param subjectCode
+     */
+    public static void clear(int examId, String subjectCode, int number) {
+        synchronized (CurrentTaskUtil.class) {
+            taskMap.removeAll(getKey(examId, subjectCode, number));
+        }
+    }
+
+    /**
+     * 清除某个评卷员已领取未给分的任务
+     * 
+     * @param examId
+     * @param subjectCode
+     */
+    public static void clear(Marker marker) {
+        String key = getKey(marker);
+        Set<TaskEntry> set = new HashSet<TaskEntry>();
+        synchronized (CurrentTaskUtil.class) {
+            set.addAll(taskMap.get(key));
+            for (TaskEntry obj : set) {
+                if (obj.markerId == marker.getId()) {
+                    taskMap.remove(key, obj);
+                }
+            }
+        }
+    }
+
+    private static String getKey(int examId, String subjectCode, int number) {
+        return examId + "_" + subjectCode + "_" + number;
+    }
+
+    private static String getKey(Marker marker) {
+        return getKey(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
+    }
+}
+
+class TaskEntry {
+
+    int markerId;
+
+    int libraryId;
+
+    public TaskEntry(int markerId, int libraryId) {
+        this.markerId = markerId;
+        this.libraryId = libraryId;
+    }
+
+    @Override
+    public int hashCode() {
+        return libraryId;
+    }
+
+    @Override
+    public String toString() {
+        return markerId + "-" + libraryId;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj != null && obj instanceof TaskEntry) {
+            TaskEntry mt = (TaskEntry) obj;
+            return mt.libraryId == this.libraryId;
+        } else {
+            return false;
+        }
+    }
+}

+ 197 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/CurrentTaskUtil2.java

@@ -0,0 +1,197 @@
+package cn.com.qmth.stmms.biz.utils;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+
+/**
+ * Redis zset替代方案,单JVM内部针对已领取未给分任务的管理工具
+ * 
+ * @author luoshi
+ * 
+ */
+public class CurrentTaskUtil2 {
+
+    private static Map<String, TaskGroup> store = new HashMap<String, TaskGroup>();
+
+    /**
+     * 尝试领取某个任务
+     * 
+     * @param marker
+     * @param libraryId
+     * @return
+     */
+    public static boolean add(Marker marker, int libraryId) {
+        return getTaskMap(marker.getExamId(), marker.getSubjectCode()).add(libraryId, marker.getId());
+    }
+
+    /**
+     * 删除某个已完成的任务
+     * 
+     * @param marker
+     * @param libraryId
+     */
+    public static void remove(Marker marker, int libraryId) {
+        getTaskMap(marker.getExamId(), marker.getSubjectCode()).remove(libraryId);
+    }
+
+    /**
+     * 某个科目已领取未给分的任务总数
+     * 
+     * @param examId
+     * @param subjectCode
+     * @return
+     */
+    public static int count(int examId, String subjectCode) {
+        return getTaskMap(examId, subjectCode).count();
+    }
+
+    /**
+     * 某个评卷员已领取未给分的任务总数
+     * 
+     * @param marker
+     * @return
+     */
+    public static int count(Marker marker) {
+        return getTaskMap(marker.getExamId(), marker.getSubjectCode()).count(marker.getId());
+    }
+
+    /**
+     * 清除某个科目已领取未给分的任务
+     * 
+     * @param examId
+     * @param subjectCode
+     */
+    public static void clear(int examId, String subjectCode) {
+        getTaskMap(examId, subjectCode).clear();
+    }
+
+    /**
+     * 清除某个评卷员已领取未给分的任务
+     * 
+     * @param examId
+     * @param subjectCode
+     */
+    public static void clear(Marker marker) {
+        getTaskMap(marker.getExamId(), marker.getSubjectCode()).clear(marker.getId());
+    }
+
+    /**
+     * 获取某个科目的任务控制器
+     * 
+     * @param examId
+     * @param subjectCode
+     * @return
+     */
+    private static TaskGroup getTaskMap(int examId, String subjectCode) {
+        String key = examId + "_" + subjectCode;
+        TaskGroup group = store.get(key);
+        if (group == null) {
+            synchronized (CurrentTaskUtil2.class) {
+                group = store.get(key);
+                if (group == null) {
+                    group = new TaskGroup();
+                    store.put(key, group);
+                }
+            }
+        }
+        return group;
+    }
+}
+
+class TaskGroup {
+
+    // 任务-评卷员对应关系
+    private Map<Integer, Integer> taskStore;
+
+    // 评卷员-任务对应关系
+    private Map<Integer, Set<Integer>> markerStore;
+
+    private Lock lock;
+
+    public TaskGroup() {
+        this.taskStore = new HashMap<Integer, Integer>();
+        this.markerStore = new HashMap<Integer, Set<Integer>>();
+        this.lock = new ReentrantLock();
+    }
+
+    public boolean add(int libraryId, int markerId) {
+        if (taskStore.containsKey(libraryId)) {
+            return false;
+        }
+        lock.lock();
+        try {
+            if (taskStore.containsKey(libraryId)) {
+                return false;
+            }
+            taskStore.put(libraryId, markerId);
+            Set<Integer> set = markerStore.get(markerId);
+            if (set == null) {
+                set = new HashSet<Integer>();
+                markerStore.put(markerId, set);
+            }
+            set.add(libraryId);
+            return true;
+        } catch (Exception e) {
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public void remove(int libraryId) {
+        lock.lock();
+        try {
+            Integer markerId = taskStore.get(libraryId);
+            if (markerId != null) {
+                markerStore.get(markerId).remove(libraryId);
+            }
+            taskStore.remove(libraryId);
+        } catch (Exception e) {
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public int count() {
+        return taskStore.size();
+    }
+
+    public int count(int markerId) {
+        try {
+            return markerStore.get(markerId).size();
+        } catch (Exception e) {
+            return 0;
+        }
+    }
+
+    public void clear() {
+        lock.lock();
+        try {
+            taskStore.clear();
+            markerStore.clear();
+        } catch (Exception e) {
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public void clear(int markerId) {
+        lock.lock();
+        try {
+            Set<Integer> set = markerStore.get(markerId);
+            for (Integer id : set) {
+                taskStore.remove(id);
+            }
+            set.clear();
+        } catch (Exception e) {
+        } finally {
+            lock.unlock();
+        }
+    }
+}

+ 53 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/MarkRedisUtil.java

@@ -0,0 +1,53 @@
+package cn.com.qmth.stmms.biz.utils;
+
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+import cn.com.qmth.stmms.biz.exam.model.Marker;
+import cn.com.qmth.stmms.common.redis.RedisKeyBuilder;
+
+public class MarkRedisUtil {
+
+    public static void addCurrentTask(StringRedisTemplate redisTemplate, Marker marker, int libraryId) {
+        String key = getKey(marker);
+        redisTemplate.opsForZSet().add(key, String.valueOf(libraryId), marker.getId());
+    }
+
+    public static int countCurrentTask(StringRedisTemplate redisTemplate, int examId, String subjectCode, int number) {
+        String key = RedisKeyBuilder.getCurrentTaskKey(examId, subjectCode, number);
+        Long count = redisTemplate.opsForZSet().size(key);
+        return count != null ? count.intValue() : 0;
+    }
+
+    public static int countCurrentTask(StringRedisTemplate redisTemplate, Marker marker) {
+        String key = getKey(marker);
+        Long count = redisTemplate.opsForZSet().count(key, marker.getId() - 0.5, marker.getId() + 0.5);
+        return count != null ? count.intValue() : 0;
+    }
+
+    public static void removeCurrentTask(StringRedisTemplate redisTemplate, int examId, String subjectCode, int number,
+            int libraryId) {
+        String key = RedisKeyBuilder.getCurrentTaskKey(examId, subjectCode, number);
+        redisTemplate.opsForZSet().remove(key, String.valueOf(libraryId));
+    }
+
+    public static boolean isCurrentTask(StringRedisTemplate redisTemplate, int examId, String subjectCode, int number,
+            int libraryId) {
+        String key = RedisKeyBuilder.getCurrentTaskKey(examId, subjectCode, number);
+        Double score = redisTemplate.opsForZSet().score(key, String.valueOf(libraryId));
+        return score != null && score > 0;
+    }
+
+    public static void clearCurrentTask(StringRedisTemplate redisTemplate, Marker marker) {
+        String key = getKey(marker);
+        redisTemplate.opsForZSet().removeRangeByScore(key, marker.getId() - 0.5, marker.getId() + 0.5);
+    }
+
+    public static void clearCurrentTask(StringRedisTemplate redisTemplate, int examId, String subjectCode, int number) {
+        String key = RedisKeyBuilder.getCurrentTaskKey(examId, subjectCode, number);
+        redisTemplate.delete(key);
+    }
+
+    private static String getKey(Marker marker) {
+        return RedisKeyBuilder.getCurrentTaskKey(marker.getExamId(), marker.getSubjectCode(), marker.getGroupNumber());
+    }
+}

+ 85 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/PageModel.java

@@ -0,0 +1,85 @@
+package cn.com.qmth.stmms.biz.utils;
+
+/**
+ * 分页模型
+ * 
+ * @author zhengmin
+ * 
+ * @param <T>
+ */
+public class PageModel<T> {
+
+    private Integer page;// 当前页码
+
+    private Integer totalCount;// 总记录条数
+
+    private Integer pageCount;// 总页数
+
+    private Integer pageSize;// 每页显示多少
+
+    // private List<T> list;
+
+    // private List<T> pageList;
+
+    public PageModel(Integer page, Integer totalCount, Integer pageSize) {
+        this.page = page;
+        this.totalCount = totalCount;
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPage() {
+        return page;
+    }
+
+    public void setPage(Integer page) {
+        this.page = page;
+    }
+
+    public Integer getTotalCount() {
+        return totalCount;
+    }
+
+    public void setTotalCount(Integer totalCount) {
+        this.totalCount = totalCount;
+    }
+
+    public Integer getPageCount() {
+        pageCount = (int) totalCount / pageSize;
+        if (totalCount % pageSize > 0)
+            pageCount++;
+        return pageCount;
+    }
+
+    public void setPageCount(Integer pageCount) {
+        this.pageCount = pageCount;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public int[] getRange() {
+        if (page != null) {
+            int start = (page - 1) * pageSize;
+            int end = start + pageSize;
+            if (end > totalCount - 1) {
+                end = totalCount - 1;
+            }
+            return new int[] { start, end };
+        } else {
+            return null;
+        }
+    }
+
+    /*
+     * public List<T> getList() { return list; }
+     * 
+     * public void setList(List<T> list) { this.list = list; }
+     * 
+     * public List<T> getPageList() { return list.subList(getRange()[0],
+     * getRange()[1]); }
+     * 
+     * public void setPageList(List<T> pageList) { this.pageList = pageList; }
+     */
+
+}

+ 130 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/ScoreCalculateUtil.java

@@ -0,0 +1,130 @@
+package cn.com.qmth.stmms.biz.utils;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+
+public class ScoreCalculateUtil {
+
+    protected static Logger log = LoggerFactory.getLogger(ScoreCalculateUtil.class);
+
+    private ExamStudent student;
+
+    private ScoreCalculateUtil(ExamStudent student) {
+        this.student = student;
+    }
+
+    public ScoreInfo calculate(List<ExamQuestion> oList, List<ExamQuestion> sList) {
+        // log.debug("start calculate, examId=" + student.getExamId() +
+        // ", examNumber=" + student.getExamNumber());
+
+        ScoreInfo info = new ScoreInfo();
+        if (oList != null && oList.size() > 0) {
+            calculateObjective(oList, info);
+        }
+        if (sList != null && sList.size() > 0) {
+            calculateSubjective(sList, info);
+        }
+        return info;
+    }
+
+    private void calculateObjective(List<ExamQuestion> questionList, ScoreInfo scoreInfo) {
+        // log.debug("start calculate objective score");
+        List<String> answerList = student.getAnswerList();
+        // Map<String, Integer> config = exam.getObjectiveBlockMap();
+
+        // log.debug("student answers: " + student.getAnswers());
+        // log.debug("exam objective config: " + exam.getObjectiveBlock());
+
+        int index = -1;
+        int lastMainNumber = 0;
+        for (ExamQuestion question : questionList) {
+            // log.debug("find objective block for " + block.getTitle() +
+            // ", question start=" + start);
+            if (question.getMainNumber() != lastMainNumber) {
+                scoreInfo.incrMainNumber(question.getMainTitle());
+            }
+
+            index++;
+            String answer = "#";
+            double score = 0d;
+            try {
+                answer = answerList.get(index);
+            } catch (Exception e) {
+                continue;
+            }
+            boolean correct = true;
+            for (int i = 0; i < answer.length(); i++) {
+                if (!question.getAnswer().contains(String.valueOf(answer.charAt(i)))) {
+                    correct = false;
+                    break;
+                }
+            }
+            if (correct) {
+                score = answer.length() < question.getAnswer().length() ? 0 : question.getTotalScore();
+            }
+
+            // log.debug("question result: " + question.getNumber() + ", " +
+            // answer + ", " + score);
+            scoreInfo.addScore(null, question.getSubNumber(), score, answer, true);
+        }
+    }
+
+    private void calculateSubjective(List<ExamQuestion> sList, ScoreInfo scoreInfo) {
+
+    }
+
+    public static ScoreCalculateUtil instance(ExamStudent student) {
+        return new ScoreCalculateUtil(student);
+    }
+
+    public static void main(String[] args) {
+        ExamStudent student = new ExamStudent();
+        student.setAnswers("A,B,AB,C,#,#,#,#");
+        ScoreCalculateUtil util = ScoreCalculateUtil.instance(student);
+
+        List<ExamQuestion> oList = new LinkedList<ExamQuestion>();
+        ExamQuestion q = new ExamQuestion();
+        q.setMainNumber(1);
+        q.setMainTitle("单选");
+        q.setSubNumber(1);
+        q.setAnswer("B");
+        q.setTotalScore(2d);
+        oList.add(q);
+
+        q = new ExamQuestion();
+        q.setMainNumber(1);
+        q.setMainTitle("单选");
+        q.setSubNumber(2);
+        q.setAnswer("B");
+        q.setTotalScore(2d);
+        oList.add(q);
+
+        q = new ExamQuestion();
+        q.setMainNumber(2);
+        q.setMainTitle("多选");
+        q.setSubNumber(1);
+        q.setAnswer("AC");
+        q.setTotalScore(3d);
+        oList.add(q);
+
+        q = new ExamQuestion();
+        q.setMainNumber(2);
+        q.setMainTitle("多选");
+        q.setSubNumber(2);
+        q.setAnswer("C");
+        q.setTotalScore(3d);
+        oList.add(q);
+
+        ScoreInfo info = util.calculate(oList, null);
+        System.out.println(info.getObjectiveScore());
+        for (ScoreItem item : info.getScoreList()) {
+            System.out.println(item.getTitle() + ": " + item.toString());
+        }
+    }
+}

+ 81 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/utils/ScoreInfo.java

@@ -0,0 +1,81 @@
+package cn.com.qmth.stmms.biz.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ScoreInfo {
+
+    private int mainNumber;
+
+    private int subNumber;
+
+    private String mainTitle;
+
+    private double objectiveScore;
+
+    private double subjectiveScore;
+
+    private double totalScore;
+
+    private List<ScoreItem> scoreList;
+
+    public ScoreInfo() {
+        this.mainNumber = 0;
+        this.subNumber = 0;
+        this.objectiveScore = 0d;
+        this.subjectiveScore = 0d;
+        this.totalScore = 0d;
+        this.scoreList = new ArrayList<ScoreItem>();
+    }
+
+    public int incrMainNumber(String title) {
+        mainTitle = title;
+        mainNumber++;
+        subNumber = 0;
+        return mainNumber;
+    }
+
+    public void addScore(String title, int number, double score, String answer, boolean objective) {
+        subNumber++;
+
+        ScoreItem item = new ScoreItem(objective);
+        item.setMainNumber(mainNumber);
+        item.setSubNumber(number > 0 ? number : subNumber);
+        item.setTitle(title != null ? title : mainTitle + "-" + item.getSubNumber());
+        item.setAnswer(answer);
+        item.setScore(score);
+
+        scoreList.add(item);
+        totalScore += item.getScore();
+        if (item.isObjective()) {
+            objectiveScore += item.getScore();
+        } else {
+            subjectiveScore += item.getScore();
+        }
+    }
+
+    public double getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public double getSubjectiveScore() {
+        return subjectiveScore;
+    }
+
+    public double getTotalScore() {
+        return totalScore;
+    }
+
+    public List<ScoreItem> getScoreList() {
+        return scoreList;
+    }
+
+    public int getTotalCount() {
+        return scoreList.size();
+    }
+
+    public int getMainCount() {
+        return mainNumber;
+    }
+
+}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác