소스 검색

考试明细列表

deason 10 달 전
부모
커밋
69110ff910

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

@@ -2,25 +2,23 @@ package cn.com.qmth.examcloud.core.oe.admin.api.controller;
 
 import cn.com.qmth.examcloud.api.commons.enums.AdminOperateType;
 import cn.com.qmth.examcloud.api.commons.enums.DataRuleType;
-import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.Check;
 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.ExamRecordFileAnswerRepo;
 import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordDataEntity;
-import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordFileAnswerEntity;
-import cn.com.qmth.examcloud.core.oe.admin.service.*;
+import cn.com.qmth.examcloud.core.oe.admin.service.AsyncExportService;
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordDetailService;
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordService;
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordWaitingAuditService;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.UserDataRules;
-import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordFileAnswerInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordQuery;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamStudentQuestionScoreInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.util.AsyncExportConcurrentUtil;
 import cn.com.qmth.examcloud.reports.commons.bean.AdminOperateReport;
 import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;
-import cn.com.qmth.examcloud.support.fss.FssHelper;
 import cn.com.qmth.examcloud.support.helper.IdentityNumberHelper;
 import cn.com.qmth.examcloud.web.security.DataRule;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
@@ -33,7 +31,6 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -50,6 +47,9 @@ public class ExamRecordController extends ControllerSupport {
     @Autowired
     private ExamRecordService examRecordService;
 
+    @Autowired
+    private ExamRecordDetailService examRecordDetailService;
+
     @Autowired
     private ExamRecordWaitingAuditService examRecordWaitingAuditService;
 
@@ -59,15 +59,6 @@ public class ExamRecordController extends ControllerSupport {
     @Autowired
     private ExamRecordDataRepo examRecordDataRepo;
 
-    @Autowired
-    private ExamCaptureService examCaptureService;
-
-    @Autowired
-    private ExamRecordFileAnswerRepo examRecordFileAnswerRepo;
-
-    @Autowired
-    private ExamProcessRecordService examProcessRecordService;
-
     @DataRule(type = {DataRuleType.COURSE, DataRuleType.ORG})
     @PostMapping("/waiting/audit/list")
     @ApiOperation(value = "查询“监考待审”列表(分页)")
@@ -75,12 +66,12 @@ public class ExamRecordController extends ControllerSupport {
         UserDataRule courseRule = super.getUserDataRule(DataRuleType.COURSE);
         UserDataRule orgRule = super.getUserDataRule(DataRuleType.ORG);
 
-        Page<ExamRecordInfo> examRecordWaitingAuditList = examRecordWaitingAuditService.getExamRecordWaitingAuditList(query, courseRule, orgRule);
+        Page<ExamRecordInfo> page = examRecordWaitingAuditService.getExamRecordWaitingAuditList(query, courseRule, orgRule);
 
-        examRecordWaitingAuditList.getContent().forEach(p -> {
+        page.getContent().forEach(p -> {
             p.setIdentityNumber(IdentityNumberHelper.conceal(p.getRootOrgId(), p.getIdentityNumber()));
         });
-        return examRecordWaitingAuditList;
+        return page;
     }
 
     @DataRule(type = {DataRuleType.COURSE, DataRuleType.ORG})
@@ -104,75 +95,17 @@ public class ExamRecordController extends ControllerSupport {
     @PostMapping("/detail/list")
     @ApiOperation(value = "查询“考试明细”列表(分页)")
     public Page<ExamRecordInfo> getExamRecordDetailList(@RequestBody ExamRecordQuery query) {
-        UserDataRules uds = new UserDataRules(getUserDataRule(DataRuleType.ORG), getUserDataRule(DataRuleType.COURSE));
-        Page<ExamRecordInfo> examRecordInfoPage = examRecordService.getExamRecordDetailListForPage(uds, query);
-        List<ExamRecordInfo> examRecordInfoList = examRecordInfoPage.getContent();
-        if (examRecordInfoList != null && examRecordInfoList.size() > 0) {
-            String examType = examRecordInfoList.get(0).getExamType();
-
-            for (ExamRecordInfo examRecordInfo : examRecordInfoList) {
-                examRecordInfo.setIdentityNumber((IdentityNumberHelper.conceal(examRecordInfo.getRootOrgId(),
-                        examRecordInfo.getIdentityNumber())));
-
-                if (ExamType.OFFLINE.name().equals(examType)) {
-                    long examRecordDataId = examRecordInfo.getDataId();
-                    List<ExamRecordFileAnswerEntity> fileAnswerList =
-                            examRecordFileAnswerRepo.findByExamRecordDataId(examRecordDataId);
-                    if (fileAnswerList != null) {
-                        examRecordInfo.setOfflineFiles(getOfflineFilesFrom(fileAnswerList));
-                    }
-                }
-                if (ExamType.ONLINE.name().equals(examType) || ExamType.ONLINE_HOMEWORK.name().equals(examType)) {
-                    examRecordInfo.setVirtualCameraNames(examCaptureService.getVirtualCameraNames(examRecordInfo.getDataId()));
-                    examRecordInfo.setIp(examProcessRecordService.getIps(examRecordInfo.getDataId()));
-                }
-            }
-        }
-        return examRecordInfoPage;
-    }
-
-    private List<ExamRecordFileAnswerInfo> getOfflineFilesFrom(List<ExamRecordFileAnswerEntity> fileAnswerList) {
-        List<ExamRecordFileAnswerInfo> resultList = new ArrayList<>();
-        for (ExamRecordFileAnswerEntity entity : fileAnswerList) {
-            ExamRecordFileAnswerInfo info = new ExamRecordFileAnswerInfo();
-            info.setId(entity.getId());
-            info.setExamRecordDataId(entity.getExamRecordDataId());
-
-            info.setOfflineFileUrl(FssHelper.finalFileUrl(entity.getFileUrl()));
+        UserDataRule courseRule = super.getUserDataRule(DataRuleType.COURSE);
+        UserDataRule orgRule = super.getUserDataRule(DataRuleType.ORG);
 
-            info.setOfflineFileName(entity.getFileName());
-            info.setOriginalFileName(entity.getOriginalFileName());
-            info.setFileType(entity.getFileType());
-            info.setSuffix(entity.getSuffix());
-            info.setProperties(entity.getProperties());
-            resultList.add(info);
-        }
+        Page<ExamRecordInfo> page = examRecordDetailService.getExamRecordDetailList(query, courseRule, orgRule);
 
-        return resultList;
+        page.getContent().forEach(p -> {
+            p.setIdentityNumber(IdentityNumberHelper.conceal(p.getRootOrgId(), p.getIdentityNumber()));
+        });
+        return page;
     }
 
-    //    @Naked
-    //    @GetMapping("/detail/list/export")
-    //    @ApiOperation(value = "导出“考试明细”列表(Excel)", notes = "参数示例:query={\"pageNo\":1,\"pageSize\":10,\"examId\":123, ...}")
-    //    public void exportExamRecordDetailList(@RequestParam String query, HttpServletResponse response) throws Exception {
-    //        ExamRecordQuery newQuery = new JsonMapper().parseJson(query, ExamRecordQuery.class);
-    //        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);
-    //    }
-
     @GetMapping("/detail/list/export/async")
     @ApiOperation(value = "导出“考试明细”列表(异步)", notes = "参数示例:query={\"rootOrgId\":0,\"examId\":1}")
     public void exportExamRecordDetails(@RequestParam String query) {

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

@@ -32,7 +32,7 @@ public class ExamRecordInfo implements JsonSerializable {
     /**
      * 考试记录ID
      */
-    @ExcelProperty(name = "考试编码", width = 30, index = 14)
+    @ExcelProperty(name = "考试记录ID", width = 30, index = 14)
     private Long id;
 
     /**

+ 114 - 16
examcloud-core-oe-admin-service/src/main/java/cn/com/qmth/examcloud/core/oe/admin/service/impl/ExamRecordDetailServiceImpl.java

@@ -1,16 +1,25 @@
 package cn.com.qmth.examcloud.core.oe.admin.service.impl;
 
+import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
+import cn.com.qmth.examcloud.commons.util.DateUtil;
+import cn.com.qmth.examcloud.commons.util.StringUtil;
 import cn.com.qmth.examcloud.core.oe.admin.base.jpa.SpecUtils;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.Check;
 import cn.com.qmth.examcloud.core.oe.admin.base.utils.DateUtils;
+import cn.com.qmth.examcloud.core.oe.admin.dao.ExamRecordFileAnswerRepo;
+import cn.com.qmth.examcloud.core.oe.admin.dao.entity.ExamRecordFileAnswerEntity;
 import cn.com.qmth.examcloud.core.oe.admin.dao.enums.CourseLevel;
+import cn.com.qmth.examcloud.core.oe.admin.dao.enums.IsSuccess;
+import cn.com.qmth.examcloud.core.oe.admin.dao.enums.TrueFalse;
 import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordDetailService;
+import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordFileAnswerInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordInfo;
 import cn.com.qmth.examcloud.core.oe.admin.service.bean.examrecord.ExamRecordQuery;
 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.ExamSettingsCacheBean;
+import cn.com.qmth.examcloud.support.cache.bean.*;
+import cn.com.qmth.examcloud.support.enums.ExamProperties;
+import cn.com.qmth.examcloud.support.fss.FssHelper;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
@@ -23,6 +32,7 @@ import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -32,6 +42,9 @@ public class ExamRecordDetailServiceImpl implements ExamRecordDetailService {
 
     private static final Logger log = LoggerFactory.getLogger(ExamRecordDetailServiceImpl.class);
 
+    @Autowired
+    private ExamRecordFileAnswerRepo examRecordFileAnswerRepo;
+
     @Autowired
     private JdbcTemplate jdbcTemplate;
 
@@ -71,6 +84,15 @@ public class ExamRecordDetailServiceImpl implements ExamRecordDetailService {
         ExamSettingsCacheBean examCache = CacheHelper.getExamSettings(examId);
         Map<Long, String> orgMaps = new HashMap<>();
         Map<Long, CourseCacheBean> courseMaps = new HashMap<>();
+        Map<Long, ExamStageCacheBean> examStageMaps = new HashMap<>();
+        Map<Long, StudentCacheBean> studentMaps = new HashMap<>();
+
+        //考试 是否开启身份检测
+        boolean faceEnable = false;
+        if (ExamType.ONLINE.name().equals(examCache.getExamType())) {
+            ExamPropertyCacheBean property = CacheHelper.getExamProperty(examId, ExamProperties.IS_FACE_ENABLE.name());
+            faceEnable = property != null && StringUtil.isTrue(property.getValue());
+        }
 
         for (ExamRecordInfo info : list) {
             // 考试名称
@@ -95,8 +117,42 @@ public class ExamRecordDetailServiceImpl implements ExamRecordDetailService {
             info.setCourseLevel(CourseLevel.getCourseLevel(course.getLevel()).getTitle());
             info.setCourseNameAndCode(info.getCourseName() + "(" + info.getCourseCode() + ")");
 
+            // 场次信息
+            if (info.getExamStageId() != null) {
+                ExamStageCacheBean examStage = examStageMaps.get(info.getExamStageId());
+                if (examStage == null) {
+                    examStage = CacheHelper.getExamStage(examId, info.getExamStageId());
+                    examStageMaps.put(info.getExamStageId(), examStage);
+                }
+                info.setExamStageOrder(examStage.getStageOrder());
+                info.setStageStartTime(examStage.getStartTime());
+                info.setStageEndTime(examStage.getEndTime());
+                info.setExamStage(examStage.getStageOrder() + "("
+                        + DateUtil.format(examStage.getStartTime(), DateUtil.DatePatterns.CHINA_DEFAULT) + "至"
+                        + DateUtil.format(examStage.getEndTime(), DateUtil.DatePatterns.CHINA_DEFAULT) + ")");
+            }
+
+            // 学生信息
+            StudentCacheBean student = studentMaps.get(info.getStudentId());
+            if (student == null) {
+                student = CacheHelper.getStudent(info.getStudentId());
+                studentMaps.put(info.getStudentId(), student);
+            }
+            info.setPhone(student.getPhoneNumber());
+
             info.setDataId(info.getId());
             info.setHasVirtual(StringUtils.isNotBlank(info.getVirtualCameraNames()));
+            info.setShowReAudit(faceEnable);
+            info.setStudentNumber(info.getStudentId() + "" + info.getExamStudentId());
+
+            if (info.getSubjectiveTotalScore() == null) {
+                info.setSubjectiveTotalScore("0");
+            }
+
+            //违纪标志
+            info.setDisciplineSign(TrueFalse.of(info.getIsWarn()));
+            info.setIsIllegality("1".equals(info.getIsIllegality()) ? "是" : "否");
+
             if (info.getStartTime() != null) {
                 info.setPaperStartTime(DateUtils.format(info.getStartTime()));
             } else {
@@ -104,10 +160,52 @@ public class ExamRecordDetailServiceImpl implements ExamRecordDetailService {
             }
             if (info.getEndTime() != null) {
                 info.setPaperSubmitTime(DateUtils.format(info.getEndTime()));
+                info.setIsSubmit("是");
             } else {
                 info.setPaperSubmitTime("");
+                info.setIsSubmit("否");
             }
+
+            //每次考试持续时间
+            if (info.getStartTime() != null && info.getEndTime() != null) {
+                if (info.getUsedExamTime() != null) {
+                    info.setExamTime(info.getUsedExamTime() > 0 ? DateUtils.diff(info.getUsedExamTime()) : "");
+                }
+            } else {
+                info.setExamTime("");
+            }
+
+            IsSuccess result = IsSuccess.strToEnum(info.getFaceVerifyResult());
+            if (result != null) {
+                info.setFaceVerifyResult(result.getDesc());
+            }
+
+            if (ExamType.OFFLINE.name().equals(examCache.getExamType())) {
+                // 离线考试作答文件
+                List<ExamRecordFileAnswerEntity> fileAnswers = examRecordFileAnswerRepo.findByExamRecordDataId(info.getId());
+                info.setOfflineFiles(this.ofFileAnswer(fileAnswers));
+            }
+        }
+    }
+
+    private List<ExamRecordFileAnswerInfo> ofFileAnswer(List<ExamRecordFileAnswerEntity> entities) {
+        List<ExamRecordFileAnswerInfo> result = new ArrayList<>();
+
+        for (ExamRecordFileAnswerEntity entity : entities) {
+            ExamRecordFileAnswerInfo info = new ExamRecordFileAnswerInfo();
+            info.setId(entity.getId());
+            info.setExamRecordDataId(entity.getExamRecordDataId());
+            info.setOfflineFileName(entity.getFileName());
+            info.setOriginalFileName(entity.getOriginalFileName());
+            info.setFileType(entity.getFileType());
+            info.setSuffix(entity.getSuffix());
+            info.setProperties(entity.getProperties());
+
+            info.setOfflineFileUrl(FssHelper.finalFileUrl(entity.getFileUrl()));
+            result.add(info);
         }
+
+        return result;
     }
 
     private String queryExamRecordDetailListSql(ExamRecordQuery query, boolean isCount
@@ -117,6 +215,8 @@ public class ExamRecordDetailServiceImpl implements ExamRecordDetailService {
             sql.append(" select count(DISTINCT rd.id)");
         } else {
             sql.append(" select rd.*,a.audit_user_name,sco.objective_score objectiveTotalScore,");
+            sql.append(" sco.subjective_score subjectiveTotalScore,sco.total_score paperTotalScore,");
+            sql.append(" es.grade,es.specialty_name,");
             sql.append(" (select GROUP_CONCAT(DISTINCT pr.source_ip) from ec_oe_exam_process_record pr")
                     .append(" where pr.exam_record_data_id = rd.id) ip,");
             sql.append(" (select GROUP_CONCAT(DISTINCT cm.name) from ec_oe_exam_capture_camera_info cm")
@@ -124,6 +224,7 @@ public class ExamRecordDetailServiceImpl implements ExamRecordDetailService {
         }
 
         sql.append(" from ec_oe_exam_record_data rd");
+        sql.append(" left join ec_oe_exam_student es on es.exam_student_id = rd.exam_student_id");
         sql.append(" left join ec_oe_exam_audit a on a.exam_record_data_id = rd.id");
         sql.append(" left join ec_oe_exam_score sco on sco.exam_record_data_id = rd.id");
 
@@ -209,6 +310,17 @@ public class ExamRecordDetailServiceImpl implements ExamRecordDetailService {
             sql.append(" and rd.switch_screen_count <= ").append(query.getSwitchScreenCountEnd());
         }
 
+        if (StringUtils.isNotBlank(query.getAuditUserName())) {
+            sql.append(" and a.audit_user_name like '").append(query.getAuditUserName()).append("%'");
+        }
+
+        if (StringUtils.isNotBlank(query.getIp())) {
+            sql.append(" and exists (");
+            sql.append(" select 1 from ec_oe_exam_process_record pr where pr.exam_record_data_id = rd.id");
+            sql.append(" and pr.source_ip = '").append(query.getIp()).append("'");
+            sql.append(" )");
+        }
+
         if (query.getHasVirtual() != null) {
             sql.append(" and").append(query.getHasVirtual() ? " exists" : " not exists");
             sql.append(" (");
@@ -227,20 +339,6 @@ public class ExamRecordDetailServiceImpl implements ExamRecordDetailService {
             }
         }
 
-        if (StringUtils.isNotBlank(query.getAuditUserName())) {
-            sql.append(" and exists (");
-            sql.append(" select 1 from ec_oe_exam_audit aa where aa.exam_record_data_id = rd.id");
-            sql.append(" and aa.audit_user_name like '").append(query.getAuditUserName()).append("%'");
-            sql.append(" )");
-        }
-
-        if (StringUtils.isNotBlank(query.getIp())) {
-            sql.append(" and exists (");
-            sql.append(" select 1 from ec_oe_exam_process_record pr where pr.exam_record_data_id = rd.id");
-            sql.append(" and pr.source_ip = '").append(query.getIp()).append("'");
-            sql.append(" )");
-        }
-
         if (!isCount) {
             sql.append(" group by rd.id");