Pārlūkot izejas kodu

merge from release_v3.0

deason 5 gadi atpakaļ
vecāks
revīzija
7ec8996143
61 mainītis faili ar 1219 papildinājumiem un 680 dzēšanām
  1. 1 1
      examcloud-core-oe-admin-api-provider/pom.xml
  2. 5 14
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/bean/ExamAuditBeanConvert.java
  3. 6 6
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamAuditController.java
  4. 14 1
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamControlController.java
  5. 41 9
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamRecordController.java
  6. 1 1
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamRecordQuestionsController.java
  7. 11 6
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamScoreController.java
  8. 5 3
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamStudentController.java
  9. 37 14
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/IllegallyTypeController.java
  10. 16 16
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/OfflineExamController.java
  11. 62 5
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamRecordCloudServiceProvider.java
  12. 12 5
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamScoreDataCloudServiceProvider.java
  13. 2 2
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/ExamStudentDataCloudServiceProvider.java
  14. 10 2
      examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/provider/SyncExamDataCloudServiceProvider.java
  15. 1 1
      examcloud-core-oe-admin-base/pom.xml
  16. 1 1
      examcloud-core-oe-admin-dao/pom.xml
  17. 7 3
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/ExamAuditRepo.java
  18. 15 11
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/ExamRecordDataRepo.java
  19. 4 1
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/IllegallyTypeRepo.java
  20. 16 6
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/entity/ExamAuditEntity.java
  21. 30 2
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/entity/ExamRecordDataEntity.java
  22. 28 1
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/entity/ExamStudentEntity.java
  23. 1 1
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/entity/ExamingRecordEntity.java
  24. 0 68
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/enums/ExamProperties.java
  25. 0 42
      examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/enums/ExamType.java
  26. 1 1
      examcloud-core-oe-admin-service/pom.xml
  27. 14 8
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamAuditService.java
  28. 7 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamCaptureService.java
  29. 41 32
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/ExamStudentService.java
  30. 5 1
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/IllegallyTypeService.java
  31. 36 24
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/OnHandExamInfo.java
  32. 13 6
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examaudit/ExamAuditEntityConvert.java
  33. 28 8
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examaudit/ExamAuditExcel.java
  34. 13 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examaudit/ExamAuditInfo.java
  35. 19 7
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examaudit/RedoAuditInfo.java
  36. 68 14
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examcapture/ExamCaptureAuditInfo.java
  37. 1 1
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordDataBean.java
  38. 11 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordEntityConvert.java
  39. 15 1
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordInfo.java
  40. 13 0
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examrecord/ExamRecordQuery.java
  41. 34 33
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/cache/ExamStudentCache.java
  42. 165 111
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamAuditServiceImpl.java
  43. 36 8
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamCaptureServiceImpl.java
  44. 0 10
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordDataCacheServiceImpl.java
  45. 2 2
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordDataServiceImpl.java
  46. 10 14
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordForMarkingServiceImpl.java
  47. 3 4
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordQuestionsServiceImpl.java
  48. 13 3
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordServiceImpl.java
  49. 1 1
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamScoreObtainQueueServiceImpl.java
  50. 1 1
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamScorePushQueueServiceImpl.java
  51. 9 7
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamScoreServiceImpl.java
  52. 12 54
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamStudentFinalScoreServiceImpl.java
  53. 263 82
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamStudentServiceImpl.java
  54. 48 17
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/IllegallyTypeServiceImpl.java
  55. 1 1
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/OfflineExamServiceImpl.java
  56. 2 2
      examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/others/ExamCacheTransferHelper.java
  57. 2 1
      examcloud-core-oe-admin-starter/pom.xml
  58. 1 1
      examcloud-core-oe-admin-starter/shell/start.sh
  59. 3 1
      examcloud-core-oe-admin-starter/shell/stop.sh
  60. BIN
      examcloud-core-oe-admin-starter/src/main/resources/templates/illegallyTypeImportTemplate.xlsx
  61. 2 2
      pom.xml

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

@@ -4,7 +4,7 @@
 	<parent>
 		<groupId>cn.com.qmth.examcloud</groupId>
 		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>2019-SNAPSHOT</version>
+		<version>v3.0-RELEASE</version>
 	</parent>
 	<artifactId>examcloud-core-oe-admin-api-provider</artifactId>
 

+ 5 - 14
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/bean/ExamAuditBeanConvert.java

@@ -17,14 +17,13 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.enums.DisciplineType;
  * @since: 2018/8/17
  */
 public class ExamAuditBeanConvert implements JsonSerializable {
-	
+
 	private Long examRecordDataId;
-	
+
 	private String disciplineDetail;
-	
+
 	private Boolean isPass;
-	
-	private DisciplineType disciplineType;
+
 
 	public Long getExamRecordDataId() {
 		return examRecordDataId;
@@ -50,12 +49,4 @@ public class ExamAuditBeanConvert implements JsonSerializable {
 		this.isPass = isPass;
 	}
 
-	public DisciplineType getDisciplineType() {
-		return disciplineType;
-	}
-
-	public void setDisciplineType(DisciplineType disciplineType) {
-		this.disciplineType = disciplineType;
-	}
-	
-}
+}

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

@@ -16,13 +16,12 @@ import cn.com.qmth.examcloud.core.oe.admin.base.utils.excel.ExportUtils;
 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.AuditStatus;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.DisciplineType;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.SelectType;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamAuditService;
 import cn.com.qmth.examcloud.core.oe.admin.service.GainBaseDataService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examaudit.*;
 import cn.com.qmth.examcloud.core.oe.admin.service.others.ExamCacheTransferHelper;
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import cn.com.qmth.examcloud.support.helper.IdentityNumberHelper;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
@@ -106,7 +105,8 @@ public class ExamAuditController extends ControllerSupport {
     public void singleAudit(@RequestParam(required = true) Long examRecordDataId,
                             @RequestParam(required = false) String disciplineDetail,
                             @RequestParam(required = true) Boolean isPass,
-                            @RequestParam(required = false) DisciplineType disciplineType) {
+                            @RequestParam(required = false) String disciplineType,
+                            @RequestParam(required = false) Long illegallyTypeId) {
         if (examRecordDataId == null) {
             throw new StatusException("singleAudit-001", "examRecordDataId不能为空");
         }
@@ -114,7 +114,7 @@ public class ExamAuditController extends ControllerSupport {
             throw new StatusException("singleAudit-002", "isPass不能为空");
         }
         User user = getAccessUser();
-        examAuditService.singleAudit(examRecordDataId, isPass, disciplineDetail, disciplineType, user);
+        examAuditService.singleAudit(examRecordDataId, isPass, disciplineDetail, disciplineType, user, illegallyTypeId);
     }
 
     @PostMapping(value = "/batch/audit")
@@ -140,7 +140,7 @@ public class ExamAuditController extends ControllerSupport {
         if (redoAuditInfo.getIsPass() == null) {
             throw new StatusException("redoAudit-002", "isPass不能为空");
         }
-        if (!redoAuditInfo.getIsPass() && StringUtils.isBlank(redoAuditInfo.getDisciplineType())) {
+        if (!redoAuditInfo.getIsPass() && null == redoAuditInfo.getIllegallyTypeId()) {
             throw new StatusException("redoAudit-003", "审核为不通过时违纪类型不能为空");
         }
         Set<Long> examIds = new HashSet<Long>();
@@ -165,4 +165,4 @@ public class ExamAuditController extends ControllerSupport {
         examAuditService.redoAudit(redoAuditInfo, user);
     }
 
-}
+}

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

@@ -1,5 +1,6 @@
 package cn.com.qmth.examcloud.core.oe.admin.api.controller;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
@@ -45,7 +46,19 @@ public class ExamControlController extends ControllerSupport {
     @GetMapping("/queryExamList")
     public List<OnHandExamInfo> queryExamList() {
         User user = getAccessUser();
-        return examStudentService.queryOnlineExamList(user.getUserId());
+        return examStudentService.queryOnlineExamList(user.getUserId(), ExamType.ONLINE);
+    }
+
+    /**
+     * 获取在线作业待考列表
+     *
+     * @return
+     */
+    @ApiOperation(value = "获取在线作业待考列表")
+    @GetMapping("/queryHomeworkList")
+    public List<OnHandExamInfo> queryHomeworkList() {
+        User user = getAccessUser();
+        return examStudentService.queryOnlineExamList(user.getUserId(),ExamType.ONLINE_HOMEWORK);
     }
 
     /**

+ 41 - 9
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamRecordController.java

@@ -7,6 +7,21 @@
 
 package cn.com.qmth.examcloud.core.oe.admin.api.controller;
 
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
 import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.Check;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.JsonMapper;
@@ -15,6 +30,7 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordForMarkingRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordForMarkingEntity;
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamCaptureService;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordQuery;
@@ -25,14 +41,6 @@ import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import cn.com.qmth.examcloud.web.support.Naked;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
-
-import javax.servlet.http.HttpServletResponse;
-import java.util.List;
 
 /**
  * 考试记录相关接口
@@ -49,7 +57,9 @@ public class ExamRecordController extends ControllerSupport {
 
     @Autowired
     private ExamRecordDataRepo examRecordDataRepo;
-
+    @Autowired
+    private ExamCaptureService examCaptureService;
+    
     @Autowired
     private ExamRecordForMarkingRepo examRecordForMarkingRepo;
 
@@ -61,6 +71,16 @@ public class ExamRecordController extends ControllerSupport {
         examRecordWaitingAuditList.getContent().forEach(p -> {
             p.setIdentityNumber(IdentityNumberHelper.conceal(p.getRootOrgId(), p.getIdentityNumber()));
         });
+        List<ExamRecordInfo> examRecordInfoList=examRecordWaitingAuditList.getContent();
+        if (examRecordInfoList != null && examRecordInfoList.size() > 0) {
+            String examType = examRecordInfoList.get(0).getExamType();
+
+            for (ExamRecordInfo examRecordInfo : examRecordInfoList) {
+                if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
+                    examRecordInfo.setVirtualCameraNames(examCaptureService.getVirtualCameraNames(examRecordInfo.getDataId()));
+                }
+            }
+        }
         return examRecordWaitingAuditList;
     }
 
@@ -90,6 +110,9 @@ public class ExamRecordController extends ControllerSupport {
                                 FileStorageUtil.realPath(examRecordForMarkingEntity.getOfflineFileUrl()));
                     }
                 }
+                if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
+                    examRecordInfo.setVirtualCameraNames(examCaptureService.getVirtualCameraNames(examRecordInfo.getDataId()));
+                }
             }
         }
         return examRecordInfoPage;
@@ -103,6 +126,15 @@ public class ExamRecordController extends ControllerSupport {
         Check.isNull(newQuery, "请求参数不能为空!");
         Check.isNull(newQuery.getExamId(), "请先选择考试批次!");
         List<ExamRecordInfo> examRecordInfoList = examRecordService.getExamRecordDetailList(newQuery);
+        if (examRecordInfoList != null && examRecordInfoList.size() > 0) {
+            String examType = examRecordInfoList.get(0).getExamType();
+
+            for (ExamRecordInfo examRecordInfo : examRecordInfoList) {
+                if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
+                    examRecordInfo.setVirtualCameraNames(examCaptureService.getVirtualCameraNames(examRecordInfo.getDataId()));
+                }
+            }
+        }
         ExportUtils.exportEXCEL("考试明细列表", ExamRecordInfo.class, examRecordInfoList, response);
     }
 

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

@@ -34,7 +34,7 @@ public class ExamRecordQuestionsController extends ControllerSupport{
 
 	@Autowired
 	private ExamRecordQuestionsService examRecordQuestionsService;
-	
+
     @Autowired
     private ExamRecordDataSyncService examRecordDataSyncService;
 	

+ 11 - 6
examcloud-core-oe-admin-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/admin/api/controller/ExamScoreController.java

@@ -23,6 +23,7 @@ import cn.com.qmth.examcloud.support.examing.ExamBoss;
 import cn.com.qmth.examcloud.support.examing.ExamRecordData;
 import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.support.helper.IdentityNumberHelper;
+import cn.com.qmth.examcloud.support.redis.RedisKeyBuilder;
 import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
@@ -99,17 +100,21 @@ public class ExamScoreController extends ControllerSupport {
                 Integer examUsedNum = 0;
 
                 for (Long examRecordDataId : unSyncedExamRecordDataIds) {
-
-                    if (!resultList.isEmpty()) {
-                        examUsedNum = resultList.get(resultList.size() - 1).getExamOrder();
-                    }
-
                     ExamRecordData examRecordData =
                             redisClient.get(RedisKeyHelper.getBuilder().examRecordDataKey(examRecordDataId), ExamRecordData.class);
                     if (null == examRecordData) {
                         throw new StatusException("100001", "考试记录的缓存数据有误");
                     }
 
+                    //考试中的数据不展示
+                    if (ExamRecordStatus.EXAM_ING == examRecordData.getExamRecordStatus()) {
+                        continue;
+                    }
+
+                    if (!resultList.isEmpty()) {
+                        examUsedNum = resultList.get(resultList.size() - 1).getExamOrder();
+                    }
+
                     ObjectiveScoreInfo cachedObjectiveScoreInfo = getCachedObjectiveScoreInfo(examRecordData);
                     cachedObjectiveScoreInfo.setExamOrder(
                             getExamOrder(examRecordData.getExamId(), examRecordData.getStudentId(), examUsedNum));
@@ -189,4 +194,4 @@ public class ExamScoreController extends ControllerSupport {
 
     }
 
-}
+}

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

@@ -134,11 +134,13 @@ public class ExamStudentController extends ControllerSupport {
 
     @PostMapping("/reexamine")
     @ApiOperation(value = "设置重考")
-    public void setReexamine(@RequestParam Long examStudentId) {
+    public void setReexamine(@RequestParam Long examStudentId,
+                             @RequestParam(required=false) String reexamineType,
+                             @RequestParam(required=false) String reexamineDetail) {
         if (examStudentId == null) {
             return;
         }
-        examStudentService.setReexamine(examStudentId);
+        examStudentService.setReexamine(examStudentId,reexamineType,reexamineDetail);
     }
 
     @PostMapping("/statistic/by/finished")
@@ -242,4 +244,4 @@ public class ExamStudentController extends ControllerSupport {
         ExportUtils.exportEXCEL("课程完成进度", CourseCompleteProgressExcel.class, resultList, response);
     }
 
-}
+}

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

@@ -10,6 +10,7 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.ExamAuditRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.IllegallyTypeRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamAuditEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.IllegallyTypeEntity;
+import cn.com.qmth.examcloud.core.oe.admin.dao.enums.DisciplineType;
 import cn.com.qmth.examcloud.core.oe.admin.service.IllegallyTypeService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.IllegallyTypeInfo;
 import cn.com.qmth.examcloud.support.enums.DataCategory;
@@ -18,13 +19,14 @@ import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.fileupload.disk.DiskFileItem;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Example;
+import org.springframework.core.io.ClassPathResource;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Sort;
@@ -37,9 +39,8 @@ import org.springframework.web.multipart.commons.CommonsMultipartFile;
 import javax.persistence.criteria.Predicate;
 import javax.servlet.http.HttpServletResponse;
 import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.io.IOException;
+import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -65,7 +66,12 @@ public class IllegallyTypeController extends ControllerSupport {
     @Autowired
     ExamAuditRepo examAuditRepo;
 
-    private static final String[] EXCEL_HEADER = new String[]{"违纪类型名称", "违纪类型代码", "排序号"};
+    private static final String[] EXCEL_HEADER = new String[]{"违纪名称", "违纪代码"};
+
+    private static final List<String> EXCLUDED_ILLEGALLY_TYPES = Arrays.asList(
+            DisciplineType.ACTION_FAILURE.name(), DisciplineType.WITHOUT_ACTION.name(),
+            DisciplineType.BATCH_NOTPASS.name(), DisciplineType.BATCH_PASS.name(),
+            DisciplineType.MACHINE_STOPPAGE.name(), DisciplineType.POWER_FAILURE.name());
 
     /**
      * 方法注释
@@ -141,11 +147,20 @@ public class IllegallyTypeController extends ControllerSupport {
         return pageInfo;
     }
 
+    /**
+     *
+     * @param name
+     * @param code
+     * @param enable
+     * @param queryScope 查询范围(目前支持all/audit,默认all)
+     * @return
+     */
     @ApiOperation(value = "查询违纪类型")
     @GetMapping("queryByNameLike")
     public List<IllegallyTypeEntity> query(@RequestParam(required = false) String name,
                                            @RequestParam(required = false) String code,
-                                           @RequestParam(required = false) Boolean enable) {
+                                           @RequestParam(required = false) Boolean enable,
+                                           @RequestParam(required = false,defaultValue = "all") String queryScope) {
 
         User accessUser = getAccessUser();
         Long rootOrgId = accessUser.getRootOrgId();
@@ -179,12 +194,22 @@ public class IllegallyTypeController extends ControllerSupport {
             return list;
         }
 
-        List<Sort.Order> orderList=new ArrayList<>();
-        orderList.add(new Sort.Order(Direction.DESC,"dataCategory"));
-        orderList.add(new Sort.Order(Direction.ASC,"id"));
+        List<Sort.Order> orderList = new ArrayList<>();
+        orderList.add(new Sort.Order(Direction.DESC, "dataCategory"));
+        orderList.add(new Sort.Order(Direction.ASC, "id"));
 
         List<IllegallyTypeEntity> list = illegallyTypeRepo.findAll(specification,
                 new Sort(orderList));
+
+
+        if (StringUtils.isNotEmpty(queryScope) && queryScope.toLowerCase().equals("audit")) {
+            //去除不需要人为选择的违纪类型
+            return list.stream()
+                    .filter(p -> !(DataCategory.SYSTEM == p.getDataCategory() &&
+                            EXCLUDED_ILLEGALLY_TYPES.contains(p.getCode())))
+                    .collect(Collectors.toList());
+        }
+
         return list;
     }
 
@@ -274,11 +299,9 @@ public class IllegallyTypeController extends ControllerSupport {
             }
 
             //判断审核表中是否存在当前类型的违纪类型
-            ExamAuditEntity examAudit =
-                    examAuditRepo.findFirstByDisciplineTypeAndCreationTimeGreaterThan(one.getCode(), one.getCreationTime());
-            boolean isIllegallyTypeInUse = (null != examAudit);
+            boolean isIllegallyTypeInUse = examAuditRepo.existsByIllegallyTypeId(typeId);
             if (isIllegallyTypeInUse) {
-                throw new StatusException("100001","违纪类型已使用不允许删除");
+                throw new StatusException("100001", "违纪类型已使用不允许删除");
             }
 
             validateRootOrgIsolation(one.getRootOrgId());
@@ -343,7 +366,7 @@ public class IllegallyTypeController extends ControllerSupport {
         List<Object[]> datas = Lists.newArrayList();
 
         for (IllegallyTypeEntity cur : list) {
-            datas.add(new Object[]{cur.getName(), cur.getCode(), cur.getSortNo()});
+            datas.add(new Object[]{cur.getName(), cur.getCode()});
         }
 
         String filePath = systemConfig.getTempDataDir() + File.separator

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

@@ -7,6 +7,8 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.util.List;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -22,8 +24,6 @@ import cn.com.qmth.examcloud.commons.exception.StatusException;
 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.dao.enums.ExamProperties;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
 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.core.oe.admin.service.others.ExamCacheTransferHelper;
@@ -34,7 +34,7 @@ import io.swagger.annotations.ApiOperation;
 
 
 /**
- * 
+ *
  * @author  	chenken
  * @date    	2018年9月5日 下午3:33:26
  * @company 	QMTH
@@ -55,11 +55,11 @@ public class OfflineExamController extends ControllerSupport{
 	 * 单位:M
 	 */
 	private static int answerMaxsize = 30;
-	
-	
+
+
 	public static final String TEMP_FILE_EXP = "offlineExam/";
-	
-	
+
+
 	/**
 	 * 获取离线考试列表
 	 * @return
@@ -71,7 +71,7 @@ public class OfflineExamController extends ControllerSupport{
 		List<OfflineExamCourseInfo> offlineExamCourseInfos = offlineExamService.getOfflineCourse(user.getUserId());
 		return offlineExamCourseInfos;
 	}
-	
+
 	/**
 	 * 开始考试
 	 * @param examStudentId
@@ -82,7 +82,7 @@ public class OfflineExamController extends ControllerSupport{
 		Check.isNull(examStudentId, "examStudentId不能为空");
 		offlineExamService.startOfflineExam(examStudentId);
 	}
-	
+
 	/**
 	 * 交卷
 	 */
@@ -96,30 +96,30 @@ public class OfflineExamController extends ControllerSupport{
 		int index = fileName.lastIndexOf(".");
 		String fileSuffix = fileName.substring(index+1, fileName.length()).toUpperCase();
 		if(!"PDF".equals(fileSuffix) && !"ZIP".equals(fileSuffix)){
-			throw new StatusException("OfflineExamController-submitPaper-001","文件格式不正确"); 
+			throw new StatusException("OfflineExamController-submitPaper-001","文件格式不正确");
 		}
-		
+
 		ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo,examRecordDataId,ExamRecordDataEntity.class);
 		if(examRecordData.getExamType() != ExamType.OFFLINE){
-			throw new StatusException("OfflineExamController-submitPaper-002","非离线考试"); 
+			throw new StatusException("OfflineExamController-submitPaper-002","非离线考试");
 		}
 		String offlineUploadFileType = ExamCacheTransferHelper.getCachedExamProperty(examRecordData.getExamId(),
 				examRecordData.getStudentId(),
 				ExamProperties.OFFLINE_UPLOAD_FILE_TYPE.name()).getValue();
 		if(StringUtils.isBlank(offlineUploadFileType) || "[]".equals(offlineUploadFileType)){
-			throw new StatusException("OfflineExamController-submitPaper-003","当前考试设置不允许上传附件"); 
+			throw new StatusException("OfflineExamController-submitPaper-003","当前考试设置不允许上传附件");
 		}
 		if(offlineUploadFileType.indexOf(fileSuffix)<0){
-			throw new StatusException("OfflineExamController-submitPaper-004","当前考试允许上传文件格式为:" + offlineUploadFileType); 
+			throw new StatusException("OfflineExamController-submitPaper-004","当前考试允许上传文件格式为:" + offlineUploadFileType);
 		}
 		//判断文件大小
 		long fileSize = file.getSize();
 		if(fileSize > answerMaxsize * 1048576){
-			throw new StatusException("OfflineExamController-submitPaper-005","文件大小不能超过"+answerMaxsize+"M"); 
+			throw new StatusException("OfflineExamController-submitPaper-005","文件大小不能超过"+answerMaxsize+"M");
 		}
 		offlineExamService.submitPaper(examRecordDataId,getUploadFile(file));
 	}
-	
+
 	private File getUploadFile(MultipartFile file){
         //建临时文件夹
 		File dirFile = new File(TEMP_FILE_EXP);

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

@@ -1,6 +1,7 @@
 package cn.com.qmth.examcloud.core.oe.admin.api.provider;
 
 import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.JsonUtil;
 import cn.com.qmth.examcloud.core.oe.admin.api.ExamRecordCloudService;
 import cn.com.qmth.examcloud.core.oe.admin.api.bean.*;
 import cn.com.qmth.examcloud.core.oe.admin.api.request.*;
@@ -268,6 +269,8 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
     @ApiOperation(value = "分页获取待阅卷的考试记录")
     @PostMapping("/getPagedToBeMarkExamRecord")
     public GetPagedToBeMarkExamRecordResp getPagedToBeMarkExamRecord(@RequestBody GetPagedToBeMarkExamRecordReq req) {
+        Long st = System.currentTimeMillis();
+
         Long examId = req.getExamId();
         String courseCode = req.getSubjectCode();
         Long startId = req.getStartId();
@@ -275,31 +278,65 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
 
         validateToBeMarkData(examId, courseCode, startId, size);
 
+        Long startTime = System.currentTimeMillis();
+
         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 + "]" +
+                    "获取考生耗时:" + (System.currentTimeMillis() - startTime) + " ms");
+        }
+
+        startTime = System.currentTimeMillis();
+
         GetPagedToBeMarkExamRecordResp resp = new GetPagedToBeMarkExamRecordResp();
         Long nextId = startId;
 
         if (null == limitedExamStuList || limitedExamStuList.isEmpty()) {
             resp.setNextId(nextId);
             resp.setToBeMarkExamRecordBeanList(null);
+
+            if (log.isDebugEnabled()) {
+                log.debug("999.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]end..." +
+                        "未找到对应的考生数据,合计耗时:" + (System.currentTimeMillis() - st) + " ms");
+            }
+
             return resp;
         }
 
         List<PagedToBeMarkExamRecordBean> pagedToBeMarkList = new ArrayList<>();
 
         CourseCacheBean course = CacheHelper.getCourse(limitedExamStuList.get(0).getCourseId());
+
+        int si = 0;//考生索引
         for (ExamStudentEntity examStu : limitedExamStuList) {
+            si++;
+
+            Long st1 = System.currentTimeMillis();
+
             //当前考生待阅卷的考试记录
             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() + "]" +
+                        "获取考生待阅卷的考试记录耗时:" + (System.currentTimeMillis() - st1) + " ms");
+            }
+
+            //如果考生找不到待阅卷的数据,直接跳过
+            if (null == examRecordForMarkingList || examRecordForMarkingList.isEmpty()) {
+                continue;
+            }
+
+            st1=System.currentTimeMillis();
+
             for (ExamRecordForMarkingEntity record : examRecordForMarkingList) {
                 PagedToBeMarkExamRecordBean pagedBean = new PagedToBeMarkExamRecordBean();
                 pagedBean.setExamId(examId);
                 pagedBean.setStudentName(examStu.getStudentName());
                 pagedBean.setStudentCode(examStu.getStudentCode());
+                pagedBean.setIdentityNumber(examStu.getIdentityNumber());
                 pagedBean.setCourseCode(courseCode);
                 pagedBean.setCourseName(course.getName());
                 pagedBean.setPaperType(examStu.getPaperType());
@@ -312,11 +349,26 @@ 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() + "]" +
+                        "构建带作答记录的待阅卷的考试记录耗时:" + (System.currentTimeMillis() - st1) + " ms");
+            }
         }
 
