Ver código fonte

监考待审列表

deason 11 meses atrás
pai
commit
4e802983a7

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

@@ -1,26 +1,17 @@
-/*
- * *************************************************
- * Copyright (c) 2018 QMTH. All Rights Reserved.
- * Created by Deason on 2018-08-27 14:52:17.
- * *************************************************
- */
-
 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.AsyncExportService;
-import cn.com.qmth.examcloud.core.oe.admin.service.ExamCaptureService;
-import cn.com.qmth.examcloud.core.oe.admin.service.ExamProcessRecordService;
-import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordService;
+import cn.com.qmth.examcloud.core.oe.admin.service.*;
 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;
@@ -35,7 +26,6 @@ import cn.com.qmth.examcloud.web.security.DataRule;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
 import org.springframework.http.HttpStatus;
@@ -60,6 +50,9 @@ public class ExamRecordController extends ControllerSupport {
     @Autowired
     private ExamRecordService examRecordService;
 
+    @Autowired
+    private ExamRecordWaitingAuditService examRecordWaitingAuditService;
+
     @Autowired
     private AsyncExportService asyncExportService;
 
@@ -75,28 +68,18 @@ public class ExamRecordController extends ControllerSupport {
     @Autowired
     private ExamProcessRecordService examProcessRecordService;
 
-
     @DataRule(type = {DataRuleType.COURSE, DataRuleType.ORG})
     @PostMapping("/waiting/audit/list")
     @ApiOperation(value = "查询“监考待审”列表(分页)")
     public Page<ExamRecordInfo> getExamRecordWaitingAuditList(@RequestBody ExamRecordQuery query) {
-        UserDataRules uds = new UserDataRules(getUserDataRule(DataRuleType.ORG), getUserDataRule(DataRuleType.COURSE));
-        Page<ExamRecordInfo> examRecordWaitingAuditList = examRecordService.getExamRecordWaitingAuditList(uds, query);
+        UserDataRule courseRule = super.getUserDataRule(DataRuleType.COURSE);
+        UserDataRule orgRule = super.getUserDataRule(DataRuleType.ORG);
+
+        Page<ExamRecordInfo> examRecordWaitingAuditList = examRecordWaitingAuditService.getExamRecordWaitingAuditList(query, courseRule, orgRule);
+
         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()));
-                    examRecordInfo.setHasVirtual(StringUtils.isNotBlank(examRecordInfo.getVirtualCameraNames()));
-                    examRecordInfo.setIp(examProcessRecordService.getIps(examRecordInfo.getDataId()));
-                }
-            }
-        }
         return examRecordWaitingAuditList;
     }
 

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

@@ -7,6 +7,9 @@ import org.springframework.data.domain.Page;
 
 public interface ExamRecordIllegallyService {
 
+    /**
+     * 查询“违纪名单”列表(分页)
+     */
     Page<ExamAuditInfo> getExamRecordIllegallyList(ExamAuditQuery query, UserDataRule courseRule, UserDataRule orgRule);
 
 }

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

@@ -0,0 +1,15 @@
+package cn.com.qmth.examcloud.core.oe.admin.service;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
+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 org.springframework.data.domain.Page;
+
+public interface ExamRecordWaitingAuditService {
+
+    /**
+     * 查询“监考待审”列表(分页)
+     */
+    Page<ExamRecordInfo> getExamRecordWaitingAuditList(ExamRecordQuery query, UserDataRule courseRule, UserDataRule orgRule);
+
+}

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

