فهرست منبع

Merge remote-tracking branch 'remotes/origin/release_v4.1.0'

deason 3 سال پیش
والد
کامیت
46b23d2f60
57فایلهای تغییر یافته به همراه1018 افزوده شده و 673 حذف شده
  1. 41 10
      .gitignore
  2. 17 14
      examcloud-core-oe-admin-api-provider/pom.xml
  3. 22 2
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamAuditController.java
  4. 12 0
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamControlController.java
  5. 4 4
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/IllegallyTypeController.java
  6. 3 3
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/OfflineExamController.java
  7. 1 1
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamCourseCloudServiceProvider.java
  8. 62 89
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamRecordCloudServiceProvider.java
  9. 3 3
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamScoreDataCloudServiceProvider.java
  10. 4 4
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamScoreNoticeQueueCloudServiceProvider.java
  11. 2 2
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamStudentDataCloudServiceProvider.java
  12. 3 3
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/SyncExamDataCloudServiceProvider.java
  13. 123 123
      examcloud-core-oe-admin-base/pom.xml
  14. 0 17
      examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/Constants.java
  15. 6 2
      examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/jpa/Order.java
  16. 2 3
      examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/jpa/SpecUtils.java
  17. 6 6
      examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/utils/FileDisposeUtil.java
  18. 8 8
      examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/utils/HttpPoolUtil.java
  19. 4 4
      examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/utils/PagingAndSortingSpecification.java
  20. 18 16
      examcloud-core-oe-admin-dao/pom.xml
  21. 3 0
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/ExamRecordDataRepo.java
  22. 2 0
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/ExamStudentRepo.java
  23. 16 0
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/entity/ExamRecordDataEntity.java
  24. 2 0
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/enums/ExportTaskType.java
  25. 4 4
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/enums/FaceVerifyResult.java
  26. 17 15
      examcloud-core-oe-admin-service/pom.xml
  27. 4 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/AsyncExportService.java
  28. 8 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamAuditService.java
  29. 4 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamRecordDataService.java
  30. 8 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamRecordService.java
  31. 1 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamStudentService.java
  32. 15 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examaudit/ExamAuditInfo.java
  33. 10 1
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordEntityConvert.java
  34. 14 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordInfo.java
  35. 11 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordQuery.java
  36. 1 1
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examstudent/ExamStudentEntityConvert.java
  37. 49 30
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/exporttask/ExportTask.java
  38. 101 15
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/AsyncExportServiceImpl.java
  39. 108 56
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamAuditServiceImpl.java
  40. 4 4
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamCaptureServiceImpl.java
  41. 14 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordDataServiceImpl.java
  42. 54 7
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordServiceImpl.java
  43. 3 3
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamStudentFinalScoreServiceImpl.java
  44. 57 5
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamStudentServiceImpl.java
  45. 67 60
      examcloud-core-oe-admin-starter/pom.xml
  46. 1 1
      examcloud-core-oe-admin-starter/shell/start.args
  47. 8 24
      examcloud-core-oe-admin-starter/shell/start.sh
  48. 5 12
      examcloud-core-oe-admin-starter/shell/stop.sh
  49. 22 27
      examcloud-core-oe-admin-starter/src/main/java/cn/com/qmth/examcloud/core/oe/admin/stater/OEAdminApp.java
  50. 4 5
      examcloud-core-oe-admin-starter/src/main/java/cn/com/qmth/examcloud/core/oe/admin/stater/config/ExamCloudResourceManager.java
  51. 2 2
      examcloud-core-oe-admin-starter/src/main/java/cn/com/qmth/examcloud/core/oe/admin/stater/config/SwaggerConfig.java
  52. 5 5
      examcloud-core-oe-admin-starter/src/main/resources/application.properties
  53. 0 1
      examcloud-core-oe-admin-starter/src/main/resources/classpath.location
  54. 32 50
      examcloud-core-oe-admin-starter/src/main/resources/log4j2.xml
  55. 0 14
      examcloud-core-oe-admin-starter/src/main/resources/security-exclusions.conf
  56. 4 0
      jenkins.sh
  57. 17 17
      pom.xml

+ 41 - 10
.gitignore

@@ -1,19 +1,50 @@
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
 *.class
+*.log
 
-# Proguard folder generated by ide
-.project
+
+### Eclipse & STS ###
+.apt_generated
 .classpath
+.factorypath
+.project
 .settings
-target/
-.idea/
-*.iml
+.springBeans
+.sts4-cache
+
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
 
-# Log Files
-*.log
-*.class
 
+### VS Code ###
+.vscode
+node_modules
+package-lock.json
+yarn.lock
 
-# Package Files #
-*.jar
+
+### Package Files ###
+*.zip
 *.war
 *.ear
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+target/
+
+.flattened-pom.xml
+.DS_Store
+

+ 17 - 14
examcloud-core-oe-admin-api-provider/pom.xml

@@ -1,19 +1,22 @@
 <?xml version="1.0"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>cn.com.qmth.examcloud</groupId>
-		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>v4.0.2-RELEASE</version>
-	</parent>
-	<artifactId>examcloud-core-oe-admin-api-provider</artifactId>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+         xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-oe-admin-api-provider</artifactId>
+    <packaging>jar</packaging>
 
-	<dependencies>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud</groupId>
-			<artifactId>examcloud-core-oe-admin-service</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-oe-admin</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-core-oe-admin-service</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 22 - 2
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamAuditController.java

@@ -13,6 +13,8 @@ import java.util.Set;
 
 import javax.servlet.http.HttpServletResponse;
 