-        nextId = limitedExamStuList.get(limitedExamStuList.size() - 1).getId() + 1;
+        if (log.isDebugEnabled()) {
+            log.debug("2.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]" +
+                    "获取" + size + "条考生的待阅卷记录共耗时:" + (System.currentTimeMillis() - startTime) + " ms");
+        }
+
+        nextId = limitedExamStuList.get(limitedExamStuList.size() - 1).getExamStudentId() + 1;
         resp.setNextId(nextId);
         resp.setToBeMarkExamRecordBeanList(pagedToBeMarkList);
+
+        if (log.isDebugEnabled()) {
+            log.debug("999.[GET_PAGED_TO_BE_MARK_EXAM_RECORD-" + examId + "-" + courseCode + "-" + startId + "]end..." +
+                    "合计耗时:" + (System.currentTimeMillis() - st) + " ms");
+        }
         return resp;
     }
 
@@ -329,6 +381,10 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
      */
     private List<PagedToBeMarkSubjectiveAnswerBean> getSubjectiveAnswerList(Long examRecordDataId,
                                                                             Long examId, String courseCode, String paperType) {
+        //全部作答集合
+        ExamRecordQuestionsEntity allEqList =
+                examRecordQuestionsService.getExamRecordQuestionsAndFixExamRecordDataIfNecessary(examRecordDataId);
+        //主观题作答集合
         List<ExamQuestionEntity> eqList = examRecordQuestionsService.querySubjectiveAnswerList(examRecordDataId);
 
         List<PagedToBeMarkSubjectiveAnswerBean> resultList = new ArrayList<>();
@@ -344,7 +400,7 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
             //获取指定小题的题干相关信息
             QuestionCacheBean cachedQues = CacheHelper.getQuestion(examId, courseCode, paperType, eq.getQuestionId());
 
-            bean.setAnswer(getCorrectAnswer(eq.getOrder(), eq.getQuestionId(), cachedQues, eqList));
+            bean.setAnswer(getCorrectAnswer(eq.getOrder(), eq.getQuestionId(), cachedQues, allEqList.getExamQuestionEntities()));
 
             bean.setParentBody(getParentBody(cachedQues));
             bean.setBody(getBody(eq.getOrder(), eq.getQuestionId(), cachedQues, eqList));
@@ -412,11 +468,11 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
      * @param curSubNumber       当前小题号
      * @param questionId         原小题id
      * @param cachedQues         带题干的试卷结构
-     * @param subjectiveQuesList 主观题集合
+     * @param allEqList 所有作答集合
      * @return
      */
     private String getCorrectAnswer(Integer curSubNumber, String questionId,
-                                    QuestionCacheBean cachedQues, List<ExamQuestionEntity> subjectiveQuesList) {
+                                    QuestionCacheBean cachedQues, List<ExamQuestionEntity> allEqList) {
         QuestionAnswerCacheBean questionAnswerCache = CacheHelper.getQuestionAnswer(questionId);
         List<String> rightAnswerList = questionAnswerCache.getRightAnswers();
         DefaultQuestionStructure questionStructure = cachedQues.getDefaultQuestion().getMasterVersion();
@@ -427,8 +483,9 @@ public class ExamRecordCloudServiceProvider extends ControllerSupport implements
             return rightAnswerList.get(0);
         }
 
+
         //同一questionId的主观题集合(不带题干,有小题号)
-        List<ExamQuestionEntity> noBodySubjectiveQuesList = subjectiveQuesList.stream().
+        List<ExamQuestionEntity> noBodySubjectiveQuesList = allEqList.stream().
                 filter(p -> p.getQuestionId().equals(questionId)).collect(Collectors.toList());
 
         for (int i = 0; i < noBodySubjectiveQuesList.size(); i++) {

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

@@ -1,5 +1,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.core.basic.api.CourseCloudService;
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
@@ -14,12 +15,11 @@ import cn.com.qmth.examcloud.core.oe.admin.api.response.*;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.Check;
 import cn.com.qmth.examcloud.core.oe.admin.dao.*;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.*;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.DisciplineType;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamScoreService;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamStudentFinalScoreService;
 import cn.com.qmth.examcloud.core.oe.admin.service.GainBaseDataService;
+import cn.com.qmth.examcloud.core.oe.admin.service.IllegallyTypeService;
 import cn.com.qmth.examcloud.core.oe.admin.service.others.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
 import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
@@ -89,6 +89,9 @@ public class ExamScoreDataCloudServiceProvider extends ControllerSupport impleme
     @Autowired
     private ExamStudentFinalScoreService examStudentFinalScoreService;
 
+    @Autowired
+    IllegallyTypeService illegallyTypeService;
+
     @Override
     @ApiOperation(value = "根据分数id查询考试记录,学生信息,分数信息等数据")
     @PostMapping("/findExamScoreDataByScoreId")
@@ -193,9 +196,12 @@ public class ExamScoreDataCloudServiceProvider extends ControllerSupport impleme
         GetAuditDataResp resp = new GetAuditDataResp();
         if (examAuditEntity != null) {
             resp.setExamRecordDataId(examAuditEntity.getExamRecordDataId());
-            DisciplineType disciplineType = examAuditEntity.getDisciplineType();
+            String disciplineType = examAuditEntity.getDisciplineType();
             if (disciplineType != null) {
-                resp.setDisciplineType(disciplineType.getName());
+                IllegallyTypeEntity illegallyType =
+                        illegallyTypeService.getIllegallyType(examRecordData.getRootOrgId(), disciplineType);
+
+                resp.setDisciplineType(illegallyType.getName());
             }
             resp.setDisciplineDetail(examAuditEntity.getDisciplineDetail());
             resp.setCreationTime(examAuditEntity.getCreationTime());
@@ -512,7 +518,8 @@ public class ExamScoreDataCloudServiceProvider extends ControllerSupport impleme
         //只支持离线和在线考试
         ExamBean examSettings = ExamCacheTransferHelper.getDefaultCachedExam(req.getExamId());
         if (!(ExamType.ONLINE.toString().equals(examSettings.getExamType()) ||
-                ExamType.OFFLINE.toString().equals(examSettings.getExamType()))) {
+                ExamType.OFFLINE.toString().equals(examSettings.getExamType()) ||
+                ExamType.ONLINE_HOMEWORK.toString().equals(examSettings.getExamType()))) {
             throw new StatusException("100009", "不支持的考试类型");
         }
 

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

@@ -5,6 +5,7 @@ import java.util.DoubleSummaryStatistics;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -20,7 +21,6 @@ import cn.com.qmth.examcloud.core.oe.admin.api.response.GetExamStudentDataResp;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordQuestionsRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamQuestionEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordQuestionsEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordService;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamStudentService;
 import cn.com.qmth.examcloud.core.oe.admin.service.GainBaseDataService;
@@ -43,7 +43,7 @@ import io.swagger.annotations.ApiOperation;
 @RequestMapping("${$rmp.cloud.oe}/examStudentData")
 public class ExamStudentDataCloudServiceProvider extends ControllerSupport implements ExamStudentDataCloudService {
     /**
-     * 
+     *
      */
     private static final long serialVersionUID = 4538819077863159166L;
     @Autowired

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

@@ -1,5 +1,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;
@@ -138,7 +139,8 @@ public class SyncExamDataCloudServiceProvider extends ControllerSupport implemen
 
         //计算最终分数
         String examType = ExamCacheTransferHelper.getDefaultCachedExam(transitionExamRecordData.getExamId()).getExamType();
-        if (ExamType.ONLINE.name().equals(examType) || ExamType.OFFLINE.name().equals(examType)) {
+        if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)
+                || ExamType.OFFLINE.name().equals(examType)) {
             examStudentFinalScoreService.calcAndSaveFinalScore(examStudentId);
         }
 
@@ -304,7 +306,13 @@ public class SyncExamDataCloudServiceProvider extends ControllerSupport implemen
         result.setInfoCollector(examStudentEntity.getInfoCollector());
         Integer usedNum = examStudentEntity.getUsedNum();
         result.setExamOrder(getExamOrder(examId, studentId, usedNum));//考试次数
-        result.setIsReexamine(isReexamine(examId, studentId, usedNum));//是否重考
+        boolean isReexamine=isReexamine(examId, studentId, usedNum);
+        result.setIsReexamine(isReexamine);//是否重考
+        //如果有重考,则需要保存重考相关数据
+        if (isReexamine) {
+            result.setReexamineType(examStudentEntity.getReexamineType());
+            result.setReexamineDetail(examStudentEntity.getReexamineDetail());
+        }
 
         result.setCourseId(examRecordData.getCourseId());
         result.setOrgId(examRecordData.getOrgId());

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

@@ -5,7 +5,7 @@
 	<parent>
 		<groupId>cn.com.qmth.examcloud</groupId>
 		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>2019-SNAPSHOT</version>
+		<version>v3.0-RELEASE</version>
 	</parent>
 	<artifactId>examcloud-core-oe-admin-base</artifactId>
 

+ 1 - 1
examcloud-core-oe-admin-dao/pom.xml

@@ -5,7 +5,7 @@
 	<parent>
 		<groupId>cn.com.qmth.examcloud</groupId>
 		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>2019-SNAPSHOT</version>
+		<version>v3.0-RELEASE</version>
 	</parent>
 	<artifactId>examcloud-core-oe-admin-dao</artifactId>
 	

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

@@ -6,6 +6,8 @@ import org.springframework.stereotype.Repository;
 
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamAuditEntity;
 
+import java.util.Date;
+
 /**
  * @author chenken
  * @date 2018/8/15 10:05
@@ -14,7 +16,9 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamAuditEntity;
  */
 @Repository
 public interface ExamAuditRepo extends JpaRepository<ExamAuditEntity, Long>, JpaSpecificationExecutor<ExamAuditEntity> {
-	
-	public ExamAuditEntity findByExamRecordDataId(Long examRecordDataId);
-	
+
+	ExamAuditEntity findByExamRecordDataId(Long examRecordDataId);
+
+	Boolean existsByIllegallyTypeId(Long illegallyTypeId);
+
 }

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

@@ -1,5 +1,6 @@
 package cn.com.qmth.examcloud.core.oe.admin.dao;
 
+import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
@@ -7,9 +8,6 @@ import org.springframework.data.jpa.repository.Query;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
-import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.IsSuccess;
-
 import java.util.List;
 
 /**
@@ -21,15 +19,21 @@ import java.util.List;
 @Repository
 public interface ExamRecordDataRepo extends JpaRepository<ExamRecordDataEntity, Long>, JpaSpecificationExecutor<ExamRecordDataEntity> {
 
-    public List<ExamRecordDataEntity> findByExamStudentId(Long examStudentId);
+    List<ExamRecordDataEntity> findByExamStudentId(Long examStudentId);
 
+    /**
+     * 查询有效的考试记录(已结束且未违纪的)
+     *
+     * @param examStudentIdList
+     * @return
+     */
     @Query(value = "select erd.* " +
             "from ec_oe_exam_record_data erd " +
             "where erd.exam_record_status in('EXAM_END','EXAM_OVERDUE') " +
             "and erd.is_illegality=0 and (is_warn=0 or is_warn=1  and erd.is_audit=1) and erd.exam_student_id in ?1", nativeQuery = true)
-    public List<ExamRecordDataEntity> findByExamStudentIdList(List<Long> examStudentIdList);
+    List<ExamRecordDataEntity> findEffectiveDataByExamStudentIdList(List<Long> examStudentIdList);
 
-    public List<ExamRecordDataEntity> findByExamIdAndStudentCode(Long examId, String studentCode);
+    List<ExamRecordDataEntity> findByExamIdAndStudentCode(Long examId, String studentCode);
 
     List<ExamRecordDataEntity> findByExamIdAndIdentityNumberAndCourseId(Long examId, String identityNumber, Long courseId);
 
@@ -43,17 +47,17 @@ public interface ExamRecordDataRepo extends JpaRepository<ExamRecordDataEntity,
     @javax.transaction.Transactional
     @Modifying
     @Query(nativeQuery = true, value = "update ec_oe_exam_record_data set student_name = ?2,student_code = ?3,info_collector=?4 where exam_student_id = ?1")
-    public void syncUpdateExamStudentInfo(Long examStudentId, String studentName, String studentCode, String infoCollector);
+    void syncUpdateExamStudentInfo(Long examStudentId, String studentName, String studentCode, String infoCollector);
 
     @javax.transaction.Transactional
     @Modifying
     @Query(nativeQuery = true, value = "update ec_oe_exam_record_data set student_name = ?2  where student_id = ?1")
-    public void updateStudentName(Long studentId, String studentName);
+    void updateStudentName(Long studentId, String studentName);
 
     @javax.transaction.Transactional
     @Modifying
     @Query(nativeQuery = true, value = "update ec_oe_exam_record_data set course_level = ?2 where course_id = ?1")
-    public void updateCourse(Long courseId, String courseLevel);
+    void updateCourse(Long courseId, String courseLevel);
 
     /**
      * 根据studentId查询状态为"考试中"的在线考试记录
@@ -65,7 +69,7 @@ public interface ExamRecordDataRepo extends JpaRepository<ExamRecordDataEntity,
             " where t1.student_id = ?1  " +
             " and t1.exam_record_status = 'EXAM_ING' " +
             " and t1.exam_type = 'ONLINE'", nativeQuery = true)
-    public ExamRecordDataEntity findOnlineExamingRecordByStudentId(Long studentId);
+    ExamRecordDataEntity findOnlineExamingRecordByStudentId(Long studentId);
 
     /**
      * 更新考试记录中的考试作答记录id
@@ -95,4 +99,4 @@ public interface ExamRecordDataRepo extends JpaRepository<ExamRecordDataEntity,
             "where exam_record_status in('EXAM_END','EXAM_OVERDUE') and is_illegality=0 and (is_warn=0 or is_warn=1  and is_audit=1) " +
             "and exam_id=?1 and id>=?2 order by id asc limit ?3", nativeQuery = true)
     List<ExamRecordDataEntity> findLimitedDataByExamIdAndIdMoreThan(Long examId, Long startExamRecordId, int rowCount);
-}
+}

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

@@ -1,6 +1,7 @@
 package cn.com.qmth.examcloud.core.oe.admin.dao;
 
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.IllegallyTypeEntity;
+import cn.com.qmth.examcloud.support.enums.DataCategory;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.repository.query.QueryByExampleExecutor;
@@ -15,9 +16,11 @@ public interface IllegallyTypeRepo
 
 	IllegallyTypeEntity findByRootOrgIdAndCode(Long rootOrgId, String code);
 
-	IllegallyTypeEntity findByRootOrgIdAndCodeAndDataCategory(Long rootOrgId, String code,String dataCategory);
+	IllegallyTypeEntity findByRootOrgIdAndCodeAndDataCategory(Long rootOrgId, String code, DataCategory dataCategory);
 
 	List<IllegallyTypeEntity> findByRootOrgId(Long rootOrgId);
 
+	List<IllegallyTypeEntity> findByDataCategory(DataCategory dataCategory);
+
 	int countByRootOrgIdAndNameLike(Long rootOrgId, String name);
 }

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

@@ -36,8 +36,11 @@ public class ExamAuditEntity extends JpaEntity {
     /**
      * 违纪类型
      */
-    @Enumerated(EnumType.STRING)
-    private DisciplineType disciplineType;
+    private String disciplineType;
+    /**
+     * 违纪类型id(新加字段20200529 需求调整:由枚举,改为数据库管理)
+     */
+    private Long illegallyTypeId;
 
     /**
      * 违纪详情
@@ -98,20 +101,27 @@ public class ExamAuditEntity extends JpaEntity {
         this.examRecordDataId = examRecordDataId;
     }
 
-    public DisciplineType getDisciplineType() {
+    public String getDisciplineType() {
         return disciplineType;
     }
 
-    public void setDisciplineType(DisciplineType disciplineType) {
+    public void setDisciplineType(String disciplineType) {
         this.disciplineType = disciplineType;
     }
 
-	public String getAuditUserName() {
+    public String getAuditUserName() {
 		return auditUserName;
 	}
 
 	public void setAuditUserName(String auditUserName) {
 		this.auditUserName = auditUserName;
 	}
-    
+
+    public Long getIllegallyTypeId() {
+        return illegallyTypeId;
+    }
+
+    public void setIllegallyTypeId(Long illegallyTypeId) {
+        this.illegallyTypeId = illegallyTypeId;
+    }
 }

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

@@ -1,7 +1,7 @@
 package cn.com.qmth.examcloud.core.oe.admin.dao.entity;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.IsSuccess;
 import cn.com.qmth.examcloud.web.jpa.JpaEntity;
 import org.hibernate.annotations.DynamicInsert;
@@ -204,6 +204,18 @@ public class ExamRecordDataEntity extends JpaEntity {
      */
     private Double faceLandmarkVal;
 
+    /**
+     * 重考理由
+     */
+    @Column(length = 20)
+    private String reexamineType;
+
+    /**
+     * 重考理由详情
+     */
+    @Column(length = 200)
+    private String reexamineDetail;
+
     public Long getId() {
         return id;
     }
@@ -521,4 +533,20 @@ public class ExamRecordDataEntity extends JpaEntity {
     public void setExamRecordQuestionsId(String examRecordQuestionsId) {
         this.examRecordQuestionsId = examRecordQuestionsId;
     }
-}
+
+    public String getReexamineType() {
+        return reexamineType;
+    }
+
+    public void setReexamineType(String reexamineType) {
+        this.reexamineType = reexamineType;
+    }
+
+    public String getReexamineDetail() {
+        return reexamineDetail;
+    }
+
+    public void setReexamineDetail(String reexamineDetail) {
+        this.reexamineDetail = reexamineDetail;
+    }
+}

+ 28 - 1
examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/entity/ExamStudentEntity.java

@@ -150,6 +150,18 @@ public class ExamStudentEntity extends JpaEntity {
 	@Column(name = "enable")
 	private Boolean enable;
 
+	/**
+	 * 重考理由
+	 */
+	@Column(length = 20)
+	private String reexamineType;
+
+	/**
+	 * 重考理由详情
+	 */
+	@Column(length = 200)
+	private String reexamineDetail;
+
 	public Long getId() {
 		return id;
 	}
@@ -318,4 +330,19 @@ public class ExamStudentEntity extends JpaEntity {
 		this.enable = enable;
 	}
 
-}
+	public String getReexamineType() {
+		return reexamineType;
+	}
+
+	public void setReexamineType(String reexamineType) {
+		this.reexamineType = reexamineType;
+	}
+
+	public String getReexamineDetail() {
+		return reexamineDetail;
+	}
+
+	public void setReexamineDetail(String reexamineDetail) {
+		this.reexamineDetail = reexamineDetail;
+	}
+}