@@ -130,6 +130,9 @@ public class ExamRecordQuery implements JsonSerializable {
 	@ApiModelProperty(hidden = true)
 	private Long taskId;
 
+	@ApiModelProperty("异常类型")
+	private String warnType;
+
 	public ExamRecordQuery addRecordStatus(String recordStatus) {
 		if (recordStatuses == null) {
 			recordStatuses = new ArrayList<>();
@@ -433,4 +436,12 @@ public class ExamRecordQuery implements JsonSerializable {
 		this.taskId = taskId;
 	}
 
+	public String getWarnType() {
+		return warnType;
+	}
+
+	public void setWarnType(String warnType) {
+		this.warnType = warnType;
+	}
+
 }

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

@@ -0,0 +1,240 @@
+package cn.com.qmth.examcloud.core.oe.admin.service.impl;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
+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.dao.enums.CourseLevel;
+import cn.com.qmth.examcloud.core.oe.admin.service.ExamRecordWaitingAuditService;
+import cn.com.qmth.examcloud.core.oe.admin.service.IllegallyTypeService;
+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 org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.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.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class ExamRecordWaitingAuditServiceImpl implements ExamRecordWaitingAuditService {
+
+    private static final Logger log = LoggerFactory.getLogger(ExamRecordWaitingAuditServiceImpl.class);
+
+    @Autowired
+    private IllegallyTypeService illegallyTypeService;
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Override
+    public Page<ExamRecordInfo> getExamRecordWaitingAuditList(ExamRecordQuery query, UserDataRule courseRule, UserDataRule orgRule) {
+        Check.isNull(query, "请求参数不能为空!");
+        Check.isNull(query.getExamId(), "请先选择考试!");
+
+        Pageable pageable = SpecUtils.buildPageable(query.getPageNo(), query.getPageSize());
+        if (courseRule.assertEmptyQueryResult() || orgRule.assertEmptyQueryResult()) {
+            return Page.empty(pageable);
+        }
+
+        int offset = (query.getPageNo() - 1) * query.getPageSize();
+        String countSql = this.queryExamRecordWaitingAuditListSql(query, true, courseRule, orgRule);
+        String querySql = this.queryExamRecordWaitingAuditListSql(query, false, courseRule, orgRule);
+        String pageSql = querySql + " limit " + offset + "," + query.getPageSize();
+
+        Long totalElements = jdbcTemplate.queryForObject(countSql, Long.class);
+        if (totalElements == null || totalElements == 0) {
+            return Page.empty(pageable);
+        }
+
+        List<ExamRecordInfo> list = jdbcTemplate.query(pageSql, new BeanPropertyRowMapper(ExamRecordInfo.class));
+        if (CollectionUtils.isEmpty(list)) {
+            return Page.empty(pageable);
+        }
+
+        // 填充其它信息
+        this.fillOtherInfo(list, query.getExamId());
+
+        return new PageImpl<>(list, pageable, totalElements);
+    }
+
+    private void fillOtherInfo(List<ExamRecordInfo> list, Long examId) {
+        ExamSettingsCacheBean examCache = CacheHelper.getExamSettings(examId);
+        Map<Long, String> orgMaps = new HashMap<>();
+        Map<Long, CourseCacheBean> courseMaps = new HashMap<>();
+
+        for (ExamRecordInfo info : list) {
+            // 考试名称
+            info.setExamName(examCache.getName());
+
+            // 学习中心名称
+            String orgName = orgMaps.get(info.getOrgId());
+            if (orgName == null) {
+                orgName = CacheHelper.getOrg(info.getOrgId()).getName();
+                orgMaps.put(info.getOrgId(), orgName);
+            }
+            info.setOrgName(orgName);
+
+            // 课程信息
+            CourseCacheBean course = courseMaps.get(info.getCourseId());
+            if (course == null) {
+                course = CacheHelper.getCourse(info.getCourseId());
+                courseMaps.put(info.getCourseId(), course);
+            }
+            info.setCourseCode(course.getCode());
+            info.setCourseName(course.getName());
+            info.setCourseLevel(CourseLevel.getCourseLevel(course.getLevel()).getTitle());
+            info.setCourseNameAndCode(info.getCourseName() + "(" + info.getCourseCode() + ")");
+
+            info.setDataId(info.getId());
+            info.setHasVirtual(StringUtils.isNotBlank(info.getVirtualCameraNames()));
+        }
+    }
+
+    private String queryExamRecordWaitingAuditListSql(ExamRecordQuery query, boolean isCount
+            , UserDataRule courseRule, UserDataRule orgRule) {
+        StringBuilder sql = new StringBuilder();
+        if (isCount) {
+            sql.append(" select count(DISTINCT rd.id)");
+        } else {
+            sql.append(" select rd.*,a.audit_user_name,sco.objective_score objectiveTotalScore,");
+            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")
+                    .append(" where cm.exam_record_data_id = rd.id and cm.virtual_camera = 1) virtualCameraNames");
+        }
+
+        sql.append(" from ec_oe_exam_record_data rd");
+        sql.append(" left join ec_oe_exam_audit a on a.exam_record_data_id = rd.id");
+        sql.append(" left join ec_oe_exam_warn w on w.exam_record_data_id = rd.id");
+        sql.append(" left join ec_oe_exam_score sco on sco.exam_record_data_id = rd.id");
+
+        sql.append(" where rd.exam_id = ").append(query.getExamId());
+        sql.append(" and rd.exam_record_status in ('EXAM_END','EXAM_OVERDUE')");
+        sql.append(" and rd.is_audit = 0");
+        sql.append(" and rd.is_illegality = 0");
+        if (query.getIsWarn() != null) {
+            sql.append(" and rd.is_warn = ").append(query.getIsWarn() ? "1" : "0");
+        }
+        if (query.getExamRecordId() != null) {
+            sql.append(" and rd.id = ").append(query.getExamRecordId());
+        }
+
+        if (courseRule.assertNeedQueryRefIds()) {
+            // 限定课程数据权限范围
+            if (query.getCourseId() != null) {
+                if (courseRule.getRefIds().contains(query.getCourseId())) {
+                    sql.append(" and rd.course_id = ").append(query.getCourseId());
+                } else {
+                    // 不在数据权限范围内,无效查询
+                    sql.append(" and rd.course_id = -1");
+                }
+            } else {
+                sql.append(" and rd.course_id in (").append(StringUtils.join(courseRule.getRefIds(), ",")).append(")");
+            }
+        } else {
+            // 未限定数据权限
+            if (query.getCourseId() != null) {
+                sql.append(" and rd.course_id = ").append(query.getCourseId());
+            }
+        }
+
+        if (orgRule.assertNeedQueryRefIds()) {
+            // 限定机构数据权限范围
+            if (query.getOrgId() != null) {
+                if (orgRule.getRefIds().contains(query.getOrgId())) {
+                    sql.append(" and rd.org_id = ").append(query.getOrgId());
+                } else {
+                    // 不在数据权限范围内,无效查询
+                    sql.append(" and rd.org_id = -1");
+                }
+            } else {
+                sql.append(" and rd.org_id in (").append(StringUtils.join(orgRule.getRefIds(), ",")).append(")");
+            }
+        } else {
+            // 未限定数据权限
+            if (query.getOrgId() != null) {
+                sql.append(" and rd.org_id = ").append(query.getOrgId());
+            }
+        }
+
+        if (query.getExamStageId() != null) {
+            sql.append(" and rd.exam_stage_id = ").append(query.getExamStageId());
+        }
+        if (StringUtils.isNotBlank(query.getCourseLevel())) {
+            sql.append(" and rd.course_level = '").append(query.getCourseLevel()).append("'");
+        }
+        if (StringUtils.isNotBlank(query.getIdentityNumber())) {
+            sql.append(" and rd.identity_number like '").append(query.getIdentityNumber()).append("%'");
+        }
+        if (StringUtils.isNotBlank(query.getStudentCode())) {
+            sql.append(" and rd.student_code like '").append(query.getStudentCode()).append("%'");
+        }
+        if (StringUtils.isNotBlank(query.getStudentName())) {
+            sql.append(" and rd.student_name like '").append(query.getStudentName()).append("%'");
+        }
+
+        if (StringUtils.isNotBlank(query.getStartTime()) && StringUtils.isNotBlank(query.getEndTime())) {
+            sql.append(" and rd.start_time >= '").append(query.getStartTime()).append("'");
+            sql.append(" and rd.start_time <= '").append(query.getEndTime()).append("'");
+        }
+
+        if (StringUtils.isNotBlank(query.getSubmitStartTime()) && StringUtils.isNotBlank(query.getSubmitEndTime())) {
+            sql.append(" and rd.end_time >= '").append(query.getSubmitStartTime()).append("'");
+            sql.append(" and rd.end_time <= '").append(query.getSubmitEndTime()).append("'");
+        }
+
+        if (query.getFaceSuccessPercentLower() != null && query.getFaceSuccessPercentUpper() != null) {
+            sql.append(" and rd.face_success_percent >= ").append(query.getFaceSuccessPercentLower());
+            sql.append(" and rd.face_success_percent <= ").append(query.getFaceSuccessPercentUpper());
+        }
+
+        if (query.getLivenessSuccessPercentLower() != null && query.getLivenessSuccessPercentUpper() != null) {
+            sql.append(" and rd.baidu_face_liveness_success_percent >= ").append(query.getLivenessSuccessPercentLower());
+            sql.append(" and rd.baidu_face_liveness_success_percent <= ").append(query.getLivenessSuccessPercentUpper());
+        }
+
+        if (query.getHasStranger() != null) {
+            if (query.getHasStranger()) {
+                sql.append(" and rd.face_stranger_count > 0");
+            } else {
+                sql.append(" and rd.face_stranger_count = 0");
+            }
+        }
+
+        if (query.getHasVirtual() != null) {
+            if (query.getHasVirtual()) {
+                sql.append(" and exists(");
+                sql.append(" select 1 from ec_oe_exam_capture_camera_info v where v.exam_record_data_id = rd.id and v.virtual_camera = 1");
+                sql.append(" )");
+            } else {
+                sql.append(" and not exists(");
+                sql.append(" select 1 from ec_oe_exam_capture_camera_info v where v.exam_record_data_id = rd.id and v.virtual_camera = 1");
+                sql.append(" )");
+            }
+        }
+
+        if (StringUtils.isNotBlank(query.getWarnType())) {
+            sql.append(" and w.warn_type = '").append(query.getWarnType()).append("'");
+        }
+
+        if (!isCount) {
+            sql.append(" group by rd.id");
+            sql.append(" order by rd.id desc");
+        }
+
+        return sql.toString();
+    }
+
+}