+import cn.com.qmth.examcloud.core.oe.admin.service.AsyncExportService;
+import cn.com.qmth.examcloud.core.oe.admin.service.util.AsyncExportConcurrentUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
@@ -72,6 +74,9 @@ public class ExamAuditController extends ControllerSupport {
     @Autowired
     private IllegallyTypeRepo illegallyTypeRepo;
 
+    @Autowired
+    private AsyncExportService asyncExportService;
+
     @PostMapping("/list")
     @ApiOperation(value = "查询“监考已审”列表(分页)")
     public Page<ExamAuditInfo> getExamAuditList(@RequestBody ExamAuditQuery query) {
@@ -85,6 +90,15 @@ public class ExamAuditController extends ControllerSupport {
         return examAuditList;
     }
 
+    @GetMapping("export/async")
+    @ApiOperation(value = "导出“监考已审”(异步)")
+    public void exportExamAuditList(@RequestParam String query) {
+        User user=getAccessUser();
+        asyncExportService.exportExamAuditList(query, user);
+        AsyncExportConcurrentUtil.checkOrStartJob();
+        ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), "监考已审-导出","导出条件:"+query));
+    }
+
     @PostMapping("/discipline/list")
     @ApiOperation(value = "查询“违纪名单”列表(分页)")
     public Page<ExamAuditInfo> getExamAuditUnPassList(@RequestBody ExamAuditQuery query) {
@@ -149,7 +163,11 @@ public class ExamAuditController extends ControllerSupport {
 
     @PostMapping(value = "/batch/audit")
     @ApiOperation(value = "监考待审-批量审核")
-    public void batchAudit(@RequestParam List<Long> examRecordDataIds, @RequestParam Boolean isPass) {
+    public void batchAudit(@RequestParam(required = true) List<Long> examRecordDataIds,
+                           @RequestParam(required = false) String disciplineDetail,
+                           @RequestParam(required = true) Boolean isPass,
+                           @RequestParam(required = false) String disciplineType,
+                           @RequestParam(required = false) Long illegallyTypeId) {
         if (examRecordDataIds == null || examRecordDataIds.size() == 0) {
             throw new StatusException("batchAudit-001", "examRecordDataIds不能为空");
         }
@@ -157,7 +175,9 @@ public class ExamAuditController extends ControllerSupport {
             throw new StatusException("batchAudit-002", "isPass不能为空");
         }
         User user = getAccessUser();
-        examAuditService.batchAudit(examRecordDataIds, isPass, user);
+        for (Long examRecordDataId : examRecordDataIds) {
+            examAuditService.singleAudit(examRecordDataId, isPass, disciplineDetail, disciplineType, user, illegallyTypeId);
+        }
         StringBuilder sb=new StringBuilder();
         if(isPass) {
         	sb.append("审核状态:通过");

+ 12 - 0
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamControlController.java

@@ -49,6 +49,18 @@ public class ExamControlController extends ControllerSupport {
         return examStudentService.queryOnlineExamList(user.getUserId(), ExamType.ONLINE);
     }
 
+    /**
+     * 获取在线考试已结束列表
+     *
+     * @return
+     */
+    @ApiOperation(value = "获取在线考试已结束列表")
+    @GetMapping("/queryExamEndList")
+    public List<OnHandExamInfo> queryExamEndList() {
+        User user = getAccessUser();
+        return examStudentService.queryOnlineExamEndList(user.getUserId(), ExamType.ONLINE);
+    }
+
     /**
      * 获取在线作业待考列表
      *

+ 4 - 4
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/IllegallyTypeController.java

@@ -119,7 +119,7 @@ public class IllegallyTypeController extends ControllerSupport {
         };
 
         PageRequest pageRequest = PageRequest.of(curPage, pageSize,
-                new Sort(Direction.DESC, "id"));
+                Sort.by(Direction.DESC, "id"));
 
 
         Page<IllegallyTypeEntity> page = illegallyTypeRepo.findAll(specification, pageRequest);
@@ -197,11 +197,11 @@ public class IllegallyTypeController extends ControllerSupport {
         }
 
         List<Sort.Order> orderList = new ArrayList<>();
-        orderList.add(new Sort.Order(Direction.DESC, "dataCategory"));
-        orderList.add(new Sort.Order(Direction.ASC, "id"));
+        orderList.add(Sort.Order.desc("dataCategory"));
+        orderList.add(Sort.Order.asc("id"));
 
         List<IllegallyTypeEntity> list = illegallyTypeRepo.findAll(specification,
-                new Sort(orderList));
+                Sort.by(orderList));
 
 
         if (StringUtils.isNotEmpty(queryScope) && queryScope.toLowerCase().equals("audit")) {

+ 3 - 3
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/OfflineExamController.java

@@ -8,6 +8,7 @@ import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamStudentService;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
@@ -27,7 +28,6 @@ import cn.com.qmth.examcloud.commons.util.MD5;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.Check;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
-import cn.com.qmth.examcloud.core.oe.admin.service.ExamStudentService;
 import cn.com.qmth.examcloud.core.oe.admin.service.OfflineExamService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.OfflineExamCourseInfo;
 import cn.com.qmth.examcloud.reports.commons.bean.AdminOperateReport;
@@ -53,7 +53,6 @@ import io.swagger.annotations.ApiParam;
 @RequestMapping("${$rmp.ctr.oe}/offlineExam")
 public class OfflineExamController extends ControllerSupport {
 	private static final Logger log = LoggerFactory.getLogger(OfflineExamController.class);
-	
     @Autowired
     private OfflineExamService offlineExamService;
 
@@ -194,6 +193,7 @@ public class OfflineExamController extends ControllerSupport {
         if (StringUtils.isBlank(offlineUploadFileType) || "[]".equals(offlineUploadFileType)) {
             throw new StatusException("OfflineExamController-submitPaper-003", "当前考试设置不允许上传附件");
         }
+
         String upperFileType=fileType.toUpperCase();
         if (("PDF".equals(upperFileType) || "ZIP".equals(upperFileType))&&fileArray.length>1){
         	StringBuilder sb=new StringBuilder();
@@ -206,6 +206,7 @@ public class OfflineExamController extends ControllerSupport {
         	log.error("batchSubmitPaper-duplicate:"+examRecordDataId+":"+sb);
         	throw new StatusException("000500", "上传"+upperFileType+"类型文件时只能传一个文件");
         }
+        
         List<File> resultFiles=new ArrayList<>();
         for (int i = 0; i < fileArray.length; i++) {
             MultipartFile file = fileArray[i];
@@ -213,7 +214,6 @@ public class OfflineExamController extends ControllerSupport {
             int index = fileName.lastIndexOf(".");
             String fileSuffix = fileName.substring(index + 1, fileName.length()).toUpperCase();
 
-            
             if (!"PDF".equals(upperFileType) && !"ZIP".equals(upperFileType)
                     && !"IMAGE".equals(upperFileType)) {
                 throw new StatusException("100001", "文件类型不正确");

+ 1 - 1
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamCourseCloudServiceProvider.java

@@ -61,7 +61,7 @@ public class ExamCourseCloudServiceProvider extends ControllerSupport implements
                 courses.add(course);
             }
         } catch (Exception e) {
-            log.error(e.getMessage(), e);
+            LOGGER.error(e.getMessage(), e);
         }
 
         return resp;

+ 62 - 89
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamRecordCloudServiceProvider.java

@@ -29,12 +29,13 @@ import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Example;
+import org.springframework.data.jpa.domain.Specification;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.persistence.criteria.Predicate;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -75,24 +76,37 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
 
     @Autowired
     private ExamRecordQuestionsService examRecordQuestionsService;
-    
+
     @Autowired
     private ExamRecordDataService examRecordDataService;
-    
+
 
     @Override
     @ApiOperation(value = "查询是否已经开考")
     @PostMapping("/checkExamIsStarted")
-    public CheckExamIsStartedResp checkExamIsStarted(@RequestBody CheckExamIsStartedReq examRecordReq) {
-        Check.isNull(examRecordReq.getExamId(), "examId不能为空");
-        ExamRecordDataEntity examRecordDataEntity = new ExamRecordDataEntity();
-        examRecordDataEntity.setExamId(examRecordReq.getExamId());
-        examRecordDataEntity.setCourseId(examRecordReq.getCourseId());
-        examRecordDataEntity.setStudentId(examRecordReq.getStudentId());
-        long examRecordNum = examRecordDataRepo.count(Example.of(examRecordDataEntity));
-        CheckExamIsStartedResp checkExamIsStartedResp = new CheckExamIsStartedResp();
-        checkExamIsStartedResp.setIsStarted(examRecordNum > 0);
-        return checkExamIsStartedResp;
+    public CheckExamIsStartedResp checkExamIsStarted(@RequestBody CheckExamIsStartedReq req) {
+        Check.isNull(req.getExamId(), "examId不能为空");
+
+        Specification<ExamRecordDataEntity> specification = (root, query, cb) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            predicates.add(cb.equal(root.get("examId"), req.getExamId()));
+
+            if (req.getCourseId() != null) {
+                predicates.add(cb.equal(root.get("courseId"), req.getCourseId()));
+            }
+
+            if (req.getStudentId() != null) {
+                predicates.add(cb.equal(root.get("studentId"), req.getStudentId()));
+            }
+
+            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
+        };
+
+        long count = examRecordDataRepo.count(specification);
+
+        CheckExamIsStartedResp resp = new CheckExamIsStartedResp();
+        resp.setIsStarted(count > 0);
+        return resp;
     }
 
     @Override
@@ -286,8 +300,8 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
         List<ExamStudentEntity> limitedExamStuList =
                 examStudentRepo.getLimitExamStudentList(examId, courseCode, startId, size);
 
-        if (log.isDebugEnabled()) {
-            log.debug("1.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]" +
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("1.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]" +
                     "获取考生耗时:" + (System.currentTimeMillis() - startTime) + " ms");
         }
 
@@ -300,8 +314,8 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
             resp.setNextId(nextId);
             resp.setToBeMarkExamRecordBeanList(null);
 
-            if (log.isDebugEnabled()) {
-                log.debug("999.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]end..." +
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("999.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]end..." +
                         "未找到对应的考生数据,合计耗时:" + (System.currentTimeMillis() - st) + " ms");
             }
 
@@ -322,8 +336,8 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
             List<ExamRecordForMarkingEntity> examRecordForMarkingList =
                     examRecordForMarkingService.queryValidExamRecordList(examStu.getExamStudentId());
 
-            if (log.isDebugEnabled()) {
-                log.debug("1-2." + si + "[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + examStu.getExamStudentId() + "]" +
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("1-2." + si + "[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + examStu.getExamStudentId() + "]" +
                         "获取考生待阅卷的考试记录耗时:" + (System.currentTimeMillis() - st1) + " ms");
             }
 
@@ -352,14 +366,14 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
                 pagedToBeMarkList.add(pagedBean);
             }
 
-            if (log.isDebugEnabled()) {
-                log.debug("1-2." + si + "[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + examStu.getExamStudentId() + "]" +
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("1-2." + si + "[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + examStu.getExamStudentId() + "]" +
                         "构建带作答记录的待阅卷的考试记录耗时:" + (System.currentTimeMillis() - st1) + " ms");
             }
         }
 
-        if (log.isDebugEnabled()) {
-            log.debug("2.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]" +
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("2.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]" +
                     "获取" + size + "条考生的待阅卷记录共耗时:" + (System.currentTimeMillis() - startTime) + " ms");
         }
 
@@ -367,8 +381,8 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
         resp.setNextId(nextId);
         resp.setToBeMarkExamRecordBeanList(pagedToBeMarkList);
 
-        if (log.isDebugEnabled()) {
-            log.debug("999.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]end..." +
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("999.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]end..." +
                     "合计耗时:" + (System.currentTimeMillis() - st) + " ms");
         }
         return resp;
@@ -400,57 +414,6 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
         return resultList;
     }
 
-    /**
-     * 获取套题的主题干
-     *
-     * @param cachedQues
-     * @return
-     */
-    private String getParentBody(QuestionCacheBean cachedQues) {
-
-        DefaultQuestionStructure questionStructure = cachedQues.getDefaultQuestion().getMasterVersion();
-
-        //如果主题干不为空,则认为是套题
-        return questionStructure.getBody();
-    }
-
-    /**
-     * 获取当前小题的题干
-     *
-     * @param curSubNumber       当前小题号
-     * @param questionId         原小题id
-     * @param cachedQues         带题干的试卷结构
-     * @param subjectiveQuesList 主观题集合
-     * @return
-     */
-    private String getBody(Integer curSubNumber, String questionId,
-                           QuestionCacheBean cachedQues, List<ExamQuestionEntity> subjectiveQuesList) {
-        DefaultQuestionStructure questionStructure = cachedQues.getDefaultQuestion().getMasterVersion();
-
-        //body为空,则说明当前小题为非套题(即questionUnitList集合大小为1),可直接返回小题题干
-        if (StringUtils.isNullOrEmpty(questionStructure.getBody())) {
-            return questionStructure.getQuestionUnitList().get(0).getBody();
-        }
-
-        //同一questionId的主观题集合(不带题干)
-        List<ExamQuestionEntity> noBodySubjectiveQuesList = subjectiveQuesList.stream().
-                filter(p -> p.getQuestionId().equals(questionId)).collect(Collectors.toList());
-
-        //同一questionId的主观题集合(带题干)
-        List<DefaultQuestionUnit> haveBodySubjectiveQuesList = questionStructure.getQuestionUnitList().stream()
-                .filter(p -> QuestionType.FILL_UP == p.getQuestionType() || QuestionType.ESSAY == p.getQuestionType())
-                .collect(Collectors.toList());
-
-        for (int i = 0; i < noBodySubjectiveQuesList.size(); i++) {
-            //如果小题号相同,则根据相同索引从带题干的集合中取出对应的小题题干
-            if (noBodySubjectiveQuesList.get(i).getOrder().intValue() == curSubNumber.intValue()) {
-                return haveBodySubjectiveQuesList.get(i).getBody();
-            }
-        }
-
-        return "";
-    }
-
     /**
      * 校验待阅卷数据
      *
@@ -662,21 +625,31 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
         return studentAnswer;
     }
 
-    
-	@Override
+
+    @Override
     @ApiOperation(value = "获取考试监考待审记录数")
     @PostMapping("/getGetAwaitingAuditCount")
-	public GetAwaitingAuditCountResp getGetAwaitingAuditCount(@RequestBody GetAwaitingAuditCountReq req) {
-		if(req.getRootOrgId()==null) {
-			throw new StatusException("500", "RootOrgId不允许为空");
-		}
-		if(req.getExamId()==null) {
-			throw new StatusException("500", "ExamId不允许为空");
-		}
-		Long count=examRecordDataService.getGetAwaitingAuditCount(req.getRootOrgId(),req.getExamId());
-		GetAwaitingAuditCountResp res=new GetAwaitingAuditCountResp();
-		res.setCount(count);
-		return res;
+    public GetAwaitingAuditCountResp getGetAwaitingAuditCount(@RequestBody GetAwaitingAuditCountReq req) {
+        if (req.getRootOrgId() == null) {
+            throw new StatusException("500", "RootOrgId不允许为空");
+        }
+        if (req.getExamId() == null) {
+            throw new StatusException("500", "ExamId不允许为空");
+        }
+        Long count = examRecordDataService.getGetAwaitingAuditCount(req.getRootOrgId(), req.getExamId());
+        GetAwaitingAuditCountResp res = new GetAwaitingAuditCountResp();
+        res.setCount(count);
+        return res;
+    }
+
+	@Override
+	@ApiOperation(value = "检查试卷是否已使用")
+    @PostMapping("/checkPaperInExam")
+	public CheckPaperInExamResp checkPaperInExam(@RequestBody CheckPaperInExamReq req) {
+		if (org.apache.commons.lang3.StringUtils.isBlank(req.getBasePaperId())) {
+            throw new StatusException("500", "basePaperId不允许为空");
+        }
+		return examRecordDataService.checkPaperInExam(req);
 	}
 
 }

+ 3 - 3
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamScoreDataCloudServiceProvider.java

@@ -454,18 +454,18 @@ public class ExamScoreDataCloudServiceProvider extends ControllerSupport impleme
         List<Long> examRecordDataIds = examRecordDataEntities.stream().map(ExamRecordDataEntity::getId).collect(Collectors.toList());
         List<ExamScoreEntity> examScoreEntities = examScoreRepo.findByExamRecordDataIdIn(examRecordDataIds);
         if (CollectionUtils.isEmpty(examScoreEntities)) {
-            log.info("examScoreEntities size is empty. ");
+            LOGGER.info("examScoreEntities size is empty. ");
             return queryResp;
         }
 
-        log.info("examRecordData size is " + examRecordDataEntities.size() + ", examScore size is " + examScoreEntities.size());
+        LOGGER.info("examRecordData size is " + examRecordDataEntities.size() + ", examScore size is " + examScoreEntities.size());
         Map<Long, ExamScoreEntity> examScoreMaps = examScoreEntities.stream().collect(Collectors.toMap(ExamScoreEntity::getExamRecordDataId, v -> v, (k, v) -> v));
 
         Map<Long, CourseBean> courseMaps = new HashMap<>();
         for (ExamRecordDataEntity examRecordData : examRecordDataEntities) {
             ExamScoreEntity examScore = examScoreMaps.get(examRecordData.getId());
             if (examScore == null) {
-                log.debug("examSore not exist. examRecordDataId = " + examRecordData.getId());
+                LOGGER.debug("examSore not exist. examRecordDataId = " + examRecordData.getId());
                 continue;
             }
 

+ 4 - 4
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamScoreNoticeQueueCloudServiceProvider.java

@@ -50,7 +50,7 @@ public class ExamScoreNoticeQueueCloudServiceProvider extends ControllerSupport
     @PostMapping("/sendObtainScoreNotice")
     @Override
     public void sendObtainScoreNotice() {
-        log.info("开始执行sendObtainScoreNotice");
+        LOGGER.info("开始执行sendObtainScoreNotice");
         // 获取所有的通知队列
         List<ExamScoreNoticeQueueEntity> examScoreNoticeQueueList = examScoreNoticeQueueRepo.findAll();
         if (examScoreNoticeQueueList == null || examScoreNoticeQueueList.size() == 0) {
@@ -75,14 +75,14 @@ public class ExamScoreNoticeQueueCloudServiceProvider extends ControllerSupport
                             noticeEntity.setUpdateTime(new Date());
                             examScoreNoticeQueueRepo.save(noticeEntity);
                         } catch (Exception e1) {
-                            log.error("examScoreNoticeQueueRepo.save exception:" + e1.getMessage(), e1);
+                            LOGGER.error("examScoreNoticeQueueRepo.save exception:" + e1.getMessage(), e1);
                         }
                     }
-                    log.error("OeExamScoreNoticeQueueCloudServiceProvider-sendObtainScoreNotice:" + e.getMessage(), e);
+                    LOGGER.error("OeExamScoreNoticeQueueCloudServiceProvider-sendObtainScoreNotice:" + e.getMessage(), e);
                 }
             }
         }
-        log.info("结束执行sendObtainScoreNotice");
+        LOGGER.info("结束执行sendObtainScoreNotice");
     }
 
     /**

+ 2 - 2
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamStudentDataCloudServiceProvider.java

@@ -90,7 +90,7 @@ public class ExamStudentDataCloudServiceProvider extends ControllerSupport imple
                 for (Long eid : errorExamRecordDataIdList) {
                     strErrorExamRecordDataIds += eid + ",";
                 }
-                log.error("[GETEXAMSTUDENTDATA],200105考试作答数据异常,错误的考试记录id:" + strErrorExamRecordDataIds);
+                LOGGER.error("[GETEXAMSTUDENTDATA],200105考试作答数据异常,错误的考试记录id:" + strErrorExamRecordDataIds);
                 throw new StatusException("200105", "考试作答数据异常,相关考试记录id为:" + strErrorExamRecordDataIds);
             }
             if (questionList.size() != effectiveScoreList.size()) {
@@ -99,7 +99,7 @@ public class ExamStudentDataCloudServiceProvider extends ControllerSupport imple
                 for (Long eid : errorExamRecordDataIdList) {
                     strErrorExamRecordDataIds += eid + ",";
                 }
-                log.error("[GETEXAMSTUDENTDATA],200106考试作答数据异常,错误的考试记录id:" + strErrorExamRecordDataIds);
+                LOGGER.error("[GETEXAMSTUDENTDATA],200106考试作答数据异常,错误的考试记录id:" + strErrorExamRecordDataIds);
                 throw new StatusException("200106", "考试作答数据异常,相关考试记录id为:" + strErrorExamRecordDataIds);
             }
         }

+ 3 - 3
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/SyncExamDataCloudServiceProvider.java

@@ -2,8 +2,6 @@ package cn.com.qmth.examcloud.core.oe.admin.api.provider;
 
 import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
 import cn.com.qmth.examcloud.core.oe.admin.api.SyncExamDataCloudService;
 import cn.com.qmth.examcloud.core.oe.admin.api.bean.*;
 import cn.com.qmth.examcloud.core.oe.admin.api.request.SyncExamDataReq;
@@ -25,6 +23,8 @@ import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Example;
 import org.springframework.transaction.annotation.Transactional;
@@ -49,7 +49,7 @@ public class SyncExamDataCloudServiceProvider extends ControllerSupport implemen
 
     private static final long serialVersionUID = -25466948667789119L;
 
-    private static final ExamCloudLog LOG = ExamCloudLogFactory.getLog(SyncExamDataCloudServiceProvider.class);
+    private static final Logger LOG = LoggerFactory.getLogger(SyncExamDataCloudServiceProvider.class);
 
     @Autowired
     private ExamRecordForMarkingService examRecordForMarkingService;

+ 123 - 123
examcloud-core-oe-admin-base/pom.xml

@@ -1,136 +1,136 @@
 <?xml version="1.0"?>
-<project
-	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
-	xmlns="http://maven.apache.org/POM/4.0.0"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>cn.com.qmth.examcloud</groupId>
-		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>v4.0.2-RELEASE</version>
-	</parent>
-	<artifactId>examcloud-core-oe-admin-base</artifactId>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+         xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-oe-admin-base</artifactId>
+    <packaging>jar</packaging>
 
-	<dependencies>
-		<dependency>
-			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-data-mongodb</artifactId>
-			<exclusions>
-				<exclusion>
-					<groupId>org.springframework.boot</groupId>
-					<artifactId>spring-boot-starter-logging</artifactId>
-				</exclusion>
-			</exclusions>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud</groupId>
-			<artifactId>examcloud-web</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud</groupId>
-			<artifactId>examcloud-support</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-oe-admin</artifactId>
+        <version>${revision}</version>
+    </parent>
 
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.rpc</groupId>
-			<artifactId>examcloud-exchange-inner-api-client</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.rpc</groupId>
-			<artifactId>examcloud-core-basic-api-client</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.rpc</groupId>
-			<artifactId>examcloud-core-examwork-api-client</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.rpc</groupId>
-			<artifactId>examcloud-core-questions-api-client</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.rpc</groupId>
-			<artifactId>examcloud-core-oe-admin-api-client</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.rpc</groupId>
-			<artifactId>examcloud-ws-api-client</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.rpc</groupId>
-			<artifactId>examcloud-core-marking-api-client</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.rpc</groupId>
-			<artifactId>examcloud-global-api</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.rpc</groupId>
-			<artifactId>examcloud-core-oe-student-api-client</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-web</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-support</artifactId>
+            <version>${project.version}</version>
+        </dependency>
 
-		<dependency>
-			<groupId>org.apache.httpcomponents</groupId>
-			<artifactId>httpmime</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.httpcomponents</groupId>
-			<artifactId>httpclient</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.rpc</groupId>
+            <artifactId>examcloud-exchange-inner-api-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.rpc</groupId>
+            <artifactId>examcloud-core-basic-api-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.rpc</groupId>
+            <artifactId>examcloud-core-examwork-api-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.rpc</groupId>
+            <artifactId>examcloud-core-questions-api-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.rpc</groupId>
+            <artifactId>examcloud-core-oe-admin-api-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.rpc</groupId>
+            <artifactId>examcloud-ws-api-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.rpc</groupId>
+            <artifactId>examcloud-core-marking-api-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.rpc</groupId>
+            <artifactId>examcloud-global-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.rpc</groupId>
+            <artifactId>examcloud-core-oe-student-api-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
 
-		<dependency>
-			<groupId>org.json</groupId>
-			<artifactId>json</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpmime</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>org.hibernate</groupId>
-			<artifactId>hibernate-validator</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>io.github.openfeign</groupId>
-			<artifactId>feign-okhttp</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-validator</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>com.squareup.okhttp3</groupId>
-			<artifactId>okhttp</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>io.github.openfeign</groupId>
+            <artifactId>feign-okhttp</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>com.squareup.okhttp3</groupId>
-			<artifactId>logging-interceptor</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>com.upyun</groupId>
-			<artifactId>java-sdk</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>com.baidu.aip</groupId>
-			<artifactId>java-sdk</artifactId>
-		</dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>logging-interceptor</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>com.esotericsoftware</groupId>
-			<artifactId>reflectasm</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud.reports</groupId>
-			<artifactId>examcloud-reports-commons</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-	</dependencies>
+        <dependency>
+            <groupId>com.upyun</groupId>
+            <artifactId>java-sdk</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baidu.aip</groupId>
+            <artifactId>java-sdk</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.esotericsoftware</groupId>
+            <artifactId>reflectasm</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-reports-commons</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
 
 </project>

+ 0 - 17
examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/Constants.java

@@ -66,29 +66,12 @@ public interface Constants {
     /**
      * 原始数据库表
      */
-    String OE_EXAM_RECORD = "oe_exam_record";
-    String ECS_EXAM_STUDENT = "ecs_exam_student";
     String OE_EXAM_QUESTION = "oe_exam_question";
-    String OE_EXAM_CAPTURE = "oe_exam_capture";
-    String OE_EXAM_SCORE = "oe_exam_score";
-    String OE_EXAM_AUDIT = "oe_exam_audit";
-    String OE_FACE_VERIFY = "oe_face_verify";
 
     /**
      * 新数据库表
      */
-    String EC_OE_EXAM_RECORD_DATA = "ec_oe_exam_record_data";
-    String EC_OE_EXAM_STUDENT = "ec_oe_exam_student";
     String EXAM_RECORD_QUESTIONS = "examRecordQuestions";
-    String EC_OE_EXAM_CAPTURE = "ec_oe_exam_capture";
-    String EC_OE_EXAM_SCORE = "ec_oe_exam_score";
-    String EC_OE_EXAM_AUDIT = "ec_oe_exam_audit";
-    String EC_OE_EXAM_FACE_VERIFY = "ec_oe_exam_face_liveness_verify";
-
-    /**
-     * 课程信息表
-     */
-    String ECS_CORE_COURSE = "ecs_core_course";
 
     //缓存
     String CACHE_EXAM_STUDENT_PREFIX = "cache_examStudent_";

+ 6 - 2
examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/jpa/Order.java

@@ -42,9 +42,13 @@ public class Order implements Serializable {
         }
         List<Sort.Order> list = new ArrayList<>();
         for (Order order : orders) {
-            list.add(new Sort.Order(order.getDirection(), order.getFieldName()));
+            if(order.getDirection().isAscending()){
+                list.add(Sort.Order.asc(order.getFieldName()));
+            }else {
+                list.add(Sort.Order.desc(order.getFieldName()));
+            }
         }
-        return new Sort(list);
+        return Sort.by(list);
     }
 
     private Order(String fieldName, Sort.Direction direction) {

+ 2 - 3
examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/jpa/SpecUtils.java

@@ -11,7 +11,6 @@ import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.domain.Specification;
-import org.springframework.data.jpa.domain.Specifications;
 
 import javax.persistence.criteria.*;
 import java.util.ArrayList;
@@ -124,12 +123,12 @@ public class SpecUtils {
         };
     }
 
-    public static Specification andMerge(Specification target1, Specification target2) {
+    /*public static Specification andMerge(Specification target1, Specification target2) {
         return Specifications.where(target1).and(target2);
     }
 
     public static Specification orMerge(Specification target1, Specification target2) {
         return Specifications.where(target1).or(target2);
-    }
+    }*/
 
 }

+ 6 - 6
examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/utils/FileDisposeUtil.java

@@ -36,7 +36,7 @@ import org.slf4j.LoggerFactory;
  */
 public class FileDisposeUtil {
 	
-	private static final Logger logger = LoggerFactory.getLogger(FileDisposeUtil.class);
+	private static final Logger LOG = LoggerFactory.getLogger(FileDisposeUtil.class);
 	
 	/**
 	 * 将网络文件保存到本地
@@ -147,7 +147,7 @@ public class FileDisposeUtil {
 	 * @return
 	 */
 	public static boolean fileToZip(String sourceFilePath, String zipFilePath,String fileName) {
-		logger.info("压缩"+sourceFilePath+"目录开始");
+		LOG.info("压缩"+sourceFilePath+"目录开始");
 		boolean flag = false;
 		File sourceFile = new File(sourceFilePath);
 		FileInputStream fis = null;
@@ -155,16 +155,16 @@ public class FileDisposeUtil {
 		FileOutputStream fos = null;
 		ZipOutputStream zos = null;
 		if (sourceFile.exists() == false) {
-			logger.error("待压缩的文件目录:" + sourceFilePath + "不存在.");
+			LOG.error("待压缩的文件目录:" + sourceFilePath + "不存在.");
 		} else {
 			try {
 				File zipFile = new File(zipFilePath+File.separator+fileName+".zip");
 				if (zipFile.exists()) {
-					logger.error(zipFilePath + "目录下存在名字为:"+fileName+".zip"+"打包文件.");
+					LOG.error(zipFilePath + "目录下存在名字为:"+fileName+".zip"+"打包文件.");
 				} else {
 					File[] sourceFiles = sourceFile.listFiles();
 					if (null == sourceFiles || sourceFiles.length < 1) {
-						logger.error("待压缩的文件目录:" + sourceFilePath+ "里面不存在文件,无需压缩.");
+						LOG.error("待压缩的文件目录:" + sourceFilePath+ "里面不存在文件,无需压缩.");
 					} else {
 						fos = new FileOutputStream(zipFile);
 						zos = new ZipOutputStream(new BufferedOutputStream(fos));
@@ -203,7 +203,7 @@ public class FileDisposeUtil {
 				IOUtils.closeQuietly(fos);
 			}
 		}
-		logger.info("压缩"+sourceFilePath+"目录完成");
+		LOG.info("压缩"+sourceFilePath+"目录完成");
 		return flag;
 	}
 	

+ 8 - 8
examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/utils/HttpPoolUtil.java

@@ -1,21 +1,21 @@
 package cn.com.qmth.examcloud.core.oe.admin.base.utils;
 
-import org.apache.commons.logging.Log; 
-import org.apache.commons.logging.LogFactory; 
-import org.apache.http.client.config.RequestConfig; 
+import org.apache.http.client.config.RequestConfig;
 import org.apache.http.impl.client.CloseableHttpClient; 
 import org.apache.http.impl.client.HttpClientBuilder; 
 import org.apache.http.impl.client.HttpClients; 
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
-
 /** 
 * 连接池工具类 
 */ 
 @Component
-public class HttpPoolUtil { 
-	private static Log logger = LogFactory.getLog(HttpPoolUtil.class); 
+public class HttpPoolUtil {
+
+	private static final Logger log = LoggerFactory.getLogger(HttpPoolUtil.class);
 	
 	public static final String UTF8 = "UTF-8"; 
 	public static volatile boolean isClosed = false; 
@@ -73,7 +73,7 @@ public class HttpPoolUtil {
 	public static CloseableHttpClient getHttpClient() { 
 		CloseableHttpClient httpClient = httpClientBuilder.build(); 
 		if(null == httpClient){ 
-			logger.info("---------HttpClients.createDefault()---------"); 
+			log.info("---------HttpClients.createDefault()---------");
 			httpClient = HttpClients.createDefault(); 
 		} 
 		return httpClient; 

+ 4 - 4
examcloud-core-oe-admin-base/src/main/java/cn/com/qmth/examcloud/core/oe/admin/base/utils/PagingAndSortingSpecification.java

@@ -60,13 +60,13 @@ public abstract class PagingAndSortingSpecification implements QuerySpecificatio
             order = "ASC";
         }
         if (properties != null) {
-            Sort sort = new Sort(Sort.Direction.valueOf(order), properties);
-            pageRequest = new PageRequest(page, size, sort);
+            Sort sort = Sort.by(Sort.Direction.valueOf(order), properties);
+            pageRequest = PageRequest.of(page, size, sort);
         } else if (page != null && size != null) {
-            pageRequest = new PageRequest(page, size);
+            pageRequest = PageRequest.of(page, size);
         } else {
             //TODO 暂时返还一条数据
-            pageRequest = new PageRequest(0, 1);
+            pageRequest = PageRequest.of(0, 1);
         }
         return pageRequest;
     }

+ 18 - 16
examcloud-core-oe-admin-dao/pom.xml

@@ -1,19 +1,21 @@
 <?xml version="1.0"?>
 <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
-	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>cn.com.qmth.examcloud</groupId>
-		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>v4.0.2-RELEASE</version>
-	</parent>
-	<artifactId>examcloud-core-oe-admin-dao</artifactId>
-	
-	<dependencies>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud</groupId>
-			<artifactId>examcloud-core-oe-admin-base</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-	</dependencies>
+         xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-oe-admin-dao</artifactId>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-oe-admin</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-core-oe-admin-base</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
 </project>

+ 3 - 0
examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/ExamRecordDataRepo.java

@@ -104,4 +104,7 @@ public interface ExamRecordDataRepo extends JpaRepository<ExamRecordDataEntity,
             "where record_data.exam_record_status in('EXAM_END','EXAM_OVERDUE') and record_data.exam_id=?1 " +
             "AND record_data.is_audit=0 ", nativeQuery = true)
     List<ExamRecordDataEntity> findDataByExamId(Long examId);
+    
+    @Query(value = "select t.id from ec_oe_exam_record_data t where t.base_paper_id=?1 limit 1", nativeQuery = true)
+    Long getRecordIdByPaperId(String basePaperId);
 }

+ 2 - 0
examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/ExamStudentRepo.java

@@ -29,6 +29,8 @@ public interface ExamStudentRepo extends JpaRepository<ExamStudentEntity, Long>,
 	
 	public List<ExamStudentEntity> findByStudentIdAndEnableAndExamIdIn(Long studentId,Boolean enable,List<Long> examId);
 
+	List<ExamStudentEntity> findByStudentIdAndEnable(Long studentId,Boolean enable);
+
 	public List<ExamStudentEntity> findByStudentId(Long studentId);
 
 	public ExamStudentEntity findByExamStudentId(Long examStudentId);

+ 16 - 0
examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/entity/ExamRecordDataEntity.java

@@ -23,6 +23,8 @@ import java.util.Date;
         @Index(name = "IDX_E_O_E_R_D_004", columnList = "examId"),
         @Index(name = "IDX_E_O_E_R_D_005", columnList = "courseId"),
         @Index(name = "IDX_E_O_E_R_D_006", columnList = "examRecordStatus"),
+        @Index(name = "IDX_E_O_E_R_D_007", columnList = "basePaperId"),
+        
 })
 @DynamicInsert
 public class ExamRecordDataEntity extends JpaEntity {
@@ -252,6 +254,12 @@ public class ExamRecordDataEntity extends JpaEntity {
     @Transient
     private String ip;
 
+    /**
+     * 审核人(忽略该字段持久化)
+     */
+    @Transient
+    private String auditUserName;
+
     public Long getId() {
         return id;
     }
@@ -641,4 +649,12 @@ public class ExamRecordDataEntity extends JpaEntity {
     public void setIp(String ip) {
         this.ip = ip;
     }
+
+    public String getAuditUserName() {
+        return auditUserName;
+    }
+
+    public void setAuditUserName(String auditUserName) {
+        this.auditUserName = auditUserName;
+    }
 }

+ 2 - 0
examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/enums/ExportTaskType.java

@@ -12,6 +12,8 @@ public enum ExportTaskType {
 
     EXAM_DETAIL("考试明细"),
 
+    AUDIT("监考已审"),
+
     SCORE_STATISTIC("成绩统计"),
     
     EXAM_SCHEDULING("考试进度");

+ 4 - 4
examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/enums/FaceVerifyResult.java

@@ -9,13 +9,13 @@ import org.apache.commons.lang3.StringUtils;
  * @description 人脸活体检测验证结果
  */
 public enum FaceVerifyResult {
-	
+
 	VERIFY_SUCCESS("验证成功"),
-	
+
 	VERIFY_FAILED("动作有误,验证失败"),
-	
+
 	NOT_ONESELF("不是本人"),
-	
+
 	TIME_OUT("超时未完成"),
 
 	SCREEN_REPLAY("屏幕翻拍"),

+ 17 - 15
examcloud-core-oe-admin-service/pom.xml

@@ -1,20 +1,22 @@
 <?xml version="1.0"?>
 <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
-	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>cn.com.qmth.examcloud</groupId>
-		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>v4.0.2-RELEASE</version>
-	</parent>
-	<artifactId>examcloud-core-oe-admin-service</artifactId>
+         xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-oe-admin-service</artifactId>
+    <packaging>jar</packaging>
 
-	<dependencies>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud</groupId>
-			<artifactId>examcloud-core-oe-admin-dao</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-	</dependencies>
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-oe-admin</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-core-oe-admin-dao</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
 
 </project>

+ 4 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/AsyncExportService.java

@@ -6,6 +6,7 @@
 package cn.com.qmth.examcloud.core.oe.admin.service;
 
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.core.oe.admin.service.bean.examaudit.ExamAuditQuery;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordQuery;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examscore.ExamScoreQuery;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamStudentQuery;
@@ -21,10 +22,13 @@ public interface AsyncExportService {
     
     void exportExamScheduling(String jsonParams,User user);
 
+    void exportExamAuditList(String query, User user);
+
 	void asyncExportExamScheduling(Long taskId, ExamStudentQuery req);
 
 	void asyncExportExamRecordDetails(Long taskId, ExamRecordQuery req);
 
 	void asyncExportExamScoreStatistics(Long taskId, ExamScoreQuery req);
 
+    void asyncExportExamAuditList(Long taskId, ExamAuditQuery query);
 }

+ 8 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamAuditService.java

@@ -34,6 +34,14 @@ public interface ExamAuditService {
      */
     Page<ExamAuditInfo> getExamAuditList(ExamAuditQuery query);
 
+    /**
+     * 查询监考已审列表
+     *
+     * @param query
+     * @return
+     */
+    List<ExamAuditInfo> getExamAudit(ExamAuditQuery query);
+
 
     /**
      * 获取审核信息

+ 4 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamRecordDataService.java

@@ -1,5 +1,7 @@
 package cn.com.qmth.examcloud.core.oe.admin.service;
 
+import cn.com.qmth.examcloud.core.oe.admin.api.request.CheckPaperInExamReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.CheckPaperInExamResp;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamStudentBean;
 import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
@@ -28,4 +30,6 @@ public interface ExamRecordDataService {
 
 	Long getGetAwaitingAuditCount(Long rootOrgId, Long examId);
 
+	CheckPaperInExamResp checkPaperInExam(CheckPaperInExamReq req);
+
 }

+ 8 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamRecordService.java

@@ -49,6 +49,14 @@ public interface ExamRecordService {
      */
     Page<ExamRecordInfo> getExamRecordWaitingAuditList(ExamRecordQuery query);
 
+    /**
+     * 查询“监考待审”列表(分页)
+     *
+     * @param query
+     * @return
+     */
+    List<ExamRecordInfo> getExamRecordWaitingAudit(ExamRecordQuery query);
+
 	/**
 	 * Description 查询“监考待审”下一条记录
 	 *

+ 1 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamStudentService.java

@@ -150,4 +150,5 @@ public interface ExamStudentService {
 
     List<ExamStudentInfo> getExamStudentInfoListForAsync(ExamStudentQuery query);
 
+    List<OnHandExamInfo> queryOnlineExamEndList(Long userId, ExamType online);
 }

+ 15 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examaudit/ExamAuditInfo.java

@@ -8,6 +8,7 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.bean.examaudit;
 
 import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import cn.com.qmth.examcloud.support.excel.ExcelProperty;
 
 /**
  * 监考已审信息
@@ -25,21 +26,25 @@ public class ExamAuditInfo implements JsonSerializable {
      */
     private Long id;
 
+    @ExcelProperty(name = "考试记录id", width = 30, index = 1)
     private Long examRecordDataId;
 
     /**
      * 审核状态
      */
+    @ExcelProperty(name = "审核结果", width = 30, index = 13)
     private String status;
     /**
      * 违纪详情
      */
     private String disciplineDetail;
 
+    @ExcelProperty(name = "审核说明", width = 30, index = 12)
     private String disciplineType;
     /**
      * 审核人姓名
      */
+    @ExcelProperty(name = "审核人", width = 30, index = 14)
     private String auditUserName;
 
     /**
@@ -65,14 +70,17 @@ public class ExamAuditInfo implements JsonSerializable {
     /**
      * 学号
      */
+    @ExcelProperty(name = "学号", width = 30, index = 4)
     private String studentCode;
     /**
      * 学生姓名
      */
+    @ExcelProperty(name = "姓名", width = 30, index = 2)
     private String studentName;
     /**
      * 身份证号
      */
+    @ExcelProperty(name = "身份证号", width = 30, index = 3)
     private String identityNumber;
     /**
      * 课程ID
@@ -85,10 +93,12 @@ public class ExamAuditInfo implements JsonSerializable {
     /**
      * 课程名称
      */
+    @ExcelProperty(name = "课程", width = 30, index = 5)
     private String courseName;
     /**
      * 课程层次
      */
+    @ExcelProperty(name = "课程层次", width = 30, index = 6)
     private String courseLevel;
     /**
      * 学习中心ID
@@ -121,6 +131,7 @@ public class ExamAuditInfo implements JsonSerializable {
     /**
      * 第几次考试
      */
+    @ExcelProperty(name = "考试次数", width = 30, index = 11)
     private Integer examOrder;
     /**
      * 是否为重考
@@ -137,6 +148,7 @@ public class ExamAuditInfo implements JsonSerializable {
     /**
      * 抓拍比对成功次数
      */
+    @ExcelProperty(name = "成功次数", width = 30, index = 8)
     private Integer faceSuccessCount;
     /**
      * 抓拍比对失败次数
@@ -145,14 +157,17 @@ public class ExamAuditInfo implements JsonSerializable {
     /**
      * 抓拍存在陌生人的次数
      */
+    @ExcelProperty(name = "陌生人记录", width = 30, index = 9)
     private Integer faceStrangerCount;
     /**
      * 抓拍比对总次数
      */
+    @ExcelProperty(name = "校验次数", width = 30, index = 7)
     private Integer faceTotalCount;
     /**
      * 抓拍比对成功比率
      */
+    @ExcelProperty(name = "人脸识别成功率(%)", width = 30, index = 10)
     private Double faceSuccessPercent;
     /**
      * 活体检测结果

+ 10 - 1
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordEntityConvert.java

@@ -154,13 +154,15 @@ public class ExamRecordEntityConvert {
 
         //ip
         info.setIp(recordData.getIp());
+        //审核人
+        info.setAuditUserName(recordData.getAuditUserName());
 
         return info;
     }
     
 
     public Page<ExamRecordInfo> of(Page<ExamRecordDataEntity> page) {
-        Pageable pageable = new PageRequest(page.getNumber(), page.getSize());
+        Pageable pageable = PageRequest.of(page.getNumber(), page.getSize());
         List<ExamRecordDataEntity> entities = page.getContent();
         if (entities == null || entities.size() == 0) {
             return new PageImpl<ExamRecordInfo>(Lists.newArrayList(), pageable, page.getTotalElements());
@@ -171,6 +173,13 @@ public class ExamRecordEntityConvert {
         return new PageImpl<ExamRecordInfo>(list, pageable, page.getTotalElements());
     }
 
+    public List<ExamRecordInfo> ofList(List<ExamRecordDataEntity> entities) {
+        //缓存
+        Map<String,Object> cahcheMap = new HashMap<>();
+        List<ExamRecordInfo> list = entities.stream().map(entity -> of(entity,cahcheMap)).collect(Collectors.toList());
+        return list;
+    }
+
 
     public List<ExamRecordInfo> of(List<ExamRecordDataEntity> entities) {
     	//缓存

+ 14 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordInfo.java

@@ -294,6 +294,12 @@ public class ExamRecordInfo implements JsonSerializable {
     @ExcelProperty(name = "Ip", width = 30, index = 32)
     private String ip;
 
+    /**
+     * Ip
+     */
+    @ExcelProperty(name = "审核人", width = 30, index = 33)
+    private String auditUserName;
+
     private Boolean hasVirtual;
 
     public Long getId() {
@@ -778,6 +784,14 @@ public class ExamRecordInfo implements JsonSerializable {
 		this.faceVerifyResultValue = faceVerifyResultValue;
 	}
 
+    public String getAuditUserName() {
+        return auditUserName;
+    }
+
+    public void setAuditUserName(String auditUserName) {
+        this.auditUserName = auditUserName;
+    }
+
     public Boolean getHasVirtual() {
         return hasVirtual;
     }

+ 11 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordQuery.java

@@ -93,6 +93,9 @@ public class ExamRecordQuery implements JsonSerializable {
     @ApiModelProperty("Ip")
     private String ip;
 
+    @ApiModelProperty("审核人")
+    private String auditUserName;
+
     public ExamRecordQuery addRecordStatus(String recordStatus) {
         if (recordStatuses == null) {
             recordStatuses = new ArrayList<>();
@@ -357,4 +360,12 @@ public class ExamRecordQuery implements JsonSerializable {
     public void setIp(String ip) {
         this.ip = ip;
     }
+
+    public String getAuditUserName() {
+        return auditUserName;
+    }
+
+    public void setAuditUserName(String auditUserName) {
+        this.auditUserName = auditUserName;
+    }
 }

+ 1 - 1
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examstudent/ExamStudentEntityConvert.java

@@ -164,7 +164,7 @@ public class ExamStudentEntityConvert {
 
 
     public static Page<ExamStudentInfo> of(Page<ExamStudentEntity> page) {
-        Pageable pageable = new PageRequest(page.getNumber(), page.getSize());
+        Pageable pageable = PageRequest.of(page.getNumber(), page.getSize());
         List<ExamStudentEntity> entities = page.getContent();
         if (entities == null || entities.size() == 0) {
             return new PageImpl<>(Lists.newArrayList(), pageable, page.getTotalElements());

+ 49 - 30
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/exporttask/ExportTask.java

@@ -1,21 +1,23 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.bean.exporttask;
 
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
 import cn.com.qmth.examcloud.commons.util.JsonMapper;
 import cn.com.qmth.examcloud.commons.util.Util;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExportTaskEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExportTaskType;
 import cn.com.qmth.examcloud.core.oe.admin.service.AsyncExportService;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExportTaskService;
+import cn.com.qmth.examcloud.core.oe.admin.service.bean.examaudit.ExamAuditQuery;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordQuery;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examscore.ExamScoreQuery;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamStudentQuery;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 import cn.com.qmth.examcloud.web.support.SpringContextHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ExportTask extends Thread {
-	private static final ExamCloudLog log = ExamCloudLogFactory.getLog(ExportTask.class);
+
+	private static final Logger log = LoggerFactory.getLogger(ExportTask.class);
 
 	private static int cacheLockTimeout = 60 * 2;
 
@@ -28,41 +30,58 @@ public class ExportTask extends Thread {
 	@Override
 	public void run() {
 		for (;;) {
-			ExportTaskEntity et = exportTaskService.findExportTaskToDispose();
-			if (et == null) {
-				log.info("ExportTask sleep...");
-				Util.sleep(30);
-				continue;
-			}
+			try {
+				log.info("ExportTask start");
+				ExportTaskEntity et = exportTaskService.findExportTaskToDispose();
+				if (et == null) {
+					log.info("ExportTask sleep 30s");
+					Util.sleep(30);
+					continue;
+				}
 
-			String cacheLock = "$_CACHE_LOCK:OE_EXPORT_TASK:" + et.getId();
-			Boolean lock = redisClient.setIfAbsent(cacheLock, cacheLock, cacheLockTimeout);
-			if (!lock) {
-				log.info("ExportTask lock... " + cacheLock);
-				continue;
-			}
+				String cacheLock = "$_CACHE_LOCK:OE_EXPORT_TASK:" + et.getId();
+				Boolean lock = redisClient.setIfAbsent(cacheLock, cacheLock, cacheLockTimeout);
+				if (!lock) {
+					log.info("ExportTask lock... " + cacheLock);
+					continue;
+				}
 
-			try {
-				exportTaskService.startExportTask(et.getId());
-				if (ExportTaskType.EXAM_DETAIL.equals(et.getType())) {
-					examRecordDetails(et);
-				} else if (ExportTaskType.SCORE_STATISTIC.equals(et.getType())) {
-					examScores(et);
-				} else if (ExportTaskType.EXAM_SCHEDULING.equals(et.getType())) {
-					examScheduling(et);
+				try {
+					exportTaskService.startExportTask(et.getId());
+					if (ExportTaskType.EXAM_DETAIL.equals(et.getType())) {
+						examRecordDetails(et);
+					} else if (ExportTaskType.SCORE_STATISTIC.equals(et.getType())) {
+						examScores(et);
+					} else if (ExportTaskType.EXAM_SCHEDULING.equals(et.getType())) {
+						examScheduling(et);
+					} else if (ExportTaskType.AUDIT.equals(et.getType())) {
+						examAudit(et);
+					}
+					exportTaskService.endExportTask(et.getId());
+				} finally {
+					redisClient.delete(cacheLock);
 				}
-				exportTaskService.endExportTask(et.getId());
+				log.info("ExportTask end");
 			} catch (Exception e) {
-				log.error("ExportTask error ", e);
-			} finally {
-				redisClient.delete(cacheLock);
+				log.error("ExportTask error " + e.getMessage(), e);
 			}
 		}
 	}
 
+	/**
+	 * 监考已审
+	 *
+	 * @param et
+	 */
+	private void examAudit(ExportTaskEntity et) {
+		ExamAuditQuery req = new JsonMapper().parseJson(et.getExportParam(), ExamAuditQuery.class);
+		req.setRootOrgId(et.getRootOrgId());
+		asyncExportService.asyncExportExamAuditList(et.getId(), req);
+	}
+
 	/**
 	 * 考试明细
-	 * 
+	 *
 	 * @param et
 	 */
 	private void examRecordDetails(ExportTaskEntity et) {
@@ -73,7 +92,7 @@ public class ExportTask extends Thread {
 
 	/**
 	 * 成绩统计
-	 * 
+	 *
 	 * @param et
 	 */
 	private void examScores(ExportTaskEntity et) {
@@ -84,7 +103,7 @@ public class ExportTask extends Thread {
 
 	/**
 	 * 考试进度
-	 * 
+	 *
 	 * @param et
 	 */
 	private void examScheduling(ExportTaskEntity et) {

+ 101 - 15
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/AsyncExportServiceImpl.java

@@ -13,15 +13,21 @@ import java.util.Date;
 import java.util.List;
 import java.util.UUID;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamAuditService;
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamCaptureService;
+import cn.com.qmth.examcloud.core.oe.admin.service.bean.examaudit.ExamAuditInfo;
+import cn.com.qmth.examcloud.core.oe.admin.service.bean.examaudit.ExamAuditQuery;
+import cn.com.qmth.examcloud.support.helper.IdentityNumberHelper;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
 import cn.com.qmth.examcloud.commons.util.JsonMapper;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.Check;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExportTaskStatus;
@@ -54,7 +60,7 @@ import cn.com.qmth.examcloud.web.filestorage.YunPathInfo;
 @Service
 public class AsyncExportServiceImpl implements AsyncExportService {
 
-	private static final ExamCloudLog log = ExamCloudLogFactory.getLog(AsyncExportServiceImpl.class);
+	private static final Logger LOG = LoggerFactory.getLogger(AsyncExportServiceImpl.class);
 
 	private static final String TASK_EXPORT_DIR = "task_export";
 
@@ -73,6 +79,9 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 	@Autowired
 	private ExamStudentService examStudentService;
 
+	@Autowired
+	private ExamAuditService examAuditService;
+
 	@Override
 	public void exportExamScheduling(String jsonParams, User user) {
 		ExamStudentQuery req = new JsonMapper().parseJson(jsonParams, ExamStudentQuery.class);
@@ -104,7 +113,7 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 			examRecords = ExamStudentEntityConvert.ofExcel(examStudentInfoList);
 
 		} catch (Exception e) {
-			log.error(e.getMessage(),e);
+			LOG.error(e.getMessage(), e);
 			if (e instanceof StatusException) {
 				exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR,
 						((StatusException) e).getDesc());
@@ -124,7 +133,7 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 			tempFile.getParentFile().mkdirs();
 			tempFile.createNewFile();
 		} catch (IOException e) {
-			log.error(e.getMessage(),e);
+			LOG.error(e.getMessage(), e);
 			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "生成导出文件异常");
 			return;
 		}
@@ -138,10 +147,10 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 			env.setRelativePath(filePath);
 			YunPathInfo oss = FileStorageUtil.saveFile(TASK_EXPORT_DIR, env, tempFile, null);
 
-			log.info("asyncExportExamScheduling finished... " + oss.getRelativePath());
+			LOG.info("asyncExportExamScheduling finished... " + oss.getRelativePath());
 			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.SUCCESS, null, oss.getRelativePath());
 		} catch (Exception e) {
-			log.error("asyncExportExamScheduling error... " + e);
+			LOG.error("asyncExportExamScheduling error... " + e);
 			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "上传至文件服务器异常");
 		} finally {
 			FileUtils.deleteQuietly(tempFile);
@@ -181,7 +190,7 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 			}
 
 		} catch (Exception e) {
-			log.error(e.getMessage(),e);
+			LOG.error(e.getMessage(),e);
 			if (e instanceof StatusException) {
 				exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR,
 						((StatusException) e).getDesc());
@@ -200,7 +209,7 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 			tempFile.getParentFile().mkdirs();
 			tempFile.createNewFile();
 		} catch (IOException e) {
-			log.error(e.getMessage(),e);
+			LOG.error(e.getMessage(), e);
 			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "生成导出文件异常");
 			return;
 		}
@@ -214,10 +223,10 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 			env.setRelativePath(filePath);
 			YunPathInfo oss = FileStorageUtil.saveFile(TASK_EXPORT_DIR, env, tempFile, null);
 
-			log.info("asyncExportExamRecordDetails finished... " + oss.getRelativePath());
+			LOG.info("asyncExportExamRecordDetails finished... " + oss.getRelativePath());
 			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.SUCCESS, null, oss.getRelativePath());
 		} catch (Exception e) {
-			log.info("asyncExportExamRecordDetails error... " + e.getMessage());
+			LOG.info("asyncExportExamRecordDetails error... " + e.getMessage());
 			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "上传至文件服务器异常");
 		} finally {
 			FileUtils.deleteQuietly(tempFile);
@@ -254,7 +263,7 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 				return;
 			}
 		} catch (Exception e) {
-			log.error(e.getMessage(),e);
+			LOG.error(e.getMessage(), e);
 			if (e instanceof StatusException) {
 				exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR,
 						((StatusException) e).getDesc());
@@ -273,7 +282,7 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 			tempFile.getParentFile().mkdirs();
 			tempFile.createNewFile();
 		} catch (IOException e) {
-			log.error(e.getMessage(),e);
+			LOG.error(e.getMessage(), e);
 			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "生成导出文件异常");
 			return;
 		}
@@ -286,16 +295,93 @@ public class AsyncExportServiceImpl implements AsyncExportService {
 			env.setRelativePath(filePath);
 			YunPathInfo oss = FileStorageUtil.saveFile(TASK_EXPORT_DIR, env, tempFile, null);
 
-			log.info("asyncExportExamScoreStatistics finished... " + oss.getRelativePath());
+			LOG.info("asyncExportExamScoreStatistics finished... " + oss.getRelativePath());
 			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.SUCCESS, null, oss.getRelativePath());
 		} catch (Exception e) {
-			log.info("asyncExportExamScoreStatistics error... " + e.getMessage());
+			LOG.info("asyncExportExamScoreStatistics error... " + e.getMessage());
 			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "上传至文件服务器异常");
 		} finally {
 			FileUtils.deleteQuietly(tempFile);
 		}
 	}
 
+	@Override
+	public void asyncExportExamAuditList(Long taskId, ExamAuditQuery req) {
+		List<ExamAuditInfo> auditInfos;
+		try {
+			auditInfos = examAuditService.getExamAudit(req);
+
+			if (CollectionUtils.isEmpty(auditInfos)) {
+				exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "当前条件暂无数据,任务终止");
+				return;
+			}
+			for (ExamAuditInfo examAuditInfo : auditInfos) {
+				examAuditInfo.setIdentityNumber(
+						IdentityNumberHelper.conceal(req.getRootOrgId(), examAuditInfo.getIdentityNumber()));
+			}
+
+		} catch (Exception e) {
+			LOG.error(e.getMessage(), e);
+			if (e instanceof StatusException) {
+				exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR,
+						((StatusException) e).getDesc());
+			} else {
+				exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "导出数据异常");
+			}
+			return;
+		}
+		// 导出文件的存储路径
+		String examName = auditInfos.get(0).getExamName();
+		final String filePath = String.format("/%s/%s/%s/%s/%s_监考已审.xlsx", TASK_EXPORT_DIR, req.getRootOrgId(),
+				dateDir(), randomUUID(), examName);
+		String tempFilePath = systemConfig.getTempDataDir() + File.separator + filePath;
+		File tempFile = new File(tempFilePath);
+		try {
+			tempFile.getParentFile().mkdirs();
+			tempFile.createNewFile();
+		} catch (IOException e) {
+			LOG.error(e.getMessage(), e);
+			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "生成导出文件异常");
+			return;
+		}
+		try (FileOutputStream out = new FileOutputStream(tempFile);) {
+
+			ExcelExportUtil.exportExcel(ExamAuditInfo.class, auditInfos, out);
+
+			// 上传至文件服务器
+			FileStoragePathEnvInfo env = new FileStoragePathEnvInfo();
+			env.setRootOrgId(String.valueOf(req.getRootOrgId()));
+			env.setRelativePath(filePath);
+			YunPathInfo oss = FileStorageUtil.saveFile(TASK_EXPORT_DIR, env, tempFile, null);
+
+			LOG.info("asyncExportExamAuditList finished... " + oss.getRelativePath());
+			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.SUCCESS, null, oss.getRelativePath());
+		} catch (Exception e) {
+			LOG.info("asyncExportExamAuditList error... " + e.getMessage());
+			exportTaskService.updateExportTaskStatus(taskId, ExportTaskStatus.ERROR, "上传至文件服务器异常");
+		} finally {
+			FileUtils.deleteQuietly(tempFile);
+		}
+	}
+
+	@Override
+	public void exportExamAuditList(String query, User user) {
+		ExamStudentQuery req = new JsonMapper().parseJson(query, ExamStudentQuery.class);
+		req.setRootOrgId(user.getRootOrgId());
+		Check.isNull(req, "请求参数不能为空!");
+		Check.isNull(req.getExamId(), "请先选择考试批次!");
+
+		// 创建导出任务
+		ExportTaskInfo task = new ExportTaskInfo();
+		task.setRootOrgId(user.getRootOrgId());
+		task.setExamId(req.getExamId());
+		task.setType(ExportTaskType.AUDIT);
+		task.setStatus(ExportTaskStatus.WAITING);
+		task.setCreator(user.getUserId());
+		task.setJsonParams(query);
+		exportTaskService.addExportTask(task);
+	}
+
 	private String randomUUID() {
 		return UUID.randomUUID().toString().replace("-", "");
 	}

+ 108 - 56
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamAuditServiceImpl.java

@@ -118,6 +118,113 @@ public class ExamAuditServiceImpl implements ExamAuditService {
         Check.isNull(query.getExamId(), "请先选择考试批次!");
         //封装查询条件
         Pageable pageable = SpecUtils.buildPageable(query.getPageNo(), query.getPageSize());
+
+        final String columns = ExamAuditMapper.defaultColumns();
+        SqlWrapper wrapper = getSqlWrapper(query);
+
+        long totalSize = 0;
+        //查询总记录数
+        if (query.getSelectType() == null || query.getSelectType() != SelectType.EXPORT) {
+            final String count = "count(0)";
+            final String leftJoin = "LEFT JOIN ec_oe_exam_process_record AS process ON record.id = process.exam_record_data_id";
+            String countSql = wrapper.build().replace(columns, count).replace(leftJoin," ");
+            Query countQuery = entityManager.createNativeQuery(countSql);
+            BigInteger element = (BigInteger) countQuery.getSingleResult();
+            totalSize = element.longValue();
+            if (totalSize == 0) {
+                return new PageImpl<>(Lists.newArrayList(), pageable, totalSize);
+            }
+        }
+
+        wrapper.groupBy("record.id ");
+        //查询分页记录
+        wrapper.orderBy("record.update_time", true);//需求调整20200816:按审核时间排序
+        Query dataQuery = entityManager.createNativeQuery(wrapper.build());
+
+//        dataQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(HashMap.class));
+        dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
+        if (query.getSelectType() == null || query.getSelectType() != SelectType.EXPORT) {
+            dataQuery.setFirstResult((int) pageable.getOffset());
+            dataQuery.setMaxResults(pageable.getPageSize());
+        }
+        List resultList = dataQuery.getResultList();
+
+        List<ExamAuditInfo> list = ExamAuditEntityConvert.of(resultList);
+
+        for (ExamAuditInfo examAuditInfo : list) {
+            OrgCacheBean orgBean = gainBaseDataService.getOrgBean(examAuditInfo.getOrgId());
+            examAuditInfo.setOrgName(orgBean.getName());
+
+            //将违纪类型重赋值为文本,万恶的历史原因,不该这么做的。TODO 待优化
+            if (StringUtils.isNotEmpty(examAuditInfo.getDisciplineType())) {
+                IllegallyTypeEntity illegallyType = illegallyTypeService.getIllegallyType(orgBean.getRootId(), examAuditInfo.getDisciplineType());
+                examAuditInfo.setDisciplineType(illegallyType.getName());
+            }
+
+
+            CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(examAuditInfo.getCourseId());
+            examAuditInfo.setCourseName(courseBean.getName());
+            examAuditInfo.setCourseCode(courseBean.getCode());
+            examAuditInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
+
+            //考试名称
+            ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
+            examAuditInfo.setExamName(examBean.getName());
+
+            //客观分
+            ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examAuditInfo.getExamRecordDataId());
+            examAuditInfo.setObjectiveScore(String.valueOf(examScore.getObjectiveScore()));
+
+        }
+        return new PageImpl<ExamAuditInfo>(list, pageable, totalSize);
+    }
+
+    @Override
+    public List<ExamAuditInfo> getExamAudit(ExamAuditQuery query) {
+        Check.isNull(query, "查询参数不能为空!");
+        Check.isNull(query.getExamId(), "请先选择考试批次!");
+
+        SqlWrapper wrapper = getSqlWrapper(query);
+
+        wrapper.groupBy("record.id ");
+        //查询分页记录
+        wrapper.orderBy("record.update_time", true);//需求调整20200816:按审核时间排序
+        Query dataQuery = entityManager.createNativeQuery(wrapper.build());
+        dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
+
+        List resultList = dataQuery.getResultList();
+
+        List<ExamAuditInfo> list = ExamAuditEntityConvert.of(resultList);
+
+        for (ExamAuditInfo examAuditInfo : list) {
+            OrgCacheBean orgBean = gainBaseDataService.getOrgBean(examAuditInfo.getOrgId());
+            examAuditInfo.setOrgName(orgBean.getName());
+
+            //将违纪类型重赋值为文本,万恶的历史原因,不该这么做的。TODO 待优化
+            if (StringUtils.isNotEmpty(examAuditInfo.getDisciplineType())) {
+                IllegallyTypeEntity illegallyType = illegallyTypeService.getIllegallyType(orgBean.getRootId(), examAuditInfo.getDisciplineType());
+                examAuditInfo.setDisciplineType(illegallyType.getName());
+            }
+
+            CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(examAuditInfo.getCourseId());
+            examAuditInfo.setCourseName(courseBean.getName());
+            examAuditInfo.setCourseCode(courseBean.getCode());
+            examAuditInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
+
+            //考试名称
+            ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
+            examAuditInfo.setExamName(examBean.getName());
+
+            //客观分
+            ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examAuditInfo.getExamRecordDataId());
+            examAuditInfo.setObjectiveScore(String.valueOf(examScore.getObjectiveScore()));
+
+        }
+        return list;
+    }
+
+
+    private SqlWrapper getSqlWrapper(ExamAuditQuery query){
         final String columns = ExamAuditMapper.defaultColumns();
         SqlWrapper wrapper = new SqlWrapper()
                 .select(columns).from("ec_oe_exam_audit").as("audit")
@@ -177,62 +284,7 @@ public class ExamAuditServiceImpl implements ExamAuditService {
             wrapper.and().gte("audit.update_time", query.getAuditStartTime());
             wrapper.and().lte("audit.update_time", query.getAuditEndTime());
         }
-
-        long totalSize = 0;
-        //查询总记录数
-        if (query.getSelectType() == null || query.getSelectType() != SelectType.EXPORT) {
-            final String count = "count(0)";
-            final String leftJoin = "LEFT JOIN ec_oe_exam_process_record AS process ON record.id = process.exam_record_data_id";
-            String countSql = wrapper.build().replace(columns, count).replace(leftJoin," ");
-            Query countQuery = entityManager.createNativeQuery(countSql);
-            BigInteger element = (BigInteger) countQuery.getSingleResult();
-            totalSize = element.longValue();
-            if (totalSize == 0) {
-                return new PageImpl<>(Lists.newArrayList(), pageable, totalSize);
-            }
-        }
-
-        wrapper.groupBy("record.id ");
-        //查询分页记录
-        wrapper.orderBy("record.update_time", true);//需求调整20200816:按审核时间排序
-        Query dataQuery = entityManager.createNativeQuery(wrapper.build());
-
-//        dataQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(HashMap.class));
-        dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
-        if (query.getSelectType() == null || query.getSelectType() != SelectType.EXPORT) {
-            dataQuery.setFirstResult((int) pageable.getOffset());
-            dataQuery.setMaxResults(pageable.getPageSize());
-        }
-        List resultList = dataQuery.getResultList();
-
-        List<ExamAuditInfo> list = ExamAuditEntityConvert.of(resultList);
-
-        for (ExamAuditInfo examAuditInfo : list) {
-            OrgCacheBean orgBean = gainBaseDataService.getOrgBean(examAuditInfo.getOrgId());
-            examAuditInfo.setOrgName(orgBean.getName());
-
-            //将违纪类型重赋值为文本,万恶的历史原因,不该这么做的。TODO 待优化
-            if (StringUtils.isNotEmpty(examAuditInfo.getDisciplineType())) {
-                IllegallyTypeEntity illegallyType = illegallyTypeService.getIllegallyType(orgBean.getRootId(), examAuditInfo.getDisciplineType());
-                examAuditInfo.setDisciplineType(illegallyType.getName());
-            }
-
-
-            CourseCacheBean courseBean = ExamCacheTransferHelper.getCachedCourse(examAuditInfo.getCourseId());
-            examAuditInfo.setCourseName(courseBean.getName());
-            examAuditInfo.setCourseCode(courseBean.getCode());
-            examAuditInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
-
-            //考试名称
-            ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(query.getExamId());
-            examAuditInfo.setExamName(examBean.getName());
-
-            //客观分
-            ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examAuditInfo.getExamRecordDataId());
-            examAuditInfo.setObjectiveScore(String.valueOf(examScore.getObjectiveScore()));
-
-        }
-        return new PageImpl<ExamAuditInfo>(list, pageable, totalSize);
+        return wrapper;
     }
 
     @Override

+ 4 - 4
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamCaptureServiceImpl.java

@@ -8,8 +8,6 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.impl;
 
 import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamCaptureRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
@@ -35,6 +33,8 @@ import org.apache.commons.lang3.StringUtils;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -64,8 +64,8 @@ public class ExamCaptureServiceImpl implements ExamCaptureService {
     private IllegallyTypeService illegallyTypeService;
     @Autowired
     private ExamScoreRepo examScoreRepo;
-    private static final ExamCloudLog LOG = ExamCloudLogFactory
-            .getLog(ExamCaptureServiceImpl.class);
+
+    private static final Logger LOG = LoggerFactory.getLogger(ExamCaptureServiceImpl.class);
 
     @Override
     public ExamCaptureAuditInfo getExamCaptureAuditDetail(Long examRecordDataId) {

+ 14 - 0
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordDataServiceImpl.java

@@ -1,6 +1,8 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.impl;
 
 import cn.com.qmth.examcloud.api.commons.enums.ExamType;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.CheckPaperInExamReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.CheckPaperInExamResp;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
@@ -71,4 +73,16 @@ public class ExamRecordDataServiceImpl implements ExamRecordDataService {
 		return count;
 	}
 
+	@Override
+	public CheckPaperInExamResp checkPaperInExam(CheckPaperInExamReq req) {
+		Long id=examRecordDataRepo.getRecordIdByPaperId(req.getBasePaperId());
+		CheckPaperInExamResp res=new CheckPaperInExamResp();
+		if(id==null) {
+			res.setInExam(false);
+		}else {
+			res.setInExam(true);
+		}
+		return res;
+	}
+
 }

+ 54 - 7
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordServiceImpl.java

@@ -29,6 +29,8 @@ import org.apache.commons.lang3.StringUtils;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+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.domain.PageImpl;
@@ -44,8 +46,6 @@ import com.google.common.collect.Lists;
 
 import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
 import cn.com.qmth.examcloud.core.basic.api.StudentCloudService;
 import cn.com.qmth.examcloud.core.basic.api.bean.StudentBean;
 import cn.com.qmth.examcloud.core.basic.api.request.GetStudentListByIdsReq;
@@ -93,8 +93,9 @@ import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
  */
 @Service
 public class ExamRecordServiceImpl implements ExamRecordService {
-    private static final ExamCloudLog LOG = ExamCloudLogFactory
-            .getLog(ExamRecordServiceImpl.class);
+
+    private static final Logger LOG = LoggerFactory.getLogger(ExamRecordServiceImpl.class);
+
     @Autowired
     private ExamScoreRepo examScoreRepo;
     @Autowired
@@ -156,6 +157,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
             "record_data.paper_type paperType," +
             "record_data.paper_struct_id paperStructId," +
             "record_data.info_collector infoCollector," +
+            "audit.audit_user_name audit_user_name," +
             "GROUP_CONCAT(DISTINCT process.source_ip) ip," +
 			"eoes.objective_score objectiveTotalScore," +
 			"eoes.subjective_score subjectiveTotalScore," +
@@ -165,6 +167,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
             
             " from ec_oe_exam_record_data record_data " +
             " LEFT JOIN ec_oe_exam_process_record AS process ON record_data.id = process.exam_record_data_id " +
+            " LEFT JOIN ec_oe_exam_audit AS audit ON record_data.id = audit.exam_record_data_id " +
             " LEFT JOIN ec_oe_exam_score eoes ON  record_data.id = eoes.exam_record_data_id "+
             " LEFT JOIN ec_oe_exam_student eoest ON  record_data.exam_student_id = eoest.exam_student_id "+
             " where 1=1";
@@ -210,9 +213,11 @@ public class ExamRecordServiceImpl implements ExamRecordService {
             "record_data.paper_type paper_type," +
             "record_data.paper_struct_id paper_struct_id," +
             "record_data.info_collector info_collector," +
+            "audit.audit_user_name audit_user_name," +
             "GROUP_CONCAT(DISTINCT process.source_ip) ip" +
             " from ec_oe_exam_record_data record_data " +
             " LEFT JOIN ec_oe_exam_process_record AS process ON record_data.id = process.exam_record_data_id " +
+            " LEFT JOIN ec_oe_exam_audit AS audit ON record_data.id = audit.exam_record_data_id " +
             " where 1=1";
 
     /**
@@ -232,6 +237,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
     @Override
     public Page<ExamRecordInfo> getExamRecordDetailListForPage(ExamRecordQuery query) {
         Check.isNull(query, "查询参数不能为空!");
+        Check.isNull(query.getExamId(), "请先选择考试批次!");
         query.addRecordStatus(ExamRecordStatus.EXAM_END.name());
         query.addRecordStatus(ExamRecordStatus.EXAM_OVERDUE.name());
         return this.loadData(_getExamRecordDetailListForPage(query), query.getExamId());
@@ -240,6 +246,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
     @Override
     public Page<ExamRecordInfo> getExamRecordWaitingAuditList(ExamRecordQuery query) {
         Check.isNull(query, "查询参数不能为空!");
+        Check.isNull(query.getExamId(), "请先选择考试批次!");
         //默认条件
         query.setIsAudit(false);
         query.addRecordStatus(ExamRecordStatus.EXAM_END.name());
@@ -247,9 +254,43 @@ public class ExamRecordServiceImpl implements ExamRecordService {
         return this.getExamRecordList(query);
     }
 
+    @Override
+    public List<ExamRecordInfo> getExamRecordWaitingAudit(ExamRecordQuery query) {
+        Check.isNull(query, "查询参数不能为空!");
+        //默认条件
+        query.setIsAudit(false);
+        query.addRecordStatus(ExamRecordStatus.EXAM_END.name());
+        query.addRecordStatus(ExamRecordStatus.EXAM_OVERDUE.name());
+
+        //查询条件
+        StringBuilder sqlBuilder = new StringBuilder();
+        //待审核(按原先的sql,多了一个ip字段)
+        sqlBuilder.append(EXAM_RECORD_SQL);
+        sqlBuilder.append(buildExamRecordCommonSelectCondition(query));
+        if (query.getIsWarn() != null) {
+            //只查有异常未审核
+            if (query.getIsWarn()) {
+                sqlBuilder.append(" and record_data.is_warn  = 1 and record_data.is_audit = 0 ");
+            } else {
+                sqlBuilder.append(" and record_data.is_warn  = 0 ");
+            }
+        } else {
+            sqlBuilder.append(" and ((record_data.is_warn = 0) OR (record_data.is_warn  = 1 and record_data.is_audit = 0))");
+        }
+        sqlBuilder.append(" and record_data.is_illegality = 0");
+        //查询分页记录
+        sqlBuilder.append(" group by record_data.id ");
+
+        sqlBuilder.append(" order by record_data.id desc");
+        List<ExamRecordDataEntity> entities = jdbcTemplate.query(sqlBuilder.toString(), (rs, rowNum) -> getExamRecordDataEntityByResultSet(rs));
+
+        return examRecordEntityConvert.ofList(entities);
+    }
+
     @Override
     public Long getExamRecordWaitingAuditNextId(ExamRecordQuery query, Long examRecordDataId, String next) {
         Check.isNull(query, "查询参数不能为空!");
+        Check.isNull(query.getExamId(), "请先选择考试批次!");
         //默认条件
         query.setIsWarn(true);
         query.setIsAudit(false);
@@ -299,6 +340,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
         //分页条件
         int currentNum = (query.getPageNo() - 1) * query.getPageSize();
         Check.isNull(query, "查询参数不能为空!");
+        Check.isNull(query.getExamId(), "请先选择考试批次!");
         //查询条件
         StringBuilder sqlBuilder = new StringBuilder();
         sqlBuilder.append(EXAM_RECORD_SQL);
@@ -324,7 +366,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
         });
         //查询总数
         long total = countExamRecordDetailListForPage(query);
-        Pageable pageable = new PageRequest(query.getPageNo() - 1, query.getPageSize());
+        Pageable pageable = PageRequest.of(query.getPageNo() - 1, query.getPageSize());
         Page<ExamRecordDataEntity> page = new PageImpl<ExamRecordDataEntity>(examRecordDataList, pageable, total);
         return examRecordEntityConvert.of(page);
     }
@@ -353,13 +395,15 @@ public class ExamRecordServiceImpl implements ExamRecordService {
         examRecordData.setFaceVerifyResult(IsSuccess.strToEnum(rs.getString("face_verify_result")));
         examRecordData.setBaiduFaceLivenessSuccessPercent(rs.getDouble("baidu_face_liveness_success_percent"));
         examRecordData.setIp(rs.getString("ip"));
+        examRecordData.setAuditUserName(rs.getString("audit_user_name"));
 
         return examRecordData;
     }
 
     private long countExamRecordDetailListForPage(ExamRecordQuery query) {
         StringBuilder sqlBuilder = new StringBuilder();
-        sqlBuilder.append("select count(record_data.id) from ec_oe_exam_record_data record_data where 1=1");
+        sqlBuilder.append("select count(record_data.id) from ec_oe_exam_record_data record_data " +
+                "LEFT JOIN ec_oe_exam_audit AS audit ON record_data.id = audit.exam_record_data_id where 1=1");
         sqlBuilder.append(buildExamRecordCommonSelectCondition(query));
         sqlBuilder.append(" and ((record_data.is_warn = 0) OR (record_data.is_warn  = 1 and record_data.is_audit = 1))");
         return jdbcTemplate.queryForObject(sqlBuilder.toString(), Long.class);
@@ -398,6 +442,9 @@ public class ExamRecordServiceImpl implements ExamRecordService {
         if (StringUtils.isNotBlank(query.getInfoCollector())) {
             sql.append(" and record_data.info_collector LIKE '%" + query.getInfoCollector() + "%'");
         }
+        if (StringUtils.isNotBlank(query.getAuditUserName())) {
+            sql.append(" and audit.audit_user_name LIKE '%" + query.getAuditUserName() + "%'");
+        }
         if (query.getCourseId() != null) {
             sql.append(" and record_data.course_id = " + query.getCourseId());
         }
@@ -506,7 +553,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
         });
         //查询总数
         long total = countExamRecordListForPage(query);
-        Pageable pageable = new PageRequest(query.getPageNo() - 1, query.getPageSize());
+        Pageable pageable = PageRequest.of(query.getPageNo() - 1, query.getPageSize());
 
         Page<ExamRecordDataEntity> page = new PageImpl<ExamRecordDataEntity>(examRecordDataList, pageable, total);
         return examRecordEntityConvert.of(page);

+ 3 - 3
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamStudentFinalScoreServiceImpl.java

@@ -1,7 +1,5 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.impl;
 
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
-import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
 import cn.com.qmth.examcloud.commons.util.JsonUtil;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamScoreRepo;
@@ -15,6 +13,8 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.enums.MarkingType;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamStudentFinalScoreService;
 import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -39,7 +39,7 @@ public class ExamStudentFinalScoreServiceImpl implements ExamStudentFinalScoreSe
     @Autowired
     private ExamStudentFinalScoreRepo examStudentFinalScoreRepo;
 
-    private static final ExamCloudLog LOG = ExamCloudLogFactory.getLog(ExamStudentFinalScoreServiceImpl.class);
+    private static final Logger LOG = LoggerFactory.getLogger(ExamStudentFinalScoreServiceImpl.class);
 
     @Override
     public ExamStudentFinalScoreEntity calcAndSaveFinalScore(Long examStudentId) {

+ 57 - 5
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamStudentServiceImpl.java

@@ -15,6 +15,7 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.text.DecimalFormat;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -25,6 +26,7 @@ import java.util.stream.Collectors;
 import javax.persistence.EntityManager;
 import javax.persistence.Query;
 
+import cn.com.qmth.examcloud.examwork.api.request.GetExamListReq;
 import org.apache.commons.lang3.StringUtils;
 import org.hibernate.query.NativeQuery;
 import org.hibernate.transform.Transformers;
@@ -341,6 +343,37 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         setPhone(examStudentInfoList, query.getRootOrgId());
         return examStudentInfoList;
     }
+
+    @Override
+    public List<OnHandExamInfo> queryOnlineExamEndList(Long studentId, ExamType examType) {
+        //只查没有禁用的考生
+        List<ExamStudentEntity> examStudents =
+                examStudentRepo.findByStudentIdAndEnable(studentId, true);
+
+        List<OnHandExamInfo> examStudentDtoList = new ArrayList<OnHandExamInfo>();
+        Date now = new Date();
+        for (ExamStudentEntity examStudent : examStudents) {
+            assemblingExamStudentDto(examStudent, now, examStudentDtoList, true);
+        }
+
+        for(OnHandExamInfo info:examStudentDtoList) {
+            ExamPropertyCacheBean examCycleEnabledCache = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.EXAM_CYCLE_ENABLED.name());
+            if(examCycleEnabledCache!=null&&StringUtil.isTrue(examCycleEnabledCache.getValue())) {
+                info.setExamCycleEnabled(true);
+
+                ExamPropertyCacheBean examCycleWeekCache = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.EXAM_CYCLE_WEEK.name());
+
+                info.setExamCycleWeek(JSONObject.parseArray(examCycleWeekCache.getValue()));
+                ExamPropertyCacheBean examCycleTimeRangeCache = CacheHelper.getExamProperty(info.getExamId(), ExamProperties.EXAM_CYCLE_TIME_RANGE.name());
+                info.setExamCycleTimeRange(JSONObject.parseArray(examCycleTimeRangeCache.getValue()));
+            }else {
+                info.setExamCycleEnabled(false);
+            }
+        }
+
+        return examStudentDtoList;
+    }
+
     private void setPhone(List<ExamStudentInfo> dataList,Long rootOrgId) {
     	GetStudentListByIdsReq req= new GetStudentListByIdsReq();
         BatchSetDataUtil<ExamStudentInfo> tool = new BatchSetDataUtil<ExamStudentInfo>() {
@@ -1077,7 +1110,7 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         List<OnHandExamInfo> examStudentDtoList = new ArrayList<OnHandExamInfo>();
         Date now = new Date();
         for (ExamStudentEntity examStudent : examStudents) {
-            assemblingExamStudentDto(examStudent, now, examStudentDtoList);
+            assemblingExamStudentDto(examStudent, now, examStudentDtoList, false);
         }
         
         for(OnHandExamInfo info:examStudentDtoList) {
@@ -1098,12 +1131,17 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         return examStudentDtoList;
     }
 
-    private void assemblingExamStudentDto(ExamStudentEntity examStudent, Date now, final List<OnHandExamInfo> resultList) {
+    private void assemblingExamStudentDto(ExamStudentEntity examStudent, Date now, final List<OnHandExamInfo> resultList, boolean end) {
         Long examId = examStudent.getExamId();
         Long studentId = examStudent.getStudentId();
         Long examStageId = examStudent.getExamStageId();
 
         ExamSettingsCacheBean examBean = ExamCacheTransferHelper.getCachedExam(examId, studentId, examStageId);
+
+        if (end && !ExamType.ONLINE.name().equals(examBean.getExamType())){
+            return;
+        }
+
         if (examBean.getSpecialSettingsEnabled() && examStageId != null
                 && ExamSpecialSettingsType.STAGE_BASED == examBean.getSpecialSettingsType()) {
             ExamStageCacheBean examStage = CacheHelper.getExamStage(examId, examStageId);
@@ -1112,16 +1150,25 @@ public class ExamStudentServiceImpl implements ExamStudentService {
             if (examStage.getHasValue() && !examStage.getEnable()) {
                 return;
             }
+        }
 
-            //如果当前时间超过场次结束时间,不允许考试
+        if (end) {
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(examBean.getEndTime());
+            calendar.add(Calendar.DATE, 30);
+            Date leftTime = calendar.getTime();
+            //已结束且结束时间30天以内的
+            if(now.after(leftTime)||now.before(examBean.getEndTime())){
+                return;
+            }
+        } else {
             if (now.after(examBean.getEndTime())) {
                 return;
             }
-
         }
 
         OnHandExamInfo examStudentInfo = new OnHandExamInfo();
-        resultList.add(examStudentInfo);
+
 
         examStudentInfo.setExamStudentId(examStudent.getExamStudentId());
         examStudentInfo.setStudentCode(examStudent.getStudentCode());
@@ -1161,6 +1208,9 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         } else {
             examStudentInfo.setIsObjScoreView(Boolean.valueOf(isObjScoreView));
         }
+        if (end && !examStudentInfo.getIsObjScoreView()) {
+            return;
+        }
 
         //是否开放app考试
         String appExamEnabled = ExamCacheTransferHelper.getCachedExamProperty(examId,
@@ -1171,6 +1221,8 @@ public class ExamStudentServiceImpl implements ExamStudentService {
             examStudentInfo.setAppExamEnabled(Boolean.valueOf(appExamEnabled));
         }
 
+        resultList.add(examStudentInfo);
+
     }
 
     private Integer countExamTimes(ExamStudentEntity examStudentInfo, ExamSettingsCacheBean examBean) {

+ 67 - 60
examcloud-core-oe-admin-starter/pom.xml

@@ -1,66 +1,73 @@
 <?xml version="1.0"?>
 <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
-	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>cn.com.qmth.examcloud</groupId>
-		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>v4.0.2-RELEASE</version>
-	</parent>
-	<artifactId>examcloud-core-oe-admin-starter</artifactId>
+         xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-oe-admin-starter</artifactId>
+    <packaging>jar</packaging>
 
-	<dependencies>
-		<dependency>
-			<groupId>cn.com.qmth.examcloud</groupId>
-			<artifactId>examcloud-core-oe-admin-api-provider</artifactId>
-			<version>${examcloud.version}</version>
-		</dependency>
-	</dependencies>
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-oe-admin</artifactId>
+        <version>${revision}</version>
+    </parent>
 
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-jar-plugin</artifactId>
-				<configuration>
-					<archive>
-						<manifest>
-							<mainClass>cn.com.qmth.examcloud.core.oe.admin.stater.OEAdminApp</mainClass>
-							<addClasspath>true</addClasspath>
-							<classpathPrefix>./</classpathPrefix>
-						</manifest>
-						<manifestEntries>
-							<Class-Path>../config/</Class-Path>
-						</manifestEntries>
-					</archive>
-					<excludes>
-						<exclude>templates/*</exclude>
-						<exclude>*.properties</exclude>
-						<exclude>*.xml</exclude>
-						<exclude>classpath.location</exclude>
-					</excludes>
-				</configuration>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-assembly-plugin</artifactId>
-				<configuration>
-					<finalName>examcloud-core-oe-admin</finalName>
-					<descriptors>
-						<descriptor>assembly.xml</descriptor>
-					</descriptors>
-				</configuration>
-				<executions>
-					<execution>
-						<id>make-assembly</id>
-						<phase>install</phase>
-						<goals>
-							<goal>assembly</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-		</plugins>
-	</build>
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-core-oe-admin-api-provider</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>cn.com.qmth.examcloud.core.oe.admin.stater.OEAdminApp</mainClass>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>./</classpathPrefix>
+                        </manifest>
+                        <manifestEntries>
+                            <Class-Path>../config/</Class-Path>
+                        </manifestEntries>
+                    </archive>
+                    <excludes>
+                        <exclude>templates/*</exclude>
+                        <exclude>*.properties</exclude>
+                        <exclude>*.xml</exclude>
+                        <exclude>classpath.location</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <finalName>examcloud-core-oe-admin</finalName>
+                    <descriptors>
+                        <descriptor>assembly.xml</descriptor>
+                    </descriptors>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>install</phase>
+                        <goals>
+                            <goal>assembly</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
 
 </project>

+ 1 - 1
examcloud-core-oe-admin-starter/shell/start.args

@@ -1 +1 @@
---spring.profiles.active=dev --examcloud.startup.configCenterHost=192.168.10.39
+--spring.profiles.active=dev --sys.config.center.address=192.168.10.39:8888

+ 8 - 24
examcloud-core-oe-admin-starter/shell/start.sh

@@ -1,35 +1,19 @@
 #!/bin/bash
 
-APP_MAIN_JAR="examcloud-core-oe-admin-starter-v4.0.2-RELEASE.jar"
+PROJECT_JAR="examcloud-core-oe-admin-starter-v4.1.0-SNAPSHOT.jar"
 
-FILE_PATH=$(cd `dirname $0`; pwd)
+PROJECT_JVM_ARGS=`cat start.vmoptions`
 
-JAVA_OPTS=`cat $FILE_PATH/start.vmoptions`
-APP_ARGS=`cat $FILE_PATH/start.args`
+PROJECT_ARGS=`cat start.args`
 
-PID_LIST=`ps -ef|grep $APP_MAIN_JAR|grep java|awk '{print $2}'`
+PROJECT_ARGS=$PROJECT_ARGS" --sys.config.center.secretKey="$1
 
+PID_LIST=`ps -ef | grep $PROJECT_JAR | grep java | awk '{print $2}'`
 if [ ! -z "$PID_LIST" ]; then
-    echo "[ERROR] : APP is already running!"
-#    exit -1
-fi
-
-if [ "$1" ];then
-    echo "startupCode:"$1;
-else
-    echo "[ERROR] : no arguments"
+    echo "$PROJECT_JAR is already running..."
     exit -1
 fi
 
-APP_ARGS=$APP_ARGS" --examcloud.startup.startupCode="$1
-
-echo "java options:"
-echo "$JAVA_OPTS"
-echo "args:"
-echo "$APP_ARGS"
-
-nohup java $JAVA_OPTS -jar $FILE_PATH/lib/$APP_MAIN_JAR $APP_ARGS >/dev/null 2>&1 &
-
-echo "starting......"
+nohup java $PROJECT_JVM_ARGS -jar lib/$PROJECT_JAR $PROJECT_ARGS >/dev/null 2>&1 &
 
-exit 0
+echo "$PROJECT_JAR start..."

+ 5 - 12
examcloud-core-oe-admin-starter/shell/stop.sh

@@ -1,15 +1,8 @@
 #!/bin/bash
 
-APP_MAIN_JAR="examcloud-core-oe-admin-starter-v4.0.2-RELEASE.jar"
+PROJECT_JAR="examcloud-core-oe-admin-starter-v4.1.0-SNAPSHOT.jar"
 
-FILE_PATH=$(cd `dirname $0`; pwd)
-PID_LIST=`ps -ef|grep $APP_MAIN_JAR|grep java|awk '{print $2}'`
-if [ ! -z "$PID_LIST" ]; then
-    echo "Runnable jar is $APP_MAIN_JAR."
-    for PID in $PID_LIST
-    do
-        kill -9 $PID
-    done
-    echo "stopped !"
-fi
-exit 0
+ps -ef | grep $PROJECT_JAR | grep java | awk '{printf("kill -15 %s\n",$2)}' | sh
+BUILD_ID=DONTKILLME
+
+echo "$PROJECT_JAR stop..."

+ 22 - 27
examcloud-core-oe-admin-starter/src/main/java/cn/com/qmth/examcloud/core/oe/admin/stater/OEAdminApp.java

@@ -1,6 +1,9 @@
 package cn.com.qmth.examcloud.core.oe.admin.stater;
 
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import cn.com.qmth.examcloud.core.oe.admin.dao.UniqueRuleHolder;
+import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
+import cn.com.qmth.examcloud.web.jpa.DataIntegrityViolationTransverter;
+import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.domain.EntityScan;
 import org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration;
@@ -17,14 +20,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 import org.springframework.web.multipart.MultipartResolver;
 import org.springframework.web.multipart.commons.CommonsMultipartResolver;
 
-import cn.com.qmth.examcloud.core.oe.admin.dao.UniqueRuleHolder;
-import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
-import cn.com.qmth.examcloud.web.bootstrap.AppBootstrap;
-import cn.com.qmth.examcloud.web.jpa.DataIntegrityViolationTransverter;
-import cn.com.qmth.examcloud.web.support.SpringContextHolder;
-
 @EnableAsync
-@SpringBootApplication
 @Configuration
 @EnableJpaAuditing
 @EnableTransactionManagement
@@ -34,28 +30,26 @@ import cn.com.qmth.examcloud.web.support.SpringContextHolder;
 @EntityScan(basePackages = {"cn.com.qmth"})
 @EnableJpaRepositories(basePackages = {"cn.com.qmth"})
 @EnableMongoRepositories(basePackages = {"cn.com.qmth"})
-@EnableAutoConfiguration(exclude = {MultipartAutoConfiguration.class})
+@SpringBootApplication(exclude = {MultipartAutoConfiguration.class})
 public class OEAdminApp {
-	static {
-		String runtimeLevel = System.getProperty("log.commonLevel");
-		if (null == runtimeLevel) {
-			System.setProperty("log.commonLevel", "INFO");
-		}
-		System.setProperty("hibernate.dialect.storage_engine", "innodb");
-		DataIntegrityViolationTransverter.setUniqueRules(UniqueRuleHolder.getUniqueRuleList());
-	}
 
-	public static void main(String[] args) {
-		AppBootstrap.run(OEAdminApp.class, args);
-		FileStorageUtil.initYunSite();
-		FileStorageUtil.initYunClient();
-		test();
-	}
+    static {
+        if (System.getProperty("log.commonLevel") == null) {
+            System.setProperty("log.commonLevel", "INFO");
+        }
+        System.setProperty("hibernate.dialect.storage_engine", "innodb");
+
+        DataIntegrityViolationTransverter.setUniqueRules(UniqueRuleHolder.getUniqueRuleList());
+    }
+
+    public static void main(String[] args) {
+        // AppBootstrap.run(OEAdminApp.class, args);
+        SpringApplication.run(OEAdminApp.class, args);
+
+        FileStorageUtil.initYunSite();
+        FileStorageUtil.initYunClient();
+    }
 
-	private static void test() {
-		Tester tester = SpringContextHolder.getBean(Tester.class);
-		tester.test();
-	}
     @Bean(name = "multipartResolver")
     public MultipartResolver multipartResolver() {
         CommonsMultipartResolver resolver = new CommonsMultipartResolver();
@@ -65,4 +59,5 @@ public class OEAdminApp {
         resolver.setMaxUploadSize(200 * 1024 * 1024);
         return resolver;
     }
+
 }

+ 4 - 5
examcloud-core-oe-admin-starter/src/main/java/cn/com/qmth/examcloud/core/oe/admin/stater/config/ExamCloudResourceManager.java

@@ -3,8 +3,6 @@ package cn.com.qmth.examcloud.core.oe.admin.stater.config;
 import cn.com.qmth.examcloud.api.commons.enums.DataRuleType;
 import cn.com.qmth.examcloud.api.commons.security.bean.*;
 import cn.com.qmth.examcloud.api.commons.security.enums.RoleMeta;
-import cn.com.qmth.examcloud.commons.util.PathUtil;
-import cn.com.qmth.examcloud.commons.util.PropertiesUtil;
 import cn.com.qmth.examcloud.commons.util.RegExpUtil;
 import cn.com.qmth.examcloud.core.basic.api.UserDataRuleCloudService;
 import cn.com.qmth.examcloud.core.basic.api.request.QueryUserDataRuleReq;
@@ -13,6 +11,7 @@ import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.AppCacheBean;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 import cn.com.qmth.examcloud.web.security.ResourceManager;
+import cn.com.qmth.examcloud.web.security.SecurityProperty;
 import cn.com.qmth.examcloud.web.support.ApiInfo;
 import com.google.common.collect.Sets;
 import org.apache.commons.collections4.CollectionUtils;
@@ -40,7 +39,7 @@ public class ExamCloudResourceManager implements ResourceManager {
     UserDataRuleCloudService userDataRuleCloudService;
 
     static {
-        PropertiesUtil.loadFromPath(PathUtil.getResoucePath("security.properties"));
+        SecurityProperty.loadProperties("security.properties");
     }
 
     @Override
@@ -94,8 +93,8 @@ public class ExamCloudResourceManager implements ResourceManager {
         }
 
         // 权限组集合
-        String privilegeGroups = PropertiesUtil.getString(mapping);
-        if (StringUtils.isBlank(privilegeGroups)) {
+        String privilegeGroups = SecurityProperty.getProperty(mapping);
+        if (StringUtils.isEmpty(privilegeGroups)) {
             return true;
         }
 

+ 2 - 2
examcloud-core-oe-admin-starter/src/main/java/cn/com/qmth/examcloud/core/oe/admin/stater/config/SwaggerConfig.java

@@ -16,10 +16,10 @@ import springfox.documentation.builders.RequestHandlerSelectors;
 import springfox.documentation.service.ApiInfo;
 import springfox.documentation.spi.DocumentationType;
 import springfox.documentation.spring.web.plugins.Docket;
-import springfox.documentation.swagger2.annotations.EnableSwagger2;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
 
 @Configuration
-@EnableSwagger2
+@EnableSwagger2WebMvc
 public class SwaggerConfig {
 
     @Bean

+ 5 - 5
examcloud-core-oe-admin-starter/src/main/resources/application.properties

@@ -1,6 +1,6 @@
 spring.profiles.active=dev
-
-examcloud.startup.startupCode=2000
-examcloud.startup.configCenterHost=192.168.10.39
-examcloud.startup.configCenterPort=9999
-examcloud.startup.appCode=OE
+sys.config.center.enabled=true
+sys.config.center.address=192.168.10.39:8888
+sys.config.center.namespace=examcloud
+sys.config.center.appCode=OE
+sys.config.center.secretKey=

+ 0 - 1
examcloud-core-oe-admin-starter/src/main/resources/classpath.location

@@ -1 +0,0 @@
-classpath 定位文件

+ 32 - 50
examcloud-core-oe-admin-starter/src/main/resources/log4j2.xml

@@ -2,47 +2,31 @@
 <Configuration status="WARN" monitorInterval="30">
 
     <Properties>
-        <Property name="commonLevel" value="${sys:log.commonLevel}"/>
-        <Property name="logPattern">
+        <Property name="LOG_LEVEL" value="${sys:log.commonLevel}"/>
+        <Property name="LOG_DIR" value="../logs/examcloud-core-oe-admin"/>
+        <Property name="LOG_PATTERN">
             %d{yyyy-MM-dd HH:mm:ss.SSS} | %clr{%level} | %X{TRACE_ID} %X{CALLER} | %clr{%c{1.1}:%L}{cyan} | %m%n
         </Property>
     </Properties>
 
     <Appenders>
-        <!-- 控制台 日志 -->
-        <Console name="Console" target="SYSTEM_OUT">
-            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
+        <Console name="CONSOLE_APPENDER" target="SYSTEM_OUT">
+            <PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
         </Console>
 
-        <!-- debug 日志 -->
-        <RollingFile name="DEBUG_APPENDER"
-                     fileName="./logs/debug/debug.log"
-                     filePattern="./logs/debug/debug-%d{yyyy.MM.dd.HH}-%i.log">
-            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
-            <Policies>
-                <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
-                <SizeBasedTriggeringPolicy size="100 MB"/>
-            </Policies>
-            <DefaultRolloverStrategy max="1000">
-                <Delete basePath="./logs/debug" maxDepth="1">
-                    <IfFileName glob="debug-*.log">
-                        <IfAccumulatedFileSize exceeds="2 GB"/>
-                    </IfFileName>
-                </Delete>
-            </DefaultRolloverStrategy>
-        </RollingFile>
+        <RollingFile name="FILE_APPENDER"
+                     fileName="${LOG_DIR}/debug.log"
+                     filePattern="${LOG_DIR}/debug-%d{yyyyMMdd}-%i.log">
+            <PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
 
-        <!-- 接口日志 -->
-        <RollingFile name="INTERFACE_APPENDER" fileName="./logs/interface/interface.log"
-                     filePattern="./logs/interface/interface-%d{yyyy.MM.dd.HH}-%i.log">
-            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
             <Policies>
                 <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
                 <SizeBasedTriggeringPolicy size="100 MB"/>
             </Policies>
+
             <DefaultRolloverStrategy max="1000">
-                <Delete basePath="./logs/interface" maxDepth="1">
-                    <IfFileName glob="interface-*.log">
+                <Delete basePath="${LOG_DIR}" maxDepth="1">
+                    <IfFileName glob="debug-*.log">
                         <IfAccumulatedFileSize exceeds="10 GB"/>
                     </IfFileName>
                 </Delete>
@@ -51,35 +35,33 @@
     </Appenders>
 
     <Loggers>
-        <logger name="springfox.documentation" level="ERROR"/>
-        <logger name="org.springframework" level="ERROR"/>
-        <logger name="org.hibernate" level="ERROR"/>
-        <logger name="org.apache" level="ERROR"/>
-        <logger name="org.quartz" level="ERROR"/>
-        <logger name="org.docx4j" level="ERROR"/>
-        <logger name="cn.afterturn" level="ERROR"/>
-        <logger name="com.netflix" level="ERROR"/>
-        <logger name="com.aliyun" level="ERROR"/>
-        <logger name="io.lettuce" level="ERROR"/>
-        <logger name="io.netty" level="ERROR"/>
+        <logger name="springfox.documentation" level="WARN"/>
+        <logger name="org.springframework" level="WARN"/>
+        <logger name="org.hibernate" level="WARN"/>
+        <logger name="org.apache" level="WARN"/>
+        <logger name="org.quartz" level="WARN"/>
+        <logger name="org.docx4j" level="WARN"/>
+        <logger name="cn.afterturn" level="WARN"/>
+        <logger name="com.netflix" level="WARN"/>
+        <logger name="com.aliyun" level="WARN"/>
+        <logger name="io.lettuce" level="WARN"/>
+        <logger name="io.netty" level="WARN"/>
 
+        <!--<Logger name="org.hibernate.SQL" level="DEBUG"/>-->
+        <!--<Logger name="org.hibernate.engine.transaction" level="DEBUG"/>-->
+        <!--<Logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>-->
         <!--<logger name="org.springframework.jdbc.core.JdbcTemplate" level="DEBUG"/>-->
         <!--<logger name="org.springframework.data.mongodb" level="DEBUG"/>-->
         <!--<logger name="org.springframework.data.redis" level="DEBUG"/>-->
 
-        <Logger name="cn.com.qmth" level="${commonLevel}" additivity="false">
-            <AppenderRef ref="DEBUG_APPENDER"/>
-            <AppenderRef ref="Console"/>
-        </Logger>
-
-        <Logger name="INTERFACE_LOGGER" level="${commonLevel}" additivity="false">
-            <AppenderRef ref="INTERFACE_APPENDER"/>
-            <AppenderRef ref="Console"/>
+        <Logger name="cn.com.qmth" level="${LOG_LEVEL}" additivity="false">
+            <AppenderRef ref="CONSOLE_APPENDER"/>
+            <AppenderRef ref="FILE_APPENDER"/>
         </Logger>
 
-        <Root level="${commonLevel}">
-            <AppenderRef ref="Console"/>
-            <AppenderRef ref="DEBUG_APPENDER"/>
+        <Root level="${LOG_LEVEL}">
+            <AppenderRef ref="CONSOLE_APPENDER"/>
+            <AppenderRef ref="FILE_APPENDER"/>
         </Root>
     </Loggers>
 

+ 0 - 14
examcloud-core-oe-admin-starter/src/main/resources/security-exclusions.conf

@@ -1,14 +0,0 @@
-[][/][GET]
-[][/doc][GET]
-[][/swagger/ui/index][GET]
-[/swagger-resources][][GET]
-[/swagger-resources][/configuration/ui][GET]
-[/swagger-resources][/configuration/security][GET]
-[][${springfox.documentation.swagger.v2.path:/v2/api-docs}][GET]
-[][/doc.html][GET]
-[][/docs.html][GET]
-[${$rmp.ctr.oe}/exam/student][/all/list/export][GET]
-[${$rmp.ctr.oe}/exam/student][/unfinished/list/export][GET]
-[${$rmp.ctr.oe}/exam/audit][/discipline/list/export][GET]
-[${$rmp.ctr.oe}/exam/record][/detail/list/export][GET]
-[${$rmp.ctr.oe}/exam/score][/statistic/list/export][GET]

+ 4 - 0
jenkins-prod.sh → jenkins.sh

@@ -1,4 +1,8 @@
 #!/bin/bash
+
 pwd
+mkdir -p ~/packages
 
 cp examcloud-core-oe-admin-starter/target/examcloud-core-oe-admin-distribution.zip ~/packages
+
+echo "finished..."

+ 17 - 17
pom.xml

@@ -1,22 +1,22 @@
 <?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>
-	<parent>
-		<groupId>cn.com.qmth.examcloud</groupId>
-		<artifactId>examcloud-parent</artifactId>
-		<version>v4.0.2-RELEASE</version>
-	</parent>
-	<artifactId>examcloud-core-oe-admin</artifactId>
-	<version>v4.0.2-RELEASE</version>
-	<packaging>pom</packaging>
+         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>
+    <artifactId>examcloud-core-oe-admin</artifactId>
+    <packaging>pom</packaging>
 
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-parent</artifactId>
+        <version>${revision}</version>
+        <relativePath>../examcloud-parent/pom.xml</relativePath>
+    </parent>
 
-	<modules>
-		<module>examcloud-core-oe-admin-base</module>
-		<module>examcloud-core-oe-admin-dao</module>
-		<module>examcloud-core-oe-admin-service</module>
-		<module>examcloud-core-oe-admin-api-provider</module>
-		<module>examcloud-core-oe-admin-starter</module>
-	</modules>
+    <modules>
+        <module>examcloud-core-oe-admin-base</module>
+        <module>examcloud-core-oe-admin-dao</module>
+        <module>examcloud-core-oe-admin-service</module>
+        <module>examcloud-core-oe-admin-api-provider</module>
+        <module>examcloud-core-oe-admin-starter</module>
+    </modules>
 </project>