+ 1 - 1
examcloud-core-oe-admin-dao/src/main/java/cn/com/qmth/examcloud/core/oe/admin/dao/entity/ExamingRecordEntity.java

@@ -1,6 +1,6 @@
 package cn.com.qmth.examcloud.core.oe.admin.dao.entity;
 
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.web.jpa.JpaEntity;
 
 import javax.persistence.*;

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

@@ -1,68 +0,0 @@
-package cn.com.qmth.examcloud.core.oe.admin.dao.enums;
-
-/**
- * 
- * @author  	chenken
- * @date    	2018年11月15日 下午5:37:35
- * @company 	QMTH
- * @description 考试属性
- */
-public enum ExamProperties {
-
-	SCORE_PUBLISHING("发布成绩"),
-	IS_ENTRANCE_EXAM("是否入学考试"),
-	FREEZE_TIME("交卷冻结时间"),
-	EXAM_RECONNECT_TIME("断点续考时间"),
-	BEFORE_EXAM_REMARK("考前说明"),
-	AFTER_EXAM_REMARK("考后说明"),
-	SHOW_CHEATING_REMARK("是否展示作弊"),
-	CHEATING_REMARK("作弊说明"),
-	PRACTICE_TYPE("练习模式"),
-	SINGLE_EDIT("单选题补充说明是否可填"),
-	MUTIPLE_EDIT("多选题补充说明是否可填"),
-	BOOL_EDIT("判断题补充说明是否可填"),
-	FILL_BLANK_EDIT("填空题补充说明是否可填"),
-	SINGLE_ANSWER_REMARK("单选题补充说明"),
-	MUTIPLE_ANSWER_REMARK("多选题补充说明"),
-	BOOL_ANSWER_REMARK("判断题补充说明"),
-	FILL_BLANK_REMARK("填空题补充说明"),
-	TEXT_ANSWER_REMARK("问答题补充说明"),
-	nestedAnswerRemark("套题补充说明"),
-	IS_FACE_ENABLE("是否启用人脸识别"),
-	IS_FACE_CHECK("进入考试是否验证人脸识别"),
-	WARN_THRESHOLD("人脸检测预警阈值"),
-	MARKING_TYPE("阅卷方式"),
-	IS_FACE_VERIFY("是否开启人脸活体检测"),
-	FACE_VERIFY_START_MINUTE("活体检测开始分钟数"),
-	FACE_VERIFY_END_MINUTE("活体检测结束分钟数"),
-	ADD_FACE_VERIFY_OUT_FREEZE_TIME("冻结时间外新加人脸活体检测"),
-	OUT_FREEZE_TIME_FACE_VERIFY_START_MINUTE("冻结时间外活体检测开始分钟数"),
-	OUT_FREEZE_TIME_FACE_VERIFY_END_MINUTE("冻结时间外活体检测结束分钟数"),
-	IP_LIMIT("是否IP限制"),
-	IP_ADDRESSES("IP白名单"),
-	IS_OBJ_SCORE_VIEW("是否显示客观题成绩"),
-	CAN_UPLOAD_ATTACHMENT("是否允许上传附件(离线考试)"),
-	LIVING_WARN_THRESHOLD("人脸真实性阈值"),
-	MARKING_TASK_BUILDED("阅卷是否生成评卷任务"),
-	OFFLINE_UPLOAD_FILE_TYPE("离线考试上传文件类型"),
-	PUSH_SCORE("是否推送分数"),
-	MAX_INTERRUPT_NUM("最大断点续考次数"),
-	IS_STRANGER_ENABLE("是否启用陌生人检测"),
-	LIMITED_IF_NO_SPECIAL_SETTINGS("无特殊设置时禁止考试"),
-	WEIXIN_ANSWER_ENABLED("是否开放微信小程序作答");
-	
-	private ExamProperties(String desc){
-		this.desc = desc;
-	}
-	
-	private String desc;
-
-	public String getDesc() {
-		return desc;
-	}
-
-	public void setDesc(String desc) {
-		this.desc = desc;
-	}
-	
-}

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

@@ -1,42 +0,0 @@
-package cn.com.qmth.examcloud.core.oe.admin.dao.enums;
-
-
-/**
- * @author ting.yin
- * @Description: 考试类型
- * @date 2017年1月5日
- */
-public enum ExamType {
-    /**
-     * 传统考试
-     */
-    TRADITION,
-    /**
-     * 在线考试
-     */
-    ONLINE,
-    /**
-     * 在线练习
-     */
-    PRACTICE,
-
-    /**
-     * 离线考试
-     */
-    OFFLINE,
-
-    /**
-     * 分布式印刷考试
-     */
-    PRINT_EXAM;
-
-    public static ExamType strToEnum(String str) {
-        for (ExamType examType : ExamType.values()) {
-            if (examType.name().equals(str)) {
-                return examType;
-            }
-        }
-        return null;
-    }
-
-}

+ 1 - 1
examcloud-core-oe-admin-service/pom.xml

@@ -5,7 +5,7 @@
 	<parent>
 		<groupId>cn.com.qmth.examcloud</groupId>
 		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>2019-SNAPSHOT</version>
+		<version>v3.0-RELEASE</version>
 	</parent>
 	<artifactId>examcloud-core-oe-admin-service</artifactId>
 

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

@@ -45,30 +45,35 @@ public interface ExamAuditService {
 
     /**
      * 监考待审-批量审核
+     *
      * @param examRecordDataIds
      * @param isPass
      * @param user
      */
-    void batchAudit(List<Long> examRecordDataIds, Boolean isPass,User user);
+    void batchAudit(List<Long> examRecordDataIds, Boolean isPass, User user);
 
     /**
      * 单个审核
+     *
      * @param examRecordDataId
      * @param isPass
      * @param disciplineDetail
      * @param disciplineType
+     * @param illegallyTypeId
      */
-	void singleAudit(Long examRecordDataId, Boolean isPass,String disciplineDetail, DisciplineType disciplineType,User user);
+    void singleAudit(Long examRecordDataId, Boolean isPass, String disciplineDetail, String disciplineType, User user, Long illegallyTypeId);
 
-	/**
-	 * 重新审核
-	 * @param redoAuditInfo
-	 * @param user
-	 */
+    /**
+     * 重新审核
+     *
+     * @param redoAuditInfo
+     * @param user
+     */
     void redoAudit(RedoAuditInfo redoAuditInfo, User user);
 
     /**
      * 活体检测失败,系统审核
+     *
      * @param examRecordDataId
      * @param rootOrgId
      */
@@ -76,8 +81,9 @@ public interface ExamAuditService {
 
     /**
      * 抓拍照片为0,系统审核
+     *
      * @param examRecordDataId
      */
     void saveExamAuditByNoPhoto(Long examRecordDataId);
 
-}
+}

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

@@ -36,4 +36,11 @@ public interface ExamCaptureService {
      */
     List<ExamCaptureInfo> getExamCaptureList(Long examRecordDataId);
 
+    /**
+     * 获取虚拟摄像头名称
+     * @param examRecordDataId
+     * @return
+     */
+    String getVirtualCameraNames(Long examRecordDataId);
+
 }

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

@@ -9,6 +9,7 @@ package cn.com.qmth.examcloud.core.oe.admin.service;
 
 import java.util.List;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import org.springframework.data.domain.Page;
 
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.OnHandExamInfo;
@@ -33,7 +34,7 @@ public interface ExamStudentService {
      * @param examStudents
      * @return
      */
-	List<Long> saveExamStudentList(List<ExamStudentInfo> examStudents);
+    List<Long> saveExamStudentList(List<ExamStudentInfo> examStudents);
 
     /**
      * 同步考生(部分)数据
@@ -58,10 +59,10 @@ public interface ExamStudentService {
      * @return
      */
     Page<ExamStudentInfo> getExamStudentListPage(ExamStudentQuery query);
-    
-    
+
+
     public List<ExamStudentInfo> getExamStudentInfoList(ExamStudentQuery query);
-    
+
     /**
      * 查询重考考生列表(分页)
      *
@@ -94,41 +95,49 @@ public interface ExamStudentService {
      * @return
      */
     ExamStudentInfo getExamStudentInfo(Long examStudentId);
+
     /**
      * 查询课程信息
+     *
      * @param examId
      * @param orgId
      * @return
      */
-	List<Long> findCoursesFromExamStudent(Long examId, Long orgId);
-
-	/**
-	 * 设置重考
-	 * @param examStudentId
-	 */
-	public void setReexamine(Long examStudentId);
-	/**
-	 * 课程进度查询
-	 * @param examId
-	 * @param courseId
-	 */
-	public List<CourseProgressInfo> queryCourseProgressInfos(Long examId, Long courseId,String orderColumn);
-
-	/**
-	 * @Author lideyin
-	 * @Description 获取指定数量的考生数据
-	 * @Date 2019/7/18 14:36
-	 * @Param [ examId, startId, size]
-	 * @return java.util.List<cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamStudentInfo>
-	 */
-	public List<ExamStudentInfo> getLimitExamStudentList(Long examId,Long startId,Integer size);
-
-	/**
+    List<Long> findCoursesFromExamStudent(Long examId, Long orgId);
+
+    /**
+     * 设置重考
+     *
+     * @param examStudentId
+     * @param reexamineType
+     * @param reexamineDetail
+     */
+    public void setReexamine(Long examStudentId, String reexamineType, String reexamineDetail);
+
+    /**
+     * 课程进度查询
+     *
+     * @param examId
+     * @param courseId
+     */
+    public List<CourseProgressInfo> queryCourseProgressInfos(Long examId, Long courseId, String orderColumn);
+
+    /**
+     * @return java.util.List<cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamStudentInfo>
+     * @Author lideyin
+     * @Description 获取指定数量的考生数据
+     * @Date 2019/7/18 14:36
+     * @Param [ examId, startId, size]
+     */
+    public List<ExamStudentInfo> getLimitExamStudentList(Long examId, Long startId, Integer size);
+
+    /**
      * 获取在线考试待考列表
-     * @param studentId
+     *
+     * @param studentId 学生id
+     * @param examType  考试类型
      * @return
      */
-    public List<OnHandExamInfo> queryOnlineExamList(Long studentId);
-    
+    public List<OnHandExamInfo> queryOnlineExamList(Long studentId, ExamType examType);
 
-}
+}

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

@@ -15,7 +15,11 @@ import java.util.Map;
  */
 public interface IllegallyTypeService {
 
-	/**
+    IllegallyTypeEntity getIllegallyType(Long rootOrgId, String code);
+
+    List<IllegallyTypeEntity> getSystemIllegallyTypes();
+
+    /**
 	 * 方法注释
 	 *
 	 * @author WANGWEI

+ 36 - 24
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/OnHandExamInfo.java

@@ -12,47 +12,47 @@ public class OnHandExamInfo implements JsonSerializable{
     private static final long serialVersionUID = 6364550318267288565L;
 
     private Long examStudentId;//考试报考ID
-    
+
     private Long examId;//网考批次ID
-    
+
     private String examName;//批次名称
-    
+
     private String studentName;//考生名称
-    
+
     private String studentCode;//考生学号
-    
+
     private String identityNumber;//身份证号码
-    
+
     private String specialtyName;//专业名称
-    
+
     private String specialtyLevel;//层次
-    
+
     private Long courseId;//课程ID
-    
+
     private String courseName;//课程名称
-    
+
     private String courseCode;//课程代码
-    
+
     private String courseLevel;//课程层次
-    
+
     private Long orgId;//学校中心ID
-    
+
     private String orgName;//学习中心名称
-    
+
     private String isPhotoUpload;//是否上传照片
-    
+
     private int paperMins;//考试时长
-    
+
     private int allowExamCount;//允许考试次数
-    
+
     private Date startTime;//考试时间范围开始时间
-    
+
     private Date endTime; //考试时间范围结束时间
-    
+
     private Long rootOrgId;//机构ID
-    
+
     private String isFinished;//是否缺考
-    
+
     /**
      * 考试状态
      */
@@ -70,12 +70,17 @@ public class OnHandExamInfo implements JsonSerializable{
      * 进入考试是否验证人脸识别(强制、非强制)
      */
     private Boolean faceCheck;
-    
+
     /**
      * 是否显示客观分
      */
     private Boolean isObjScoreView;
 
+    /**
+     * 是否允许app考试
+     */
+    private Boolean appExamEnabled;
+
 
     public String getStudentName() {
         return studentName;
@@ -84,7 +89,7 @@ public class OnHandExamInfo implements JsonSerializable{
     public void setStudentName(String studentName) {
         this.studentName = studentName;
     }
-    
+
     public String getStudentCode() {
         return studentCode;
     }
@@ -285,5 +290,12 @@ public class OnHandExamInfo implements JsonSerializable{
     public void setIsObjScoreView(Boolean isObjScoreView) {
         this.isObjScoreView = isObjScoreView;
     }
-    
+
+    public Boolean getAppExamEnabled() {
+        return appExamEnabled;
+    }
+
+    public void setAppExamEnabled(Boolean appExamEnabled) {
+        this.appExamEnabled = appExamEnabled;
+    }
 }

+ 13 - 6
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examaudit/ExamAuditEntityConvert.java

@@ -12,6 +12,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import com.mysql.cj.util.StringUtils;
 import org.apache.commons.beanutils.BeanUtils;
 import org.springframework.data.domain.Page;
 
@@ -49,11 +50,11 @@ public class ExamAuditEntityConvert {
                     info.setFaceVerifyResult(result.getDesc());
                 }
 
-                DisciplineType disciplineType = DisciplineType.tramsformByType(info.getDisciplineType());
-                if(disciplineType!=null){
-                	info.setDisciplineType(disciplineType.getName());	
-                }
-                
+//                DisciplineType disciplineType = DisciplineType.tramsformByType(info.getDisciplineType());
+//                if (disciplineType != null) {
+//                    info.setDisciplineType(disciplineType.getName());
+//                }
+
                 list.add(info);
             } catch (Exception e) {
                 throw new ExamCloudRuntimeException(e.getMessage(), e.getCause());
@@ -86,9 +87,15 @@ public class ExamAuditEntityConvert {
             excel.setFaceStrangerCount(e.getFaceStrangerCount());
             excel.setFaceTotalCount(e.getFaceTotalCount());
             excel.setFaceSuccessPercent(e.getFaceSuccessPercent());
+            if (!StringUtils.isNullOrEmpty(e.getDisciplineDetail()) && e.getDisciplineDetail().indexOf("&&") != -1) {
+                excel.setDisciplineDetail(e.getDisciplineDetail().replace("&&","\r\n"));
+            } else {
+                excel.setDisciplineDetail(e.getDisciplineDetail());
+            }
+            excel.setObjectiveScore(Double.valueOf(e.getObjectiveScore()));
             list.add(excel);
         });
         return list;
     }
 
-}
+}

+ 28 - 8
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examaudit/ExamAuditExcel.java

@@ -25,28 +25,32 @@ public class ExamAuditExcel implements JsonSerializable {
     private Long examRecordDataId;
     @ExcelProperty(name = "学习中心", index = 2)
     private String orgName;
-    @ExcelProperty(name = "违纪类型", index = 12)
+    @ExcelProperty(name = "违纪类型", index = 13)
     private String disciplineType;
     @ExcelProperty(name = "批次名称", index = 1)
     private String examName;
-    @ExcelProperty(name = "学号", index = 6)
+    @ExcelProperty(name = "学号", index = 7)
     private String studentCode;
-    @ExcelProperty(name = "姓名", index = 7)
+    @ExcelProperty(name = "姓名", index = 8)
     private String studentName;
     @ExcelProperty(name = "科目代码", index = 4)
     private String courseCode;
     @ExcelProperty(name = "考试科目", index = 3)
     private String courseName;
-    @ExcelProperty(name = "课程层次", index = 5)
+    @ExcelProperty(name = "课程层次", index = 6)
     private String courseLevel;
-    @ExcelProperty(name = "成功次数", index = 9)
+    @ExcelProperty(name = "成功次数", index = 10)
     private Integer faceSuccessCount;
-    @ExcelProperty(name = "陌生人记录", index = 10)
+    @ExcelProperty(name = "陌生人记录", index = 11)
     private Integer faceStrangerCount;
-    @ExcelProperty(name = "校验次数", index = 8)
+    @ExcelProperty(name = "校验次数", index = 9)
     private Integer faceTotalCount;
-    @ExcelProperty(name = "成功率", index = 11)
+    @ExcelProperty(name = "成功率", index = 12)
     private Double faceSuccessPercent;
+    @ExcelProperty(name = "客观题总分", index = 5)
+    private Double objectiveScore;
+    @ExcelProperty(name = "违纪描述", index = 14)
+    private String disciplineDetail;
     
     public Long getExamRecordDataId() {
 		return examRecordDataId;
@@ -151,4 +155,20 @@ public class ExamAuditExcel implements JsonSerializable {
     public void setOrgName(String orgName) {
         this.orgName = orgName;
     }
+
+    public String getDisciplineDetail() {
+        return disciplineDetail;
+    }
+
+    public void setDisciplineDetail(String disciplineDetail) {
+        this.disciplineDetail = disciplineDetail;
+    }
+
+    public Double getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(Double objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
 }

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

@@ -163,6 +163,11 @@ public class ExamAuditInfo implements JsonSerializable {
      */
     private Double faceLandmarkVal;
 
+    /**
+     * 客观题得分总分
+     */
+    private String objectiveScore;
+
     public Long getId() {
         return id;
     }
@@ -450,4 +455,12 @@ public class ExamAuditInfo implements JsonSerializable {
     public void setOrgName(String orgName) {
         this.orgName = orgName;
     }
+
+    public String getObjectiveScore() {
+        return objectiveScore;
+    }
+
+    public void setObjectiveScore(String objectiveScore) {
+        this.objectiveScore = objectiveScore;
+    }
 }

+ 19 - 7
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examaudit/RedoAuditInfo.java

@@ -6,7 +6,7 @@ import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
 
 
 /**
- * 
+ *
  * @author  	chenken
  * @date    	2019年1月15日 上午9:59:14
  * @company 	QMTH
@@ -15,22 +15,27 @@ import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
 public class RedoAuditInfo implements JsonSerializable{
 
 	/**
-	 * 
+	 *
 	 */
 	private static final long serialVersionUID = 5158278733859663008L;
-	
+
 	private List<Long> examRecordDataIds;
-	
+
 	/**
 	 * 是否通过
 	 */
 	private Boolean isPass;
-	
+
+	/**
+	 * 违纪类型id
+	 */
+	private Long illegallyTypeId;
+
 	/**
 	 * 违纪类型
 	 */
 	private String disciplineType;
-	
+
 	/**
 	 * 违纪详情
 	 */
@@ -67,5 +72,12 @@ public class RedoAuditInfo implements JsonSerializable{
 	public void setDisciplineDetail(String disciplineDetail) {
 		this.disciplineDetail = disciplineDetail;
 	}
-	
+
+	public Long getIllegallyTypeId() {
+		return illegallyTypeId;
+	}
+
+	public void setIllegallyTypeId(Long illegallyTypeId) {
+		this.illegallyTypeId = illegallyTypeId;
+	}
 }

+ 68 - 14
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/bean/examcapture/ExamCaptureAuditInfo.java

@@ -8,6 +8,7 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.bean.examcapture;
 
 import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+import cn.com.qmth.examcloud.core.oe.admin.base.utils.excel.ExcelProperty;
 
 /**
  * 考试抓拍检测信息
@@ -17,7 +18,7 @@ import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
  */
 public class ExamCaptureAuditInfo implements JsonSerializable {
     /**
-	 * 
+	 *
 	 */
 	private static final long serialVersionUID = 6991258456890821018L;
 
@@ -25,20 +26,20 @@ public class ExamCaptureAuditInfo implements JsonSerializable {
      * 考试记录ID
      */
 	private Long examRecordDataId;
-	
+
     private Long studentId;
-    
+
     private String studentName;
-    
+
     private String studentCode;
-    
+
     private String identityNumber;
-    
+
     private String courseCode;
-    
+
     private String courseName;
-    
-    
+
+
     /**
      * 审核状态
      */
@@ -88,12 +89,12 @@ public class ExamCaptureAuditInfo implements JsonSerializable {
      * 人脸五官坐标比对值
      */
     private Double faceLandmarkVal;
-    
+
     /**
      * 百度人脸活体检测通过率
      */
     private Double baiduFaceLivenessSuccessPercent;
-    
+
     /**
      * 虚拟摄像头名称
      */
@@ -103,6 +104,27 @@ public class ExamCaptureAuditInfo implements JsonSerializable {
      * 同步抓拍照片URL
      */
     private String syncCaptureFileUrl;
+
+    /**
+     * 学习中心名称
+     */
+    private String orgName;
+
+    /**
+     * 年级
+     */
+    private String grade;
+
+    /**
+     * 课程层次
+     */
+    private String courseLevel;
+
+    /**
+     * 客观题总分
+     */
+    private String objectiveTotalScore;
+
     public String getStatus() {
         return status;
     }
@@ -279,12 +301,44 @@ public class ExamCaptureAuditInfo implements JsonSerializable {
 	public void setVirtualCameraNames(String virtualCameraNames) {
 		this.virtualCameraNames = virtualCameraNames;
 	}
-    
-public String getSyncCaptureFileUrl() {
+
+	public String getSyncCaptureFileUrl() {
         return syncCaptureFileUrl;
     }
 
     public void setSyncCaptureFileUrl(String syncCaptureFileUrl) {
         this.syncCaptureFileUrl = syncCaptureFileUrl;
     }
-}
+
+    public String getOrgName() {
+        return orgName;
+    }
+
+    public void setOrgName(String orgName) {
+        this.orgName = orgName;
+    }
+
+    public String getGrade() {
+        return grade;
+    }
+
+    public void setGrade(String grade) {
+        this.grade = grade;
+    }
+
+    public String getCourseLevel() {
+        return courseLevel;
+    }
+
+    public void setCourseLevel(String courseLevel) {
+        this.courseLevel = courseLevel;
+    }
+
+    public String getObjectiveTotalScore() {
+        return objectiveTotalScore;
+    }
+
+    public void setObjectiveTotalScore(String objectiveTotalScore) {
+        this.objectiveTotalScore = objectiveTotalScore;
+    }
+}

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

@@ -2,9 +2,9 @@ package cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord;
 
 import java.util.Date;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.IsSuccess;
 
 public class ExamRecordDataBean implements JsonSerializable {

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

@@ -12,7 +12,9 @@ import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
 import cn.com.qmth.examcloud.core.oe.admin.base.Constants;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.DateUtils;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
+import cn.com.qmth.examcloud.core.oe.admin.dao.ExamScoreRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
+import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamScoreEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.CourseLevel;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.IsSuccess;
@@ -48,6 +50,10 @@ public class ExamRecordEntityConvert {
 
     @Autowired
     private GainBaseDataService gainBaseDataService;
+
+    @Autowired
+    private ExamScoreRepo examScoreRepo;
+
     public  ExamRecordInfo of(ExamRecordDataEntity recordData,Map<String,Object> cahcheMap) {
         if (recordData == null) {
             return null;
@@ -137,6 +143,11 @@ public class ExamRecordEntityConvert {
             info.setFaceVerifyResult(result.getDesc());
         }
         info.setFaceLandmarkVal(recordData.getFaceLandmarkVal());
+
+        //ldy20200108需求变更:
+        ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(recordData.getId());
+        info.setObjectiveTotalScore(String.valueOf(examScore.getObjectiveScore()));
+
         return info;
     }
 

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

@@ -270,7 +270,11 @@ public class ExamRecordInfo implements JsonSerializable {
      */
     private String offlineFileUrl;
     
-
+    /**
+     * 虚拟摄像头名称
+     */
+    @ExcelProperty(name = "虚拟摄像头名称", width = 30, index = 31)
+    private String virtualCameraNames;
     public Long getId() {
         return id;
     }
@@ -703,5 +707,15 @@ public class ExamRecordInfo implements JsonSerializable {
 	public void setOfflineFileUrl(String offlineFileUrl) {
 		this.offlineFileUrl = offlineFileUrl;
 	}
+
+    
+    public String getVirtualCameraNames() {
+        return virtualCameraNames;
+    }
+
+    
+    public void setVirtualCameraNames(String virtualCameraNames) {
+        this.virtualCameraNames = virtualCameraNames;
+    }
     
 }

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

@@ -73,6 +73,8 @@ public class ExamRecordQuery implements JsonSerializable {
     private String startTime;
     @ApiModelProperty("考试结束时间")
     private String endTime;
+    @ApiModelProperty("是否有虚拟设备")
+    private Boolean hasVirtual;
     
     public ExamRecordQuery addRecordStatus(String recordStatus) {
         if (recordStatuses == null) {
@@ -273,4 +275,15 @@ public class ExamRecordQuery implements JsonSerializable {
 		this.isWarn = isWarn;
 	}
 
+    
+    public Boolean getHasVirtual() {
+        return hasVirtual;
+    }
+
+    
+    public void setHasVirtual(Boolean hasVirtual) {
+        this.hasVirtual = hasVirtual;
+    }
+
+
 }

+ 34 - 33
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/cache/ExamStudentCache.java

@@ -12,38 +12,39 @@ import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 @Component
 public class ExamStudentCache extends RandomObjectRedisCache<ExamStudentCacheBean> {
 
-	@Autowired
-	ExamStudentRepo examStudentRepo;
-
-	@Override
-	public ExamStudentCacheBean loadFromResource(Object... keys) {
-
-		Long examStudentId = (Long) keys[0];
-
-		ExamStudentEntity e = examStudentRepo.findByExamStudentId(examStudentId);
-
-		ExamStudentCacheBean b = new ExamStudentCacheBean();
-		b.setCourseId(e.getCourseId());
-		b.setEnable(e.getEnable());
-		b.setExamId(e.getExamId());
-		b.setExamStudentId(e.getExamStudentId());
-		b.setExtraNum(e.getExtraNum());
-		b.setStudentId(e.getStudentId());
-		b.setUsedNum(e.getUsedNum());
-		b.setPaperType(e.getPaperType());
-
-		return b;
-	}
-
-	@Override
-	protected String getKeyPrefix() {
-		return "OE_ES:";
-	}
-
-	@Override
-	protected int getTimeout() {
-		// 10天
-		return 60 * 60 * 24 * 10;
-	}
+    @Autowired
+    ExamStudentRepo examStudentRepo;
+
+    @Override
+    public ExamStudentCacheBean loadFromResource(Object... keys) {
+
+        Long examStudentId = (Long) keys[0];
+
+        ExamStudentEntity e = examStudentRepo.findByExamStudentId(examStudentId);
+
+        ExamStudentCacheBean b = new ExamStudentCacheBean();
+        b.setCourseId(e.getCourseId());
+        b.setEnable(e.getEnable());
+        b.setExamId(e.getExamId());
+        b.setExamStudentId(e.getExamStudentId());
+        b.setExtraNum(e.getExtraNum());
+        b.setStudentId(e.getStudentId());
+        b.setUsedNum(e.getUsedNum());
+        b.setPaperType(e.getPaperType());
+        b.setGrade(e.getGrade());
+
+        return b;
+    }
+
+    @Override
+    protected String getKeyPrefix() {
+        return "OE_ES:";
+    }
+
+    @Override
+    protected int getTimeout() {
+        // 10天
+        return 60 * 60 * 24 * 10;
+    }
 
 }

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

@@ -8,6 +8,7 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.impl;
 
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
 import cn.com.qmth.examcloud.core.oe.admin.base.jpa.Searcher;
 import cn.com.qmth.examcloud.core.oe.admin.base.jpa.SpecUtils;
@@ -44,6 +45,7 @@ import javax.persistence.Query;
 import java.math.BigInteger;
 import java.util.Date;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import static cn.com.qmth.examcloud.core.oe.admin.service.bean.examaudit.ExamAuditMapper.EXAM_RECORD_DATA_ID;
 
@@ -66,8 +68,8 @@ public class ExamAuditServiceImpl implements ExamAuditService {
     private ExamRecordDataRepo examRecordDataRepo;
     @Autowired
     private ExamRecordQuestionsService examRecordQuestionsService;
-	@Autowired
-	private ExamRecordForMarkingRepo examRecordForMarkingRepo;
+    @Autowired
+    private ExamRecordForMarkingRepo examRecordForMarkingRepo;
     @Autowired
     private GainBaseDataService gainBaseDataService;
     @Autowired
@@ -78,6 +80,8 @@ public class ExamAuditServiceImpl implements ExamAuditService {
     MarkWorkCloudService markWorkCloudService;
     @Autowired
     private ExamFaceLivenessVerifyRepo examFaceLivenessVerifyRepo;
+    @Autowired
+    private IllegallyTypeService illegallyTypeService;
 
     @Autowired
     private FaceBiopsyItemRepo faceBiopsyItemRepo;
@@ -85,6 +89,8 @@ public class ExamAuditServiceImpl implements ExamAuditService {
     @Autowired
     private ExamStudentFinalScoreService examStudentFinalScoreService;
 
+    @Autowired
+    IllegallyTypeRepo illegallyTypeRepo;
     /**
      * 活体检测失败自动审核
      */
@@ -99,6 +105,7 @@ public class ExamAuditServiceImpl implements ExamAuditService {
      * 系统审核
      */
     private static final String AUDIT_USER_NAME = "SYSTEM";
+
     @Override
     public Page<ExamAuditInfo> getExamAuditList(ExamAuditQuery query) {
         Check.isNull(query, "查询参数不能为空!");
@@ -137,16 +144,16 @@ public class ExamAuditServiceImpl implements ExamAuditService {
         if (StringUtils.isNotBlank(query.getStatus())) {
             wrapper.and().eq("audit.status", query.getStatus());
         }
-        if(StringUtils.isNoneBlank(query.getDisciplineType())){
-        	wrapper.and().eq("audit.discipline_type", query.getDisciplineType());
+        if (StringUtils.isNoneBlank(query.getDisciplineType())) {
+            wrapper.and().eq("audit.discipline_type", query.getDisciplineType());
         }
-        if(StringUtils.isNoneBlank(query.getAuditUserName())){
-        	wrapper.and().like("audit.audit_user_name", query.getAuditUserName());
+        if (StringUtils.isNoneBlank(query.getAuditUserName())) {
+            wrapper.and().like("audit.audit_user_name", query.getAuditUserName());
         }
         long totalSize = 0;
         //查询总记录数
-        if(query.getSelectType() == null || query.getSelectType() != SelectType.EXPORT){
-        	final String count = "count(0)";
+        if (query.getSelectType() == null || query.getSelectType() != SelectType.EXPORT) {
+            final String count = "count(0)";
             String countSql = wrapper.build().replace(columns, count);
             Query countQuery = entityManager.createNativeQuery(countSql);
             BigInteger element = (BigInteger) countQuery.getSingleResult();
@@ -162,27 +169,38 @@ public class ExamAuditServiceImpl implements ExamAuditService {
 
 //        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());
+        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){
+
+        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());
+            }
+
+
             CourseBean courseBean = ExamCacheTransferHelper.getCachedCourse(examAuditInfo.getCourseId());
-        	examAuditInfo.setCourseName(courseBean.getName());
-        	examAuditInfo.setCourseCode(courseBean.getCode());
-        	examAuditInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
+            examAuditInfo.setCourseName(courseBean.getName());
+            examAuditInfo.setCourseCode(courseBean.getCode());
+            examAuditInfo.setCourseLevel(CourseLevel.getCourseLevel(courseBean.getLevel()).getTitle());
 
-            //获取考试名称
-            ExamBean examBean = ExamCacheTransferHelper.getCachedExam(query.getExamId(),examAuditInfo.getStudentId());
+            //考试名称
+            ExamBean examBean = ExamCacheTransferHelper.getCachedExam(query.getExamId(), examAuditInfo.getStudentId());
             examAuditInfo.setExamName(examBean.getName());
 
+            //客观分
+            ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examAuditInfo.getExamRecordDataId());
+            examAuditInfo.setObjectiveScore(String.valueOf(examScore.getObjectiveScore()));
+
         }
         return new PageImpl<ExamAuditInfo>(list, pageable, totalSize);
     }
@@ -201,77 +219,110 @@ public class ExamAuditServiceImpl implements ExamAuditService {
         }
         return null;
     }
-    
+
     @Override
-    public void batchAudit(List<Long> examRecordDataIds, Boolean isPass,User user) {
+    public void batchAudit(List<Long> examRecordDataIds, Boolean isPass, User user) {
+        //系统默认违纪类型
+        List<IllegallyTypeEntity> sysIllegallyTypeList = illegallyTypeService.getSystemIllegallyTypes();
+        if (null == sysIllegallyTypeList || sysIllegallyTypeList.isEmpty()) {
+            throw new StatusException("100001","默认违纪类型未配置");
+        }
         for (Long examRecordDataId : examRecordDataIds) {
-        	DisciplineType disciplineType = isPass?DisciplineType.BATCH_PASS:DisciplineType.BATCH_NOTPASS;
-        	singleAudit(examRecordDataId,isPass,"批量审核",disciplineType,user);
+            String disciplineType = isPass ? DisciplineType.BATCH_PASS.name() : DisciplineType.BATCH_NOTPASS.name();
+            IllegallyTypeEntity illType = sysIllegallyTypeList.stream()
+                    .filter(p -> p.getCode().equals(disciplineType))
+                    .collect(Collectors.toList()).get(0);
+            singleAudit(examRecordDataId, isPass, "批量审核", disciplineType, user, illType.getId());
         }
     }
 
-	@Override
-	@Transactional
-	public void singleAudit(Long examRecordDataId, Boolean isPass,String disciplineDetail, DisciplineType disciplineType,User user) {
-		ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo,examRecordDataId,ExamRecordDataEntity.class);
+    @Override
+    @Transactional
+    public void singleAudit(Long examRecordDataId, Boolean isPass, String disciplineDetail,
+                            String disciplineType, User user, Long illegallyTypeId) {
+        ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId, ExamRecordDataEntity.class);
         if (examRecordData == null) {
             return;
         }
         //已经审核过了,这里直接返回,如果需要重新审核,调用重审redoAudit方法
-        if(examRecordData.getIsAudit() !=null && examRecordData.getIsAudit()){
-        	return;
+        if (examRecordData.getIsAudit() != null && examRecordData.getIsAudit()) {
+            return;
         }
-        
+
         //保存审核记录
         ExamAuditEntity examAudit = new ExamAuditEntity();
         examAudit.setExamRecordDataId(examRecordDataId);
         examAudit.setStatus(isPass ? AuditStatus.PASS : AuditStatus.UN_PASS);
+        if (null != illegallyTypeId) {
+            IllegallyTypeEntity illegallyType =
+                    GlobalHelper.getEntity(illegallyTypeRepo, illegallyTypeId, IllegallyTypeEntity.class);
+            if (null == illegallyType) {
+                throw new StatusException("100001", "违纪类型数据有误");
+            }
+            disciplineType = illegallyType.getCode();
+        }
         examAudit.setDisciplineType(disciplineType);
         examAudit.setDisciplineDetail(disciplineDetail);
-        if(user != null){
-        	examAudit.setUserId(user.getUserId().toString());
-        	examAudit.setAuditUserName(user.getDisplayName());
+        if (user != null) {
+            examAudit.setUserId(user.getUserId().toString());
+            examAudit.setAuditUserName(user.getDisplayName());
         }
+        examAudit.setIllegallyTypeId(illegallyTypeId);
+
         examAuditRepo.save(examAudit);
-        
+
         //保存考试记录
         examRecordData.setIsAudit(true);
-        examRecordData.setIsIllegality(isPass?false:true);
+        examRecordData.setIsIllegality(isPass ? false : true);
         examRecordDataRepo.save(examRecordData);
-        
-        doAuditPostProcesser(isPass,examRecordData);
-	}
-	
-	@Override
-	public void redoAudit(RedoAuditInfo redoAuditInfo,User user) {
-		for(Long examRecordDataId:redoAuditInfo.getExamRecordDataIds()){
-			ExamAuditEntity examAudit = examAuditRepo.findByExamRecordDataId(examRecordDataId);
-			if(examAudit == null){
-				examAudit = new ExamAuditEntity();
-				examAudit.setCreationTime(new Date());
-				examAudit.setExamRecordDataId(examRecordDataId);
-			}
-			examAudit.setAuditUserName(user.getDisplayName());
-			examAudit.setUserId(user.getUserId().toString());
-			if(StringUtils.isBlank(redoAuditInfo.getDisciplineDetail())){
-				examAudit.setDisciplineDetail("重审");
-			}else{
-				examAudit.setDisciplineDetail(redoAuditInfo.getDisciplineDetail());
-			}
-			examAudit.setDisciplineType(DisciplineType.tramsformByType(redoAuditInfo.getDisciplineType()));
-			examAudit.setStatus(redoAuditInfo.getIsPass()?AuditStatus.PASS:AuditStatus.UN_PASS);
-			examAudit.setUpdateTime(new Date());
-			examAuditRepo.save(examAudit);
-			
-			ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo,examRecordDataId,ExamRecordDataEntity.class);
-			examRecordData.setIsWarn(true);
-			examRecordData.setIsAudit(true);
-			examRecordData.setIsIllegality(!redoAuditInfo.getIsPass());//是否违纪
-			examRecordDataRepo.save(examRecordData);
-			
-			doAuditPostProcesser(redoAuditInfo.getIsPass(),examRecordData);
-		}
-	}
+
+        doAuditPostProcesser(isPass, examRecordData);
+    }
+
+    @Override
+    public void redoAudit(RedoAuditInfo redoAuditInfo, User user) {
+        for (Long examRecordDataId : redoAuditInfo.getExamRecordDataIds()) {
+            ExamAuditEntity examAudit = examAuditRepo.findByExamRecordDataId(examRecordDataId);
+            if (examAudit == null) {
+                examAudit = new ExamAuditEntity();
+                examAudit.setCreationTime(new Date());
+                examAudit.setExamRecordDataId(examRecordDataId);
+            }
+            examAudit.setAuditUserName(user.getDisplayName());
+            examAudit.setUserId(user.getUserId().toString());
+            if (StringUtils.isBlank(redoAuditInfo.getDisciplineDetail())) {
+                examAudit.setDisciplineDetail("重审");
+            } else {
+                examAudit.setDisciplineDetail(redoAuditInfo.getDisciplineDetail());
+            }
+
+            String disciplineType = redoAuditInfo.getDisciplineType();
+            if (null != redoAuditInfo.getIllegallyTypeId()) {
+                IllegallyTypeEntity illegallyType =
+                        GlobalHelper.getEntity(illegallyTypeRepo, redoAuditInfo.getIllegallyTypeId(), IllegallyTypeEntity.class);
+                if (null == illegallyType) {
+                    throw new StatusException("100002", "违纪类型数据有误");
+                }
+                disciplineType = illegallyType.getCode();
+            }
+
+            examAudit.setDisciplineType(disciplineType);
+            examAudit.setStatus(redoAuditInfo.getIsPass() ? AuditStatus.PASS : AuditStatus.UN_PASS);
+            examAudit.setUpdateTime(new Date());
+
+            examAudit.setIllegallyTypeId(redoAuditInfo.getIllegallyTypeId());
+
+            examAuditRepo.save(examAudit);
+
+            ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId, ExamRecordDataEntity.class);
+            examRecordData.setIsWarn(true);
+            examRecordData.setIsAudit(true);
+            examRecordData.setIsIllegality(!redoAuditInfo.getIsPass());//是否违纪
+            examRecordDataRepo.save(examRecordData);
+
+            doAuditPostProcesser(redoAuditInfo.getIsPass(), examRecordData);
+        }
+    }
 
     /**
      * 活体检测失败,系统审核
@@ -287,7 +338,7 @@ public class ExamAuditServiceImpl implements ExamAuditService {
         }
         ExamAuditEntity examAuditEntity = new ExamAuditEntity();
         examAuditEntity.setExamRecordDataId(examRecordDataId);
-        examAuditEntity.setDisciplineType(DisciplineType.ACTION_FAILURE);
+        examAuditEntity.setDisciplineType(DisciplineType.ACTION_FAILURE.name());
         examAuditEntity.setUserId(FACE_LIVENESS_VERIFY_AUTO_AUDIT);//活体检测自动审核
         examAuditEntity.setAuditUserName(AUDIT_USER_NAME);
         examAuditEntity.setDisciplineDetail(getFaceVerifyDisciplineDetail(examRecordDataId, rootOrgId));//计算违纪描述
@@ -308,7 +359,7 @@ public class ExamAuditServiceImpl implements ExamAuditService {
         }
         ExamAuditEntity examAuditEntity = new ExamAuditEntity();
         examAuditEntity.setExamRecordDataId(examRecordDataId);
-        examAuditEntity.setDisciplineType(DisciplineType.OTHER);
+        examAuditEntity.setDisciplineType(DisciplineType.OTHER.name());
         examAuditEntity.setDisciplineDetail("抓拍照片数量为0");
         examAuditEntity.setUserId(NOPHOTO_VERIFY_AUTO_AUDIT);//抓拍照片为0自动审核
         examAuditEntity.setAuditUserName(AUDIT_USER_NAME);
@@ -370,42 +421,44 @@ public class ExamAuditServiceImpl implements ExamAuditService {
     }
 
     /**
-	 * 重审后置处理
-	 * @param isPass
-	 * @param examRecordData
-	 */
-	private void doAuditPostProcesser(Boolean isPass,ExamRecordDataEntity examRecordData) {
-		if(isPass){
-			auditPassPostProcesser(examRecordData);
-		}else{
-			auditUnPassPostProcesser(examRecordData);
-		}
+     * 重审后置处理
+     *
+     * @param isPass
+     * @param examRecordData
+     */
+    private void doAuditPostProcesser(Boolean isPass, ExamRecordDataEntity examRecordData) {
+        if (isPass) {
+            auditPassPostProcesser(examRecordData);
+        } else {
+            auditUnPassPostProcesser(examRecordData);
+        }
 
         //重新计算考生的最终分数
         examStudentFinalScoreService.calcAndSaveFinalScore(examRecordData.getExamStudentId());
-	}
-	
-	/**
-	 * 审核通过后置处理
-	 */
-	private void auditPassPostProcesser(ExamRecordDataEntity examRecordData){
-    	ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examRecordData.getId());
-    	//审核通过且为非全客观题卷,保存阅卷需要数据
-    	saveExamRecordForMarkingWithAudit(examRecordData,examScore);
-    	//保存推送分数队列
-        examScorePushQueueService.saveScoreDataInfoToQueue(examRecordData.getId(),examScore.getId());
+    }
+
+    /**
+     * 审核通过后置处理
+     */
+    private void auditPassPostProcesser(ExamRecordDataEntity examRecordData) {
+        ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(examRecordData.getId());
+        //审核通过且为非全客观题卷,保存阅卷需要数据
+        saveExamRecordForMarkingWithAudit(examRecordData, examScore);
+        //保存推送分数队列
+        examScorePushQueueService.saveScoreDataInfoToQueue(examRecordData.getId(), examScore.getId());
         //保存获取分数队列
         examScoreObtainQueueService.saveExamScoreObtainQueue(examRecordData.getId());
         //发送通知
         examScoreObtainQueueService.sendObtainScoreNotify(examRecordData.getRootOrgId());
-	}
+    }
 
     /**
      * 审核通过且为非全客观题卷,保存阅卷需要数据
+     *
      * @param examRecordData
      */
-	private void saveExamRecordForMarkingWithAudit(ExamRecordDataEntity examRecordData,ExamScoreEntity examScore){
-    	if(examRecordData.getIsAllObjectivePaper() != null && !examRecordData.getIsAllObjectivePaper()){
+    private void saveExamRecordForMarkingWithAudit(ExamRecordDataEntity examRecordData, ExamScoreEntity examScore) {
+        if (examRecordData.getIsAllObjectivePaper() != null && !examRecordData.getIsAllObjectivePaper()) {
             ExamRecordForMarkingEntity examRecordForMarkingExists =
                     examRecordForMarkingRepo.findByExamRecordDataId(examRecordData.getId());
             if (examRecordForMarkingExists != null) {
@@ -423,27 +476,28 @@ public class ExamAuditServiceImpl implements ExamAuditService {
             examRecordForMarking.setSubjectiveAnswerLength(subjectiveAnswerLength);
             examRecordForMarkingRepo.save(examRecordForMarking);
 
-    		//调用阅卷接口,通知有新数据
+            //调用阅卷接口,通知有新数据
             AppendMarkWorkPaperReq appendMarkWorkPaperReq = new AppendMarkWorkPaperReq();
             appendMarkWorkPaperReq.setRootOrgId(examRecordData.getRootOrgId());
             appendMarkWorkPaperReq.setExamId(examRecordData.getExamId());
             markWorkCloudService.appendMarkWorkPaper(appendMarkWorkPaperReq);
-    	}
-	}
-
-	/**
-	 * 审核不通过后置处理
-	 * @param examRecordData
-	 */
-	private void auditUnPassPostProcesser(ExamRecordDataEntity examRecordData) {
-		ExamRecordForMarkingEntity examRecordForMarking = examRecordForMarkingRepo.findByExamRecordDataId(examRecordData.getId());
-		if(examRecordForMarking != null){
-			//删除阅卷需要数据,防止违纪数据进入阅卷
-			examRecordForMarkingRepo.delete(examRecordForMarking);
-		}
-		//保存获取分数队列
+        }
+    }
+
+    /**
+     * 审核不通过后置处理
+     *
+     * @param examRecordData
+     */
+    private void auditUnPassPostProcesser(ExamRecordDataEntity examRecordData) {
+        ExamRecordForMarkingEntity examRecordForMarking = examRecordForMarkingRepo.findByExamRecordDataId(examRecordData.getId());
+        if (examRecordForMarking != null) {
+            //删除阅卷需要数据,防止违纪数据进入阅卷
+            examRecordForMarkingRepo.delete(examRecordForMarking);
+        }
+        //保存获取分数队列
         examScoreObtainQueueService.saveExamScoreObtainQueue(examRecordData.getId());
         //发送通知
         examScoreObtainQueueService.sendObtainScoreNotify(examRecordData.getRootOrgId());
-	}
-}
+    }
+}

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

@@ -13,21 +13,21 @@ 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;
+import cn.com.qmth.examcloud.core.oe.admin.dao.ExamScoreRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamSyncCaptureRepo;
-import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamAuditEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamCaptureEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamSyncCaptureEntity;
+import cn.com.qmth.examcloud.core.oe.admin.dao.entity.*;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.AuditStatus;
 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.IllegallyTypeService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examcapture.ExamCaptureAuditInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examcapture.ExamCaptureInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.others.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.support.Constants;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
+import cn.com.qmth.examcloud.support.cache.bean.ExamStudentCacheBean;
+import cn.com.qmth.examcloud.support.cache.bean.OrgCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.SysPropertyCacheBean;
-import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import com.google.common.collect.Lists;
 import org.apache.commons.lang3.StringUtils;
@@ -58,8 +58,13 @@ public class ExamCaptureServiceImpl implements ExamCaptureService {
     private ExamRecordDataRepo examRecordDataRepo;
     @Autowired
     private ExamSyncCaptureRepo examSyncCaptureRepo;
+    @Autowired
+    private IllegallyTypeService illegallyTypeService;
+    @Autowired
+    private ExamScoreRepo examScoreRepo;
     private static final ExamCloudLog LOG = ExamCloudLogFactory
             .getLog(ExamCaptureServiceImpl.class);
+
     @Override
     public ExamCaptureAuditInfo getExamCaptureAuditDetail(Long examRecordDataId) {
         if (examRecordDataId == null) {
@@ -80,7 +85,9 @@ public class ExamCaptureServiceImpl implements ExamCaptureService {
             }
             detail.setDisciplineDetail(audit.getDisciplineDetail());
             if (audit.getDisciplineType() != null) {
-                detail.setDisciplineType(audit.getDisciplineType().getName());
+                IllegallyTypeEntity illegallyType =
+                        illegallyTypeService.getIllegallyType(recordData.getRootOrgId(), audit.getDisciplineType());
+                detail.setDisciplineType(illegallyType.getName());
             }
         }
 
@@ -109,8 +116,27 @@ public class ExamCaptureServiceImpl implements ExamCaptureService {
             detail.setFaceVerifyResult(recordData.getFaceVerifyResult().name());
         }
         detail.setVirtualCameraNames(getVirtualCameraNames(examRecordDataId));
-//同步人脸比较时抓拍照片的url
+
+        //同步人脸比较时抓拍照片的url
         detail.setSyncCaptureFileUrl(getSyncCaptureFileUrl(examRecordDataId));
+
+        //组织机构
+        OrgCacheBean org = CacheHelper.getOrg(recordData.getOrgId());
+        detail.setOrgName(org.getName());
+
+        //考生
+        ExamStudentCacheBean examStudent = CacheHelper.getExamStudent(recordData.getExamStudentId());
+        detail.setGrade(examStudent.getGrade());
+
+        //课程层次
+        detail.setCourseLevel(recordData.getCourseLevel());
+
+        //客观题总分
+        ExamScoreEntity examScore = examScoreRepo.findByExamRecordDataId(recordData.getId());
+        if (null != examScore) {
+            detail.setObjectiveTotalScore(String.valueOf(examScore.getObjectiveScore()));
+        }
+
         return detail;
     }
 
@@ -130,7 +156,8 @@ public class ExamCaptureServiceImpl implements ExamCaptureService {
      * @param examRecordDataId
      * @return
      */
-    private String getVirtualCameraNames(Long examRecordDataId) {
+    @Override
+    public String getVirtualCameraNames(Long examRecordDataId) {
         Set<String> virtualCameraNames = new HashSet<String>();
         List<ExamCaptureEntity> examCaptureList = examCaptureRepo.findByExamRecordDataId(examRecordDataId);
         if (examCaptureList != null && examCaptureList.size() > 0) {
@@ -167,6 +194,7 @@ public class ExamCaptureServiceImpl implements ExamCaptureService {
         return sb.toString();
     }
 
+
     @Override
     public List<ExamCaptureInfo> getExamCaptureList(Long examRecordDataId) {
         if (examRecordDataId == null) {

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

@@ -1,22 +1,12 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.impl;
 
-import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
-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;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordDataCacheService;
-import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordDataService;
-import cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamStudentBean;
-import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
 import cn.com.qmth.examcloud.support.examing.ExamRecordData;
 import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.Date;
-
 /**
  * @author chenken
  * @date 2018/8/15 11:16

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

@@ -2,6 +2,7 @@ package cn.com.qmth.examcloud.core.oe.admin.service.impl;
 
 import java.util.Date;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -9,7 +10,6 @@ import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
 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;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordDataService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamStudentBean;
 import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
@@ -34,7 +34,7 @@ public class ExamRecordDataServiceImpl implements ExamRecordDataService {
                                                             String paperStructId, Boolean fullyObjective) {
         ExamRecordDataEntity examRecordDataEntity = new ExamRecordDataEntity();
         examRecordDataEntity.setExamId(examBean.getId());
-        examRecordDataEntity.setExamType(ExamType.strToEnum(examBean.getExamType()));
+        examRecordDataEntity.setExamType(ExamType.valueOf(examBean.getExamType()));
 
         examRecordDataEntity.setExamStudentId(examStudent.getExamStudentId());
         examRecordDataEntity.setStudentId(examStudent.getStudentId());

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

@@ -11,6 +11,8 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.stream.Collectors;
 
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
+import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -57,6 +59,7 @@ public class ExamRecordForMarkingServiceImpl implements ExamRecordForMarkingServ
 
     @Autowired
     private JdbcTemplate jdbcTemplate;
+
     @Override
     public List<ExamRecordForMarkingEntity> queryValidExamRecordInfoByStuIds(
             Long examId, Long courseId, List<Long> examStudentIds, String batchNum) {
@@ -69,7 +72,7 @@ public class ExamRecordForMarkingServiceImpl implements ExamRecordForMarkingServ
             examRecordForMarkingList =
                     examRecordForMarkingRepo.findByExamIdAndCourseIdAndExamStudentIds(examId, courseId, examStudentIds);
         } else {
-            if (ExamType.ONLINE == examType &&
+            if ((ExamType.ONLINE == examType || ExamType.ONLINE_HOMEWORK == examType) &&
                     (MarkingType.OBJECT_SCORE_MAX.name().equals(markingType) ||
                             MarkingType.LAST_SUBMIT.name().equals(markingType))) {
                 examRecordForMarkingList =
@@ -81,7 +84,7 @@ public class ExamRecordForMarkingServiceImpl implements ExamRecordForMarkingServ
         }
         if (examType == ExamType.OFFLINE) {
             return examRecordForMarkingList;
-        } else if (ExamType.ONLINE == examType) {
+        } else if (ExamType.ONLINE == examType || ExamType.ONLINE_HOMEWORK == examType) {
             if (markingType.equals(MarkingType.ALL.name())) {
                 return examRecordForMarkingList;
             } else if (markingType.equals(MarkingType.OBJECT_SCORE_MAX.name())) {
@@ -99,12 +102,8 @@ public class ExamRecordForMarkingServiceImpl implements ExamRecordForMarkingServ
      * @return
      */
     private String getMarkingType(Long examId) {
-        GetExamPropertyReq getExamPropertyReq = new GetExamPropertyReq();
-        getExamPropertyReq.setExamId(examId);
-        getExamPropertyReq.setKey("MARKING_TYPE");
-        GetExamPropertyResp getExamPropertyResp = examCloudService.getExamProperty(getExamPropertyReq);
-
-        return getExamPropertyResp.getValue();
+        return ExamCacheTransferHelper.
+                getDefaultCachedExamProperty(examId, ExamProperties.MARKING_TYPE.name()).getValue();
     }
 
     @Override
@@ -114,7 +113,7 @@ public class ExamRecordForMarkingServiceImpl implements ExamRecordForMarkingServ
         List<ExamRecordForMarkingEntity> examRecordForMarkingList = examRecordForMarkingRepo.findByExamIdAndCourseId(examId, courseId);
         if (examType == ExamType.OFFLINE) {
             return examRecordForMarkingList;
-        } else if (ExamType.ONLINE == examType) {
+        } else if (ExamType.ONLINE == examType || ExamType.ONLINE_HOMEWORK == examType) {
             String markingType = getMarkingType(examId);
 
             if (markingType.equals(MarkingType.ALL.name())) {
@@ -134,10 +133,7 @@ public class ExamRecordForMarkingServiceImpl implements ExamRecordForMarkingServ
      * @return
      */
     private ExamType getExamType(Long examId) {
-        GetExamReq getExamReq = new GetExamReq();
-        getExamReq.setId(examId);
-        GetExamResp getExamResp = examCloudService.getExam(getExamReq);
-        return ExamType.valueOf(getExamResp.getExamBean().getExamType());
+        return ExamType.valueOf(ExamCacheTransferHelper.getDefaultCachedExam(examId).getExamType());
     }
 
     /**
@@ -351,7 +347,7 @@ public class ExamRecordForMarkingServiceImpl implements ExamRecordForMarkingServ
 
         if (examType == ExamType.OFFLINE) {
             return examRecordForMarkingList;
-        } else if (ExamType.ONLINE == examType) {
+        } else if (ExamType.ONLINE == examType || ExamType.ONLINE_HOMEWORK == examType) {
 
             String markingType = getMarkingType(examId);
             if (markingType.equals(MarkingType.ALL.name())) {

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

@@ -1,5 +1,6 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.impl;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.QuestionTypeUtil;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
@@ -9,7 +10,6 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamQuestionEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordQuestionsEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamScoreEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordQuestionsService;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamStudentFinalScoreService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.SubjectiveQuestionScoreInfo;
@@ -67,7 +67,7 @@ public class ExamRecordQuestionsServiceImpl implements ExamRecordQuestionsServic
     @Override
     public void saveSubjectiveQuestionScore(Long examRecordDataId, List<SubjectiveQuestionScoreInfo> subjectiveQuestionScoreInfoList) {
         ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId, ExamRecordDataEntity.class);
-        if (examRecordData.getExamType() == ExamType.ONLINE) {
+        if (ExamType.ONLINE == examRecordData.getExamType() || ExamType.ONLINE_HOMEWORK == examRecordData.getExamType()) {
             ExamRecordQuestionsEntity examRecordQuestionsEntity =
                     getExamRecordQuestionsAndFixExamRecordDataIfNecessary(examRecordDataId);
             List<ExamQuestionEntity> examRecordQuestionList = examRecordQuestionsEntity.getExamQuestionEntities();
@@ -177,8 +177,7 @@ public class ExamRecordQuestionsServiceImpl implements ExamRecordQuestionsServic
         }
         //如果考试作答记录id为空,则根据考试记录id获取考试作答记录,并将考试作答记录id保存至examRecordData表中
         else {
-            ExamRecordQuestionsEntity examRecordQuestionsEntity =
-                    examRecordQuestionsRepo.findByExamRecordDataId(examRecordDataId);
+            ExamRecordQuestionsEntity examRecordQuestionsEntity = examRecordQuestionsRepo.findByExamRecordDataId(examRecordDataId);
 
             //将考试作答记录id保存至examRecordData表中,目的:纠正历史数据
             examRecordDataRepo.updateExamRecordDataQuestionIdById(examRecordQuestionsEntity.getId(), examRecordData.getId());

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

@@ -241,7 +241,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
             sql.append(" and record_data.student_name LIKE '%" + query.getStudentName() + "%'");
         }
         if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and record_data.identity_number LIKE '%" + query.getIdentityNumber() + "%'");
+            sql.append(" and record_data.identity_number LIKE '" + query.getIdentityNumber() + "%'");
         }
         if (StringUtils.isNotBlank(query.getInfoCollector())) {
             sql.append(" and record_data.info_collector LIKE '%" + query.getInfoCollector() + "%'");
@@ -286,6 +286,15 @@ public class ExamRecordServiceImpl implements ExamRecordService {
             sql.append(" and record_data.baidu_face_liveness_success_percent >=" + query.getLivenessSuccessPercentLower());
             sql.append(" and record_data.baidu_face_liveness_success_percent <=" + query.getLivenessSuccessPercentUpper());
         }
+
+        //是否有虚拟设备
+        if (query.getHasVirtual() != null) {
+            if (query.getHasVirtual()) {
+                sql.append(" and record_data.id in (select t1.id from ec_oe_exam_record_data t1 left join ec_oe_exam_capture t2 on t1.id=t2.exam_record_data_id where t1.exam_id =" + query.getExamId()+" and t2.has_virtual_camera=1 )");
+            } else {
+                sql.append(" and record_data.id in (select t1.id from ec_oe_exam_record_data t1 left join ec_oe_exam_capture t2 on t1.id=t2.exam_record_data_id where t1.exam_id =" + query.getExamId()+" and (t2.has_virtual_camera=0 or t2.has_virtual_camera is null) )");
+            }
+        }
         return sql;
     }
 
@@ -324,6 +333,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
         //查询总数
         long total = countExamRecordListForPage(query);
         Pageable pageable = new PageRequest(query.getPageNo() - 1, query.getPageSize());
+
         Page<ExamRecordDataEntity> page = new PageImpl<ExamRecordDataEntity>(examRecordDataList, pageable, total);
         return examRecordEntityConvert.of(page);
     }
@@ -544,7 +554,7 @@ public class ExamRecordServiceImpl implements ExamRecordService {
     public List<ExamStudentEffectiveScoreInfo> getExamStudentEffectiveScoreList(String markingType, List<Long> examStudentIdList) {
         List<ExamStudentEffectiveScoreInfo> resultList = new ArrayList<>();
         //考生所有的考试记录
-        List<ExamRecordDataEntity> allExamRecordDataList = examRecordDataRepo.findByExamStudentIdList(examStudentIdList);
+        List<ExamRecordDataEntity> allExamRecordDataList = examRecordDataRepo.findEffectiveDataByExamStudentIdList(examStudentIdList);
         if (allExamRecordDataList == null || allExamRecordDataList.isEmpty()) {
             return null;
         }
@@ -669,4 +679,4 @@ public class ExamRecordServiceImpl implements ExamRecordService {
         info.setBasePaperId(rs.getString("base_paper_id"));
         return info;
     }
-}
+}

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

@@ -7,12 +7,12 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamScoreObtainQueueRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamScoreObtainQueueEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamScoreObtainQueueService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.NotifyUrlInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.others.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.SysPropertyCacheBean;
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;

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

@@ -3,6 +3,7 @@ package cn.com.qmth.examcloud.core.oe.admin.service.impl;
 import java.util.Date;
 
 import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordDataRepo;
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -14,7 +15,6 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.OrgScoreHandleRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamScorePushQueue;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.OrgScoreHandleEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamScoreQueueStatus;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamScorePushQueueService;
 import cn.com.qmth.examcloud.core.oe.admin.service.others.ExamCacheTransferHelper;

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

@@ -14,6 +14,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
@@ -36,7 +37,6 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamScoreEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamStudentEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamStudentFinalScoreEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.CourseLevel;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordService;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamScoreService;
@@ -132,7 +132,8 @@ public class ExamScoreServiceImpl implements ExamScoreService {
         if (examTimes != null) {
             Integer extraExamNum = examStudent.getExtraNum() == null ? 0 : examStudent.getExtraNum();
             Integer usedNum = examStudent.getUsedNum() == null ? 0 : examStudent.getUsedNum();
-            examScore.setLeftExamTimes(examTimes + extraExamNum - usedNum);
+            Long leftExamTimes = (examTimes + extraExamNum - usedNum)<0?0:(examTimes + extraExamNum - usedNum);
+            examScore.setLeftExamTimes(leftExamTimes);
         }
         return setCommomScoreInfo(examScore, examStudent.getFinished(), examStudent.getExamStudentId(), examBean, markingType);
     }
@@ -180,7 +181,7 @@ public class ExamScoreServiceImpl implements ExamScoreService {
             sql.append(" and student_name LIKE '%" + query.getStudentName() + "%'");
         }
         if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and identity_number LIKE '%" + query.getIdentityNumber() + "%'");
+            sql.append(" and identity_number LIKE '" + query.getIdentityNumber() + "%'");
         }
         if (query.getCourseId() != null) {
             sql.append(" and course_id=" + query.getCourseId());
@@ -252,7 +253,8 @@ public class ExamScoreServiceImpl implements ExamScoreService {
         if (examTimes != null) {
             Integer extraExamNum = examStudent.getExtraNum() == null ? 0 : examStudent.getExtraNum();
             Integer usedNum = examStudent.getUsedNum() == null ? 0 : examStudent.getUsedNum();
-            examScore.setLeftExamTimes(examTimes + extraExamNum - usedNum);
+            Long leftExamTimes = (examTimes + extraExamNum - usedNum)<0?0:(examTimes + extraExamNum - usedNum);
+            examScore.setLeftExamTimes(leftExamTimes);
         }
 
         return setCommomScoreInfo(examScore, examStudent.getFinished(), examStudent.getExamStudentId(), examBean, markingType);
@@ -393,7 +395,7 @@ public class ExamScoreServiceImpl implements ExamScoreService {
         examStudentEntity.setGrade(rs.getString("grade"));
         return examStudentEntity;
     }
-    
+
     @Override
     public void createExamScoreWithOffline(Long examRecordDataId) {
         ExamScoreEntity examScoreEntity = new ExamScoreEntity();
@@ -448,7 +450,7 @@ public class ExamScoreServiceImpl implements ExamScoreService {
         }
         return objectiveScoreInfoList;
     }
-    
+
     private boolean isExamRecordEnded(ExamRecordDataEntity examRecordData) {
         //如果考试记录状态为已处理,则直接返回true.
         if (examRecordData.getExamRecordStatus() == ExamRecordStatus.EXAM_END ||
@@ -458,4 +460,4 @@ public class ExamScoreServiceImpl implements ExamScoreService {
         }
         return false;
     }
-}
+}

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

@@ -11,20 +11,16 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamScoreEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamStudentEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamStudentFinalScoreEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
 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.core.oe.admin.service.others.ExamCacheTransferHelper;
-
-import com.mysql.cj.log.LogFactory;
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * @Description 考生最终分数实现类
@@ -51,11 +47,11 @@ public class ExamStudentFinalScoreServiceImpl implements ExamStudentFinalScoreSe
         String markingType = ExamCacheTransferHelper.
                 getDefaultCachedExamProperty(examStudent.getExamId(), ExamProperties.MARKING_TYPE.name()).getValue();
         String examType = ExamCacheTransferHelper.getDefaultCachedExam(examStudent.getExamId()).getExamType();
-        List<ExamRecordDataEntity> allExamRecordDataList = examRecordDataRepo.findByExamStudentId(examStudentId);
+        List<ExamRecordDataEntity> effectiveExamRecordDataList = examRecordDataRepo.findEffectiveDataByExamStudentIdList(Arrays.asList(examStudentId));
 
         if (LOG.isDebugEnabled()) {
-            if (null != allExamRecordDataList) {
-                LOG.debug("[TEMP-DEBUG1]-allExamRecordDataList: " + JsonUtil.toJson(allExamRecordDataList));
+            if (null != effectiveExamRecordDataList) {
+                LOG.debug("[TEMP-DEBUG1]-effectiveExamRecordDataList: " + JsonUtil.toJson(effectiveExamRecordDataList));
             } else {
                 LOG.debug("[TEMP-DEBUG1]-考生id:" + examStudentId + ",找不到任何考试记录");
             }
@@ -63,7 +59,7 @@ public class ExamStudentFinalScoreServiceImpl implements ExamStudentFinalScoreSe
 
 
         //得到最终考试结果
-        ExamScoreEntity finalEffectiveExamScore = getFinalEffectiveExamScore(allExamRecordDataList, examType, markingType);
+        ExamScoreEntity finalEffectiveExamScore = getFinalEffectiveExamScore(effectiveExamRecordDataList, examType, markingType);
 
         if (LOG.isDebugEnabled()) {
             if (null != finalEffectiveExamScore) {
@@ -117,52 +113,18 @@ public class ExamStudentFinalScoreServiceImpl implements ExamStudentFinalScoreSe
     /**
      * 计算得出最终有效成绩
      */
-    private ExamScoreEntity getFinalEffectiveExamScore(List<ExamRecordDataEntity> examRecordAllList, String examType, String markingType) {
-        /*
-         * 第一次过滤考试记录:
-         * 状态为EXAM_END或EXAM_OVERDUE
-         */
-        List<ExamRecordDataEntity> firstFilterExamRecordList = examRecordAllList.stream().filter(examRecord -> {
-            return examRecord.getExamRecordStatus() == ExamRecordStatus.EXAM_END ||
-                    examRecord.getExamRecordStatus() == ExamRecordStatus.EXAM_OVERDUE;
-        }).collect(Collectors.toList());
-
-        if (firstFilterExamRecordList == null || firstFilterExamRecordList.size() == 0) {
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("[TEMP-DEBUG3]-firstFilterExamRecordList-考生找不到满足条件考试记录");
-            }
-            return null;
-        }
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("[TEMP-DEBUG3]-firstFilterExamRecordList: " + JsonUtil.toJson(firstFilterExamRecordList));
-        }
-
-        /*
-         * 第二次过滤考试记录:
-         * 没有违纪的&&(没有警告或有警告已审核通过的)
-         */
-        Stream<ExamRecordDataEntity> secondFilterExamRecordStream = firstFilterExamRecordList.stream().filter(examRecord -> {
-            return !examRecord.getIsIllegality() && (!examRecord.getIsWarn() || (examRecord.getIsWarn() && examRecord.getIsAudit()));
-        });
-
-        List<ExamRecordDataEntity> secondFilterExamRecords = secondFilterExamRecordStream.collect(Collectors.toList());
-        if (secondFilterExamRecords == null || secondFilterExamRecords.size() == 0) {
+    private ExamScoreEntity getFinalEffectiveExamScore(List<ExamRecordDataEntity> effectiveExamRecordList, String examType, String markingType) {
+        if (effectiveExamRecordList == null || effectiveExamRecordList.size() == 0) {
             if (LOG.isDebugEnabled()) {
-                LOG.debug("[TEMP-DEBUG4]-secondFilterExamRecords-考生找不到满足条件考试记录");
+                LOG.debug("[TEMP-DEBUG1]-effectiveExamRecordList-考生找不到满足条件考试记录");
             }
             return null;
         }
 
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("[TEMP-DEBUG4]-secondFilterExamRecords: " + JsonUtil.toJson(secondFilterExamRecords));
-        }
+        //取出有效记录的id
+        List<Long> examRecordDataIds =
+                effectiveExamRecordList.stream().map(ExamRecordDataEntity::getId).collect(Collectors.toList());
 
-        //取出有效记录的成绩
-        List<Long> examRecordDataIds = new ArrayList<>();
-        for (int i = 0; i < secondFilterExamRecords.size(); i++) {
-            examRecordDataIds.add(secondFilterExamRecords.get(i).getId());
-        }
         List<ExamScoreEntity> effectiveExamScoreList = examScoreRepo.findByExamRecordDataIdIn(examRecordDataIds);
         if (effectiveExamScoreList == null || effectiveExamScoreList.size() == 0) {
             if (LOG.isDebugEnabled()) {
@@ -171,10 +133,6 @@ public class ExamStudentFinalScoreServiceImpl implements ExamStudentFinalScoreSe
             return null;
         }
 
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("[TEMP-DEBUG5]-effectiveExamScoreList: " + JsonUtil.toJson(effectiveExamScoreList));
-        }
-
         //离线考试
         if ("OFFLINE".equals(examType)) {
             return effectiveExamScoreList.get(0);

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

@@ -13,6 +13,7 @@ import static cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.ExamS
 import java.math.BigDecimal;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
@@ -25,14 +26,17 @@ import java.util.stream.Stream;
 import javax.persistence.EntityManager;
 import javax.persistence.Query;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.commons.util.DateUtil;
 import cn.com.qmth.examcloud.commons.util.RegExpUtil;
+import cn.com.qmth.examcloud.core.oe.admin.service.*;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examstudent.*;
 import cn.com.qmth.examcloud.core.oe.admin.service.cache.ExamStudentCache;
 import cn.com.qmth.examcloud.examwork.api.ExamStudentCloudService;
 import cn.com.qmth.examcloud.examwork.api.request.GetExamStudentReq;
 import cn.com.qmth.examcloud.examwork.api.response.GetExamStudentResp;
 import cn.com.qmth.examcloud.support.cache.bean.SysPropertyCacheBean;
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.hibernate.query.NativeQuery;
@@ -43,6 +47,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.Pageable;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.core.RowMapper;
 import org.springframework.stereotype.Service;
@@ -61,14 +66,8 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordForMarkingEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamStudentEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.CourseLevel;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamType;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.FinishStatus;
-import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordService;
-import cn.com.qmth.examcloud.core.oe.admin.service.ExamStudentService;
-import cn.com.qmth.examcloud.core.oe.admin.service.GainBaseDataService;
-import cn.com.qmth.examcloud.core.oe.admin.service.LocalCacheService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.OnHandExamInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.others.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
@@ -118,6 +117,8 @@ public class ExamStudentServiceImpl implements ExamStudentService {
     private RedisClient redisClient;
     @Autowired
     private ExamStudentCache examStudentCache;
+    @Autowired
+    private ExamStudentFinalScoreService examStudentFinalScoreService;
 
     @Autowired
     ExamStudentCloudService examStudentCloudService;
@@ -220,7 +221,14 @@ public class ExamStudentServiceImpl implements ExamStudentService {
 
 
         StringBuffer sql = new StringBuffer();
-        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level,finished,student_id,student_code,student_name,identity_number"
+        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level");
+        if ((ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) && query.getFinished() == null) {
+            sql.append(",case when finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + query.getExamId() + "  ) then 1 else 0 end finished");
+        } else {
+            sql.append(",finished");
+        }
+
+        sql.append(",student_id,student_code,student_name,identity_number"
                 + ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
                 + ",specialty_code,specialty_name,grade from ec_oe_exam_student t1 where 1=1 ");
         sql.append(selectExamStudentConfitionSql(query, examBean.getExamType()));
@@ -240,6 +248,19 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         for (ExamStudentEntity examStudentEntity : examStudentList) {
             ExamStudentInfo examStudentInfo = buildExamStudentInfo(examStudentEntity, cahcheMap, examBean.getExamType());
             examStudentInfoList.add(examStudentInfo);
+            if (ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+                if (query.getFinished() != null) {
+                    if (query.getFinished().intValue() == 1) {
+                        examStudentInfo.setFinished(true);
+                        examStudentInfo.setFinishedStatus(FinishStatus.已完成.name());
+                    }
+                    if (query.getFinished().intValue() == 0) {
+                        examStudentInfo.setFinished(false);
+                        examStudentInfo.setFinishedStatus(FinishStatus.未完成.name());
+                    }
+                }
+                countUseExamTimes(examStudentInfo, examBean.getExamType());
+            }
         }
         cahcheMap.clear();
         Pageable pageable = SpecUtils.buildPageable(query.getPageNo(), query.getPageSize());
@@ -262,7 +283,14 @@ public class ExamStudentServiceImpl implements ExamStudentService {
 
         //查询条件
         StringBuffer sql = new StringBuffer();
-        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level,finished,student_id,student_code,student_name,identity_number"
+        sql.append("select id,exam_student_id,exam_id,course_id,course_code,course_level");
+        if ((ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) && query.getFinished() == null) {
+            sql.append(",case when finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + query.getExamId() + "  ) then 1 else 0 end finished");
+        } else {
+            sql.append(",finished");
+        }
+
+        sql.append(",student_id,student_code,student_name,identity_number"
                 + ",info_collector,root_org_id,org_id,paper_type,used_num,extra_num"
                 + ",specialty_code,specialty_name,grade from ec_oe_exam_student t1 where 1=1 ");
         sql.append(selectExamStudentConfitionSql(query, examBean.getExamType()));
@@ -280,6 +308,19 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         for (ExamStudentEntity examStudentEntity : examStudentList) {
             ExamStudentInfo examStudentInfo = buildExamStudentInfo(examStudentEntity, cahcheMap, examBean.getExamType());
             examStudentInfoList.add(examStudentInfo);
+            if (ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+                if (query.getFinished() != null) {
+                    if (query.getFinished().intValue() == 1) {
+                        examStudentInfo.setFinished(true);
+                        examStudentInfo.setFinishedStatus(FinishStatus.已完成.name());
+                    }
+                    if (query.getFinished().intValue() == 0) {
+                        examStudentInfo.setFinished(false);
+                        examStudentInfo.setFinishedStatus(FinishStatus.未完成.name());
+                    }
+                }
+                countUseExamTimes(examStudentInfo, examBean.getExamType());
+            }
         }
         cahcheMap.clear();
         return examStudentInfoList;
@@ -300,7 +341,7 @@ public class ExamStudentServiceImpl implements ExamStudentService {
             sql.append(" and student_name LIKE '%" + query.getStudentName() + "%'");
         }
         if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and identity_number LIKE '%" + query.getIdentityNumber() + "%'");
+            sql.append(" and identity_number LIKE '" + query.getIdentityNumber() + "%'");
         }
         if (StringUtils.isNotBlank(query.getInfoCollector())) {
             sql.append(" and info_collector LIKE '%" + query.getInfoCollector() + "%'");
@@ -312,8 +353,14 @@ public class ExamStudentServiceImpl implements ExamStudentService {
             sql.append(" and course_level= '" + query.getCourseLevel() + "'");
         }
         if (query.getFinished() != null) {
-            if (ExamType.ONLINE.name().equals(examType)) {
-                sql.append(" and finished = " + query.getFinished());
+            if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
+//                sql.append(" and finished = " + query.getFinished());
+                if (query.getFinished().intValue() == 1) {
+                    sql.append(" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + query.getExamId() + "  )  )");
+                }
+                if (query.getFinished().intValue() == 0) {
+                    sql.append(" AND ( finished = 0 and t1.exam_student_id not in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + query.getExamId() + "  )  )");
+                }
             } else if (ExamType.OFFLINE.name().equals(examType)) {
                 //如果忽略是否上传答案时,只要是已抽题则认为已参加考试
                 if (query.getIgnoreUploadOfflineAnswer() != null && true == query.getIgnoreUploadOfflineAnswer()) {
@@ -348,7 +395,7 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         String photoNumber = localCacheService.getStudentPhotoNumber(cahcheMap, examStudentInfo.getStudentId());
         examStudentInfo.setPhone(photoNumber);//电话号码
 
-        if (ExamType.ONLINE.name().equals(examType)) {
+        if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
             //完成状态
             examStudentInfo.setFinishedStatus(examStudentEntity.getFinished() ? FinishStatus.已完成.name() : FinishStatus.未完成.name());
         } else if (ExamType.OFFLINE.name().equals(examType)) {
@@ -449,7 +496,7 @@ public class ExamStudentServiceImpl implements ExamStudentService {
             sql.append(" and t.student_name LIKE '%" + query.getStudentName() + "%'");
         }
         if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and t.identity_number LIKE '%" + query.getIdentityNumber() + "%'");
+            sql.append(" and t.identity_number LIKE '" + query.getIdentityNumber() + "%'");
         }
         if (query.getCourseId() != null && StringUtils.isNotBlank(query.getCourseId() + "")) {
             sql.append(" and t.course_id=" + query.getCourseId());
@@ -523,7 +570,7 @@ public class ExamStudentServiceImpl implements ExamStudentService {
             sql.append(" and student.student_name LIKE '%" + query.getStudentName() + "%'");
         }
         if (StringUtils.isNotBlank(query.getIdentityNumber())) {
-            sql.append(" and student.identity_number LIKE '%" + query.getIdentityNumber() + "%'");
+            sql.append(" and student.identity_number LIKE '" + query.getIdentityNumber() + "%'");
         }
         if (query.getCourseId() != null && StringUtils.isNotBlank(query.getCourseId() + "")) {
             sql.append(" and student.course_id=" + query.getCourseId());
@@ -536,51 +583,107 @@ public class ExamStudentServiceImpl implements ExamStudentService {
 
     @Override
     public ExamStudentFinishedStatistic getExamStudentStatisticByFinished(Long examId) {
-        SqlWrapper wrapper = new SqlWrapper()
-                .select(statisticFinishedColumns())
-                .from("ec_oe_exam_student").as("student")
-                .where().eq("student.exam_id", examId);
-        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);
-        Map<String, BigDecimal> map = (HashMap) dataQuery.getSingleResult();
-        ExamStudentFinishedStatistic statistic = new ExamStudentFinishedStatistic();
-        if (map != null) {
-            if (map.get("finished") == null) {
-                statistic.setFinished(0);
-            } else {
-                statistic.setFinished(map.get("finished").intValue());
-            }
-            if (map.get("unFinished") == null) {
-                statistic.setUnFinished(0);
-            } else {
-                statistic.setUnFinished(map.get("unFinished").intValue());
+        ExamBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
+        if (ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+            ExamStudentFinishedStatistic statistic = new ExamStudentFinishedStatistic();
+            StringBuffer totalsql = new StringBuffer();
+            totalsql.append("select count(t1.id) from ec_oe_exam_student t1 where 1=1 ");
+            totalsql.append(" and exam_id = " + examId);
+            Integer total = jdbcTemplate.queryForObject(totalsql.toString(), Integer.class);
+
+            StringBuffer finishsql = new StringBuffer();
+            finishsql.append("select count(t1.id) from ec_oe_exam_student t1 where 1=1 ");
+            finishsql.append(" and exam_id = " + examId);
+            finishsql.append(" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + examId + "  )  )");
+            Integer finish = jdbcTemplate.queryForObject(finishsql.toString(), Integer.class);
+            statistic.setFinished(finish);
+            statistic.setUnFinished(total - finish);
+            return statistic;
+        } else {
+            SqlWrapper wrapper = new SqlWrapper()
+                    .select(statisticFinishedColumns())
+                    .from("ec_oe_exam_student").as("student")
+                    .where().eq("student.exam_id", examId);
+            Query dataQuery = entityManager.createNativeQuery(wrapper.build());
+            dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
+            Map<String, BigDecimal> map = (HashMap) dataQuery.getSingleResult();
+            ExamStudentFinishedStatistic statistic = new ExamStudentFinishedStatistic();
+            if (map != null) {
+                if (map.get("finished") == null) {
+                    statistic.setFinished(0);
+                } else {
+                    statistic.setFinished(map.get("finished").intValue());
+                }
+                if (map.get("unFinished") == null) {
+                    statistic.setUnFinished(0);
+                } else {
+                    statistic.setUnFinished(map.get("unFinished").intValue());
+                }
             }
+            return statistic;
         }
-        return statistic;
     }
 
     @Override
     public List<ExamStudentOrgStatistic> getExamStudentStatisticByOrg(Long examId, Long orgId) {
-        SqlWrapper wrapper = new SqlWrapper()
-                .select(statisticOrgColumns())
-                .from("ec_oe_exam_student").as("student")
-                .where().eq("student.exam_id", examId);
-        if (orgId != null) {
-            wrapper.and().eq("student.org_id", orgId);
-        }
-        wrapper.groupBy("student.org_id").orderBy("student.org_id", false);
-        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);
-        List<ExamStudentOrgStatistic> examStudentOrgStatisticList = ExamStudentEntityConvert.ofList(dataQuery.getResultList());
-        Map<String, Object> cahcheMap = new HashMap<String, Object>();
-        for (ExamStudentOrgStatistic statistic : examStudentOrgStatisticList) {
-            OrgCacheBean orgBean = gainBaseDataService.getOrgBean(statistic.getOrgId());
-            statistic.setOrgCode(orgBean.getCode());
-            statistic.setOrgName(orgBean.getName());
+        ExamBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
+        if (ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+            StringBuffer totalsql = new StringBuffer();
+            totalsql.append("select t1.org_id orgId,count(t1.id) totalCount from ec_oe_exam_student t1 where 1=1 ");
+            totalsql.append(" and exam_id = " + examId);
+            if (orgId != null) {
+                totalsql.append(" and org_id = " + orgId);
+            }
+            totalsql.append(" group by t1.org_id ");
+            List<ExamStudentOrgStatistic> totalList = jdbcTemplate.query(totalsql.toString(), new BeanPropertyRowMapper<ExamStudentOrgStatistic>(ExamStudentOrgStatistic.class));
+
+            StringBuffer finishsql = new StringBuffer();
+            finishsql.append("select t1.org_id orgId,count(t1.id) finishedCount from ec_oe_exam_student t1 where 1=1 ");
+            finishsql.append(" and exam_id = " + examId);
+            if (orgId != null) {
+                finishsql.append(" and org_id = " + orgId);
+            }
+            finishsql.append(" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + examId + "  ) )");
+            finishsql.append(" group by t1.org_id ");
+
+            List<ExamStudentOrgStatistic> finishList = jdbcTemplate.query(finishsql.toString(), new BeanPropertyRowMapper<ExamStudentOrgStatistic>(ExamStudentOrgStatistic.class));
+
+            Map<Long, ExamStudentOrgStatistic> finishMap = finishList.stream().collect(Collectors.toMap(ExamStudentOrgStatistic::getOrgId, account -> account));
+
+            for (ExamStudentOrgStatistic statistic : totalList) {
+                ExamStudentOrgStatistic finish = finishMap.get(statistic.getOrgId());
+                statistic.setFinishedCount(finish == null ? 0 : finish.getFinishedCount());
+                OrgCacheBean orgBean = gainBaseDataService.getOrgBean(statistic.getOrgId());
+                statistic.setOrgCode(orgBean.getCode());
+                statistic.setOrgName(orgBean.getName());
+                if (statistic.getTotalCount() == 0 || statistic.getFinishedCount() == 0) {
+                    statistic.setFinishedPercent("0");
+                } else {
+                    double percent = (double) statistic.getFinishedCount() / statistic.getTotalCount();
+                    statistic.setFinishedPercent(new DecimalFormat("#.00").format(percent * 100));
+                }
+            }
+            return totalList;
+        } else {
+            SqlWrapper wrapper = new SqlWrapper()
+                    .select(statisticOrgColumns())
+                    .from("ec_oe_exam_student").as("student")
+                    .where().eq("student.exam_id", examId);
+            if (orgId != null) {
+                wrapper.and().eq("student.org_id", orgId);
+            }
+            wrapper.groupBy("student.org_id").orderBy("student.org_id", false);
+            Query dataQuery = entityManager.createNativeQuery(wrapper.build());
+            dataQuery.unwrap(NativeQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
+            List<ExamStudentOrgStatistic> examStudentOrgStatisticList = ExamStudentEntityConvert.ofList(dataQuery.getResultList());
+            Map<String, Object> cahcheMap = new HashMap<String, Object>();
+            for (ExamStudentOrgStatistic statistic : examStudentOrgStatisticList) {
+                OrgCacheBean orgBean = gainBaseDataService.getOrgBean(statistic.getOrgId());
+                statistic.setOrgCode(orgBean.getCode());
+                statistic.setOrgName(orgBean.getName());
+            }
+            return examStudentOrgStatisticList;
         }
-        return examStudentOrgStatisticList;
     }
 
     @Override
@@ -601,7 +704,7 @@ public class ExamStudentServiceImpl implements ExamStudentService {
 
     @Override
     @Transactional
-    public void setReexamine(Long examStudentId) {
+    public void setReexamine(Long examStudentId, String reexamineType, String reexamineDetail) {
         List<ExamRecordDataEntity> examRecordDataList = examRecordService.getExamRecordListByExamStudentId(examStudentId);
         //查询出上一次重考的记录
         Optional<ExamRecordDataEntity> examRecordOptional = examRecordDataList.stream().filter(examRecordData ->
@@ -622,12 +725,17 @@ public class ExamStudentServiceImpl implements ExamStudentService {
             if (examRecordForMarking != null) {
                 examRecordForMarkingRepo.delete(examRecordForMarking);
             }
+
+            //重新计算考生的最终分数
+            examStudentFinalScoreService.calcAndSaveFinalScore(examRecordData.getExamStudentId());
         }
 
         //考生表重考次数+1
         ExamStudentEntity examStudent = examStudentRepo.findByExamStudentId(examStudentId);
         Integer extraExamNum = examStudent.getExtraNum() == null ? 0 : examStudent.getExtraNum();
         examStudent.setExtraNum(extraExamNum + 1);
+        examStudent.setReexamineType(reexamineType);
+        examStudent.setReexamineDetail(reexamineDetail);
         examStudentRepo.save(examStudent);
 
         //刷新考生的缓存
@@ -639,34 +747,73 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         if (examId == null) {
             return null;
         }
-        if (StringUtils.isBlank(orderColumn)) {
-            orderColumn = "all_num";
-        }
-        String sql = "select *,ROUND(tb.completed_num/tb.all_num,2)*100 completed_proportion from ( " +
-                " select " +
-                " course_id, " +
-                " sum(case when finished = 1 then 1 else 0 end) completed_num, " +
-                " sum(case when finished = 0 then 1 else 0 end) no_completed_num, " +
-                " count(course_id) all_num" +
-                " from ec_oe_exam_student " +
-                " where exam_id = " + examId;
-        if (courseId != null) {
-            sql += " and course_id = " + courseId;
-        }
-        sql += " group by course_id ) tb ORDER BY " + orderColumn + " desc";
+        ExamBean examBean = ExamCacheTransferHelper.getDefaultCachedExam(examId);
+        if (ExamType.ONLINE.name().equals(examBean.getExamType()) || ExamType.ONLINE_HOMEWORK.name().equals(examBean.getExamType())) {
+            StringBuffer totalsql = new StringBuffer();
+            totalsql.append("select t1.course_id courseId,count(t1.id) allNum from ec_oe_exam_student t1 where 1=1 ");
+            totalsql.append(" and exam_id = " + examId);
+            if (courseId != null) {
+                totalsql.append(" and course_id = " + courseId);
+            }
+            totalsql.append(" group by t1.course_id ");
+            List<CourseProgressInfo> totalList = jdbcTemplate.query(totalsql.toString(), new BeanPropertyRowMapper<CourseProgressInfo>(CourseProgressInfo.class));
 
-        return jdbcTemplate.query(sql, new RowMapper<CourseProgressInfo>() {
-            @Override
-            public CourseProgressInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
-                CourseProgressInfo courseProgressInfo = new CourseProgressInfo();
-                courseProgressInfo.setCourseId(rs.getLong("course_id"));
-                courseProgressInfo.setCompletedNum(rs.getInt("completed_num"));
-                courseProgressInfo.setNoCompletedNum(rs.getInt("no_completed_num"));
-                courseProgressInfo.setAllNum(rs.getInt("all_num"));
-                courseProgressInfo.setCompletedProportion(rs.getDouble("completed_proportion"));
-                return courseProgressInfo;
+            StringBuffer finishsql = new StringBuffer();
+            finishsql.append("select t1.course_id courseId,count(t1.id) completedNum from ec_oe_exam_student t1 where 1=1 ");
+            finishsql.append(" and exam_id = " + examId);
+            if (courseId != null) {
+                finishsql.append(" and course_id = " + courseId);
             }
-        });
+            finishsql.append(" AND ( finished = 1 OR t1.exam_student_id in ( SELECT t2.exam_student_id FROM ec_oes_exam_record_data t2 WHERE t2.exam_id=" + examId + "  ))");
+            finishsql.append(" group by t1.course_id ");
+
+            List<CourseProgressInfo> finishList = jdbcTemplate.query(finishsql.toString(), new BeanPropertyRowMapper<CourseProgressInfo>(CourseProgressInfo.class));
+
+            Map<Long, CourseProgressInfo> finishMap = finishList.stream().collect(Collectors.toMap(CourseProgressInfo::getCourseId, account -> account));
+
+            for (CourseProgressInfo statistic : totalList) {
+                CourseProgressInfo finish = finishMap.get(statistic.getCourseId());
+                statistic.setCompletedNum(finish == null ? 0 : finish.getCompletedNum());
+                if (statistic.getAllNum() == 0 || statistic.getCompletedNum() == 0) {
+                    statistic.setCompletedProportion(0.0D);
+                    statistic.setNoCompletedNum(0);
+                } else {
+                    statistic.setNoCompletedNum(statistic.getAllNum() - statistic.getCompletedNum());
+                    double percent = (double) statistic.getCompletedNum() / statistic.getAllNum();
+                    statistic.setCompletedProportion(Double.valueOf(new DecimalFormat("#.00").format(percent * 100)));
+                }
+            }
+            return totalList;
+        } else {
+            if (StringUtils.isBlank(orderColumn)) {
+                orderColumn = "all_num";
+            }
+            String sql = "select *,ROUND(tb.completed_num/tb.all_num,2)*100 completed_proportion from ( " +
+                    " select " +
+                    " course_id, " +
+                    " sum(case when finished = 1 then 1 else 0 end) completed_num, " +
+                    " sum(case when finished = 0 then 1 else 0 end) no_completed_num, " +
+                    " count(course_id) all_num" +
+                    " from ec_oe_exam_student " +
+                    " where exam_id = " + examId;
+            if (courseId != null) {
+                sql += " and course_id = " + courseId;
+            }
+            sql += " group by course_id ) tb ORDER BY " + orderColumn + " desc";
+
+            return jdbcTemplate.query(sql, new RowMapper<CourseProgressInfo>() {
+                @Override
+                public CourseProgressInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
+                    CourseProgressInfo courseProgressInfo = new CourseProgressInfo();
+                    courseProgressInfo.setCourseId(rs.getLong("course_id"));
+                    courseProgressInfo.setCompletedNum(rs.getInt("completed_num"));
+                    courseProgressInfo.setNoCompletedNum(rs.getInt("no_completed_num"));
+                    courseProgressInfo.setAllNum(rs.getInt("all_num"));
+                    courseProgressInfo.setCompletedProportion(rs.getDouble("completed_proportion"));
+                    return courseProgressInfo;
+                }
+            });
+        }
     }
 
     @Override
@@ -706,12 +853,12 @@ public class ExamStudentServiceImpl implements ExamStudentService {
      * @param studentId 学生id
      */
     @Override
-    public List<OnHandExamInfo> queryOnlineExamList(Long studentId) {
+    public List<OnHandExamInfo> queryOnlineExamList(Long studentId, ExamType examType) {
         StudentCacheBean studentBean = CacheHelper.getStudent(studentId);
 
         //获取可以考的和即将考的考试Id
         GetOngoingExamListReq getOngoingExamListReq = new GetOngoingExamListReq();
-        getOngoingExamListReq.setExamType(ExamType.ONLINE.name());
+        getOngoingExamListReq.setExamType(examType.name());
         getOngoingExamListReq.setRootOrgId(studentBean.getRootOrgId());
         getOngoingExamListReq.setOrgId(studentBean.getOrgId());
         getOngoingExamListReq.setStudentId(studentId);
@@ -798,6 +945,7 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         examStudentInfo.setFaceEnable(FaceBiopsyHelper.isFaceEnable(rootOrgId, examId, studentId));
         //进入考试是否验证人脸识别(强制、非强制)
         examStudentInfo.setFaceCheck(FaceBiopsyHelper.isFaceCheck(examId, studentId));
+
         //是否显示客观分
         String isObjScoreView = ExamCacheTransferHelper.getCachedExamProperty(examId,
                 studentId, ExamProperties.IS_OBJ_SCORE_VIEW.name()).getValue();
@@ -806,6 +954,16 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         } else {
             examStudentInfo.setIsObjScoreView(Boolean.valueOf(isObjScoreView));
         }
+
+        //是否开放app考试
+        String appExamEnabled = ExamCacheTransferHelper.getCachedExamProperty(examId,
+                studentId, ExamProperties.APP_EXAM_ENABLED.name()).getValue();
+        if (StringUtils.isBlank(isObjScoreView)) {
+            examStudentInfo.setAppExamEnabled(false);
+        } else {
+            examStudentInfo.setAppExamEnabled(Boolean.valueOf(appExamEnabled));
+        }
+
         return examStudentInfo;
     }
 
@@ -836,6 +994,29 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         return ret;
     }
 
+    private void countUseExamTimes(ExamStudentInfo examStudentInfo, String examType) {
+        if (!ExamType.ONLINE.name().equals(examType) && !ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
+            return;
+        }
+        //考生已考次数
+        int usedNum = (examStudentInfo.getUsedNum() == null ? 0 : examStudentInfo.getUsedNum());
+        //缓存中开考次数
+        int startCount = 0;
+        //缓存中考试完结次数
+        int endCount = 0;
+        String key = RedisKeyHelper.getBuilder().examBossKey(examStudentInfo.getExamStudentId());
+        ExamBoss eb = redisClient.get(key, ExamBoss.class);
+        if (eb != null) {
+            startCount = eb.getStartCount();
+            endCount = eb.getEndCount();
+        }
+        Integer ret = usedNum + startCount - endCount;
+        if (ret < 0) {
+            ret = 0;
+        }
+        examStudentInfo.setUsedNum(ret);
+    }
+
     //获取考试的考生信息
     private ExamStudentBean getRemoteExamStudent(Long rootOrgId, Long examStudentId) {
         GetExamStudentReq req = new GetExamStudentReq();
@@ -844,4 +1025,4 @@ public class ExamStudentServiceImpl implements ExamStudentService {
         GetExamStudentResp resp = examStudentCloudService.getExamStudent(req);
         return resp.getExamStudentBean();
     }
-}
+}

+ 48 - 17
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/IllegallyTypeServiceImpl.java

@@ -28,7 +28,36 @@ public class IllegallyTypeServiceImpl implements IllegallyTypeService {
     @Autowired
     IllegallyTypeRepo illegallyTypeRepo;
 
-    private static final String[] EXCEL_HEADER = new String[]{"违纪类型名称", "违纪类型代码"};
+    private static final String[] EXCEL_HEADER = new String[]{"违纪名称", "违纪代码"};
+
+    /**
+     * 获取违纪类型
+     *
+     * @param rootOrgId
+     * @param code
+     * @return
+     */
+    @Override
+    public IllegallyTypeEntity getIllegallyType(Long rootOrgId, String code) {
+        //先查找自定义的违纪类型
+        IllegallyTypeEntity result = illegallyTypeRepo.findByRootOrgIdAndCode(rootOrgId, code);
+
+        //如果未找到组织机构的自定义数据,则从默认数据中查找
+        if (null == result) {
+            result = illegallyTypeRepo.findByRootOrgIdAndCode(-1L, code);
+        }
+
+        return result;
+    }
+
+    /**
+     * 获取系统级别的违纪类型
+     * @return
+     */
+    @Override
+    public List<IllegallyTypeEntity> getSystemIllegallyTypes() {
+        return illegallyTypeRepo.findByDataCategory(DataCategory.SYSTEM);
+    }
 
     @Override
     public IllegallyTypeEntity saveIllegallyType(IllegallyTypeInfo info) {
@@ -37,7 +66,7 @@ public class IllegallyTypeServiceImpl implements IllegallyTypeService {
         Boolean enable = info.getEnable();
         Long rootOrgId = info.getRootOrgId();
         String name = info.getName();
-        Integer sortNo = info.getSortNo();
+//        Integer sortNo = info.getSortNo();
         String dataCategory = info.getDataCategory();
 
         if (null == rootOrgId) {
@@ -78,9 +107,10 @@ public class IllegallyTypeServiceImpl implements IllegallyTypeService {
             entity.setName(name);
         }
 
-        if (null != sortNo) {
-            entity.setSortNo(sortNo);
-        }
+//        if (null != sortNo) {
+//            entity.setSortNo(sortNo);
+//        }
+        entity.setSortNo(0);
 
         if (StringUtils.isNotEmpty(dataCategory)) {
             entity.setDataCategory(DataCategory.valueOf(dataCategory));
@@ -152,24 +182,25 @@ public class IllegallyTypeServiceImpl implements IllegallyTypeService {
 
             //校验当前编码是否为系统编码
             IllegallyTypeEntity existSysData = illegallyTypeRepo.findByRootOrgIdAndCodeAndDataCategory(
-                    rootOrgId, code, DataCategory.SYSTEM.name());
+                    rootOrgId, code, DataCategory.SYSTEM);
             if (null != existSysData) {
                 msg.append("  违纪类型编码不允许存在数据类型为系统的数据");
                 hasError = true;
             }
 
 
-            //排序号
-            String sortNo = trimAndNullIfBlank(line[2]);
-            if (StringUtils.isBlank(code)) {
-                msg.append("  排序号不能为空");
-                hasError = true;
-            } else if (StringUtils.isNumeric(sortNo)) {
-                msg.append("  排序号必须为正整数的数字");
-                hasError = true;
-            }
+//            //排序号 需求调整,不需要排序号
+//            String sortNo = trimAndNullIfBlank(line[2]);
+//            if (StringUtils.isBlank(code)) {
+//                msg.append("  排序号不能为空");
+//                hasError = true;
+//            } else if (StringUtils.isNumeric(sortNo)) {
+//                msg.append("  排序号必须为正整数的数字");
+//                hasError = true;
+//            }
 
-            illegallyType.setSortNo(Integer.valueOf(sortNo));
+            illegallyType.setSortNo(0);
+            illegallyType.setDataCategory(DataCategory.CUSTOM);
 
             if (hasError) {
                 failRecords.add(newError(i + 1, msg.toString()));
@@ -190,7 +221,7 @@ public class IllegallyTypeServiceImpl implements IllegallyTypeService {
 
             if (null != existData) {
                 existData.setName(cur.getName());
-                existData.setSortNo(cur.getSortNo());
+//                existData.setSortNo(cur.getSortNo());
                 illegallyTypeRepo.save(existData);
             } else {
                 illegallyTypeRepo.save(cur);

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

@@ -7,6 +7,7 @@ import java.util.List;
 
 import javax.transaction.Transactional;
 
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
@@ -21,7 +22,6 @@ import cn.com.qmth.examcloud.core.oe.admin.dao.ExamStudentRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordForMarkingEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamStudentEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamRecordStatus;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordDataService;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordForMarkingService;

+ 2 - 2
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/others/ExamCacheTransferHelper.java

@@ -10,13 +10,13 @@ package cn.com.qmth.examcloud.core.oe.admin.service.others;
 import cn.com.qmth.examcloud.api.commons.enums.ExamSpecialSettingsType;
 import cn.com.qmth.examcloud.commons.util.StringUtil;
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
-import cn.com.qmth.examcloud.core.oe.admin.dao.enums.ExamProperties;
 import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.ExamPropertyCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.ExamSettingsCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.OrgPropertyCacheBean;
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -251,4 +251,4 @@ public class ExamCacheTransferHelper {
 
         return resultBean;
     }
-}
+}

+ 2 - 1
examcloud-core-oe-admin-starter/pom.xml

@@ -5,7 +5,7 @@
 	<parent>
 		<groupId>cn.com.qmth.examcloud</groupId>
 		<artifactId>examcloud-core-oe-admin</artifactId>
-		<version>2019-SNAPSHOT</version>
+		<version>v3.0-RELEASE</version>
 	</parent>
 	<artifactId>examcloud-core-oe-admin-starter</artifactId>
 
@@ -34,6 +34,7 @@
 						</manifestEntries>
 					</archive>
 					<excludes>
+						<exclude>templates/*</exclude>
 						<exclude>*.properties</exclude>
 						<exclude>*.xml</exclude>
 						<exclude>classpath.location</exclude>

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

@@ -1,6 +1,6 @@
 #!/bin/bash
 
-APP_MAIN_JAR="examcloud-core-oe-admin-starter-2019-SNAPSHOT.jar"
+APP_MAIN_JAR="examcloud-core-oe-admin-starter-v3.0-RELEASE.jar"
 
 FILE_PATH=$(cd `dirname $0`; pwd)
 

+ 3 - 1
examcloud-core-oe-admin-starter/shell/stop.sh

@@ -1,5 +1,7 @@
 #!/bin/bash
-APP_MAIN_JAR="examcloud-core-oe-admin-starter-2019-SNAPSHOT.jar"
+
+APP_MAIN_JAR="examcloud-core-oe-admin-starter-v3.0-RELEASE.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

BIN
examcloud-core-oe-admin-starter/src/main/resources/templates/illegallyTypeImportTemplate.xlsx


+ 2 - 2
pom.xml

@@ -5,10 +5,10 @@
 	<parent>
 		<groupId>cn.com.qmth.examcloud</groupId>
 		<artifactId>examcloud-parent</artifactId>
-		<version>2019</version>
+		<version>v3.0-RELEASE</version>
 	</parent>
 	<artifactId>examcloud-core-oe-admin</artifactId>
-	<version>2019-SNAPSHOT</version>
+	<version>v3.0-RELEASE</version>
 	<packaging>pom</packaging>