浏览代码

新增统计考试信息

wangliang 1 年之前
父节点
当前提交
ebdb9848b2

+ 40 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TEExamSummaryMapper.java

@@ -2,6 +2,7 @@ package com.qmth.themis.business.dao;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qmth.themis.business.entity.TEExamSummary;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * <p>
@@ -13,4 +14,43 @@ import com.qmth.themis.business.entity.TEExamSummary;
  */
 public interface TEExamSummaryMapper extends BaseMapper<TEExamSummary> {
 
+    /**
+     * 统计考试信息
+     *
+     * @param examId
+     * @param examActivityId
+     * @param roomCode
+     * @return
+     */
+    TEExamSummary examSummary(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId, @Param("roomCode") String roomCode);
+
+    /**
+     * 保存统计考试信息
+     *
+     * @param fieldName
+     * @param fieldValue
+     * @return
+     */
+    Boolean saveExamSummary(@Param("fieldName") String fieldName, @Param("fieldValue") String fieldValue);
+
+    /**
+     * 更新统计考试信息
+     *
+     * @param examId
+     * @param examActivityId
+     * @param roomCode
+     * @param fieldValue
+     * @return
+     */
+    Boolean updateExamSummary(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId, @Param("roomCode") String roomCode, @Param("fieldValue") String fieldValue);
+
+    /**
+     * 查询统计考试信息count
+     *
+     * @param examId
+     * @param examActivityId
+     * @param roomCode
+     * @return
+     */
+    int selectExamSummaryCount(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId, @Param("roomCode") String roomCode);
 }

+ 13 - 12
themis-business/src/main/java/com/qmth/themis/business/entity/TEExamSummary.java

@@ -1,5 +1,6 @@
 package com.qmth.themis.business.entity;
 
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import io.swagger.annotations.ApiModel;
@@ -31,40 +32,40 @@ public class TEExamSummary implements Serializable {
     private String roomCode;
 
     @ApiModelProperty(value = "考生总数")
-    private Integer totalCount;
+    private Integer totalCount = 0;
 
     @ApiModelProperty(value = "候考人数")
-    private Integer prepareCount;
+    private Integer prepareCount = 0;
 
     @ApiModelProperty(value = "正在考试人数")
-    private Integer examCount;
+    private Integer examCount = 0;
 
     @ApiModelProperty(value = "考试完成人数")
-    private Integer finishCount;
+    private Integer finishCount = 0;
 
     @ApiModelProperty(value = "缺考人数")
-    private Integer absentCount;
+    private Integer absentCount = 0;
 
     @ApiModelProperty(value = "在线人数")
-    private Integer onlineCount;
+    private Integer onlineCount = 0;
 
     @ApiModelProperty(value = "离线人数")
-    private Integer offlineCount;
+    private Integer offlineCount = 0;
 
     @ApiModelProperty(value = "监控停止人数")
-    private Integer monitorStopCount;
+    private Integer monitorStopCount = 0;
 
     @ApiModelProperty(value = "预警总数")
-    private Integer warningCount;
+    private Integer warningCount = 0;
 
     @ApiModelProperty(value = "预警未读数")
-    private Integer warningUnread;
+    private Integer warningUnread = 0;
 
     @ApiModelProperty(value = "陌生人脸预警总数")
-    private Integer warningMultipleFaceCount;
+    private Integer warningMultipleFaceCount = 0;
 
     @ApiModelProperty(value = "异常数据总数")
-    private Integer exceptionCount;
+    private Integer exceptionCount = 0;
 
     public Long getExamId() {
         return examId;

+ 57 - 0
themis-business/src/main/java/com/qmth/themis/business/enums/ExamSummaryEnum.java

@@ -0,0 +1,57 @@
+package com.qmth.themis.business.enums;
+
+import java.util.Objects;
+
+/**
+* @Description: 考试信息统计表enum
+* @Param:
+* @return:
+* @Author: wangliang
+* @Date: 2023/10/28
+*/
+public enum ExamSummaryEnum {
+
+    examId("exam_id"),
+
+    examActivityId("exam_activity_id"),
+
+    roomCode("room_code"),
+
+    totalCount("total_count"),
+
+    prepareCount("prepare_count"),
+
+    examCount("exam_count"),
+
+    finishCount("finish_count"),
+
+    absentCount("absent_count"),
+
+    onlineCount("online_count"),
+
+    offlineCount("offline_count"),
+
+    monitorStopCount("monitor_stop_count"),
+
+    warningCount("warning_count"),
+
+    warningUnread("warning_unread"),
+
+    warningMultipleFaceCount("warning_multiple_face_count"),
+
+    exceptionCount("exception_count");
+
+    ExamSummaryEnum(String code) {
+        this.code = code;
+    }
+
+    private String code;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+}

+ 10 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TEExamSummaryService.java

@@ -3,6 +3,8 @@ package com.qmth.themis.business.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.themis.business.entity.TEExamSummary;
 
+import java.util.Set;
+
 /**
  * <p>
  * 考试信息统计表 服务类
@@ -13,4 +15,12 @@ import com.qmth.themis.business.entity.TEExamSummary;
  */
 public interface TEExamSummaryService extends IService<TEExamSummary> {
 
+    /**
+     * 统计考试信息
+     *
+     * @param examId
+     * @param examActivityId
+     * @param roomCodeSet
+     */
+    void examSummary(Long examId, Long examActivityId, Set<String> roomCodeSet);
 }

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/service/ThemisCacheService.java

@@ -317,7 +317,7 @@ public interface ThemisCacheService {
      * @param examId
      * @return
      */
-    public Map getTodayExamCache(String examId);
+    public Map<String, Set<String>> getTodayExamCache(String examId);
 
     /**
      * 更新当天考试缓存

+ 115 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamSummaryServiceImpl.java

@@ -1,10 +1,19 @@
 package com.qmth.themis.business.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.dao.TEExamSummaryMapper;
 import com.qmth.themis.business.entity.TEExamSummary;
+import com.qmth.themis.business.enums.ExamSummaryEnum;
+import com.qmth.themis.business.service.TEExamActivityService;
 import com.qmth.themis.business.service.TEExamSummaryService;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Objects;
+import java.util.Set;
+import java.util.StringJoiner;
 
 /**
  * <p>
@@ -17,4 +26,110 @@ import org.springframework.stereotype.Service;
 @Service
 public class TEExamSummaryServiceImpl extends ServiceImpl<TEExamSummaryMapper, TEExamSummary> implements TEExamSummaryService {
 
+    @Resource
+    TEExamActivityService teExamActivityService;
+
+    /**
+     * 统计考试信息
+     *
+     * @param examId
+     * @param examActivityId
+     * @param roomCodeSet
+     */
+    @Override
+    @Transactional
+    public void examSummary(Long examId, Long examActivityId, Set<String> roomCodeSet) {
+        for (String s : roomCodeSet) {
+            TEExamSummary teExamSummary = this.baseMapper.examSummary(examId, examActivityId, s);
+            if (Objects.nonNull(teExamSummary)) {
+                teExamSummary.setExamId(examId);
+                teExamSummary.setExamActivityId(examActivityId);
+                teExamSummary.setRoomCode(s);
+                ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(examActivityId);
+                //当考试场次开始时间已过且未结束考试,当前侯考数设为0,缺考数设为侯考数
+                long timestamp = System.currentTimeMillis();
+                if (teExamSummary.getPrepareCount().intValue() > 0) {//侯考
+                    teExamSummary.setAbsentCount(teExamSummary.getTotalCount() - teExamSummary.getPrepareCount());
+                }
+                //考试中
+                if (examActivityCacheBean.getStartTime().longValue() <= timestamp
+                        && examActivityCacheBean.getFinishTime().longValue() > timestamp) {
+                    teExamSummary.setPrepareCount(0);
+                    teExamSummary.setAbsentCount(teExamSummary.getTotalCount() - teExamSummary.getExamCount());
+                }//交卷
+                else if (examActivityCacheBean.getFinishTime().longValue() <= timestamp) {//当考试场次结束时间已过,缺考=全部应考-已完成考试
+                    teExamSummary.setAbsentCount(teExamSummary.getTotalCount() - teExamSummary.getFinishCount());
+                }
+                int count = this.baseMapper.selectExamSummaryCount(examId, examActivityId, s);
+                StringJoiner stringJoinerFieldName = new StringJoiner(",");
+                StringJoiner stringJoinerFieldValue = new StringJoiner(",");
+                ExamSummaryEnum[] examSummaryEnums = ExamSummaryEnum.values();
+                if (count == 0) {
+                    for (int i = 0; i < examSummaryEnums.length; i++) {
+                        stringJoinerFieldName.add(examSummaryEnums[i].getCode());
+                    }
+                    stringJoinerFieldValue.add("'" + teExamSummary.getExamId() + "'")
+                            .add("'" + teExamSummary.getExamActivityId() + "'")
+                            .add("'" + teExamSummary.getRoomCode() + "'")
+                            .add(teExamSummary.getTotalCount() + "")
+                            .add(teExamSummary.getPrepareCount() + "")
+                            .add(teExamSummary.getExamCount() + "")
+                            .add(teExamSummary.getFinishCount() + "")
+                            .add(teExamSummary.getAbsentCount() + "")
+                            .add(teExamSummary.getOnlineCount() + "")
+                            .add(teExamSummary.getOfflineCount() + "")
+                            .add(teExamSummary.getMonitorStopCount() + "")
+                            .add(teExamSummary.getWarningCount() + "")
+                            .add(teExamSummary.getWarningUnread() + "")
+                            .add(teExamSummary.getWarningMultipleFaceCount() + "")
+                            .add(teExamSummary.getExceptionCount() + "");
+                    this.baseMapper.saveExamSummary(stringJoinerFieldName.toString(), stringJoinerFieldValue.toString());
+                } else {
+                    for (int i = 0; i < examSummaryEnums.length; i++) {
+                        switch (examSummaryEnums[i]) {
+                            case totalCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getTotalCount());
+                                break;
+                            case prepareCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getPrepareCount());
+                                break;
+                            case examCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getExamCount());
+                                break;
+                            case finishCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getFinishCount());
+                                break;
+                            case absentCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getAbsentCount());
+                                break;
+                            case onlineCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getOnlineCount());
+                                break;
+                            case offlineCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getOfflineCount());
+                                break;
+                            case monitorStopCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getMonitorStopCount());
+                                break;
+                            case warningCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getWarningCount());
+                                break;
+                            case warningUnread:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getWarningUnread());
+                                break;
+                            case warningMultipleFaceCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getWarningMultipleFaceCount());
+                                break;
+                            case exceptionCount:
+                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getExceptionCount());
+                                break;
+                            default:
+                                break;
+                        }
+                    }
+                    this.baseMapper.updateExamSummary(examId, examActivityId, s, stringJoinerFieldValue.toString());
+                }
+            }
+        }
+    }
 }

+ 64 - 0
themis-business/src/main/resources/mapper/TEExamSummaryMapper.xml

@@ -2,4 +2,68 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.qmth.themis.business.dao.TEExamSummaryMapper">
 
+    <select id="examSummary" resultType="com.qmth.themis.business.entity.TEExamSummary">
+        select
+            count(1) as totalCount,
+            sum(case when t.status = 'FIRST_PREPARE' then 1 else 0 end) as prepareCount,
+            sum(case when t.client_websocket_status = 'ON_LINE' then 1 else 0 end) as onlineCount,
+            sum(case when t.client_websocket_status = 'OFF_LINE' or t.client_websocket_status is null then 1 else 0 end) as offlineCount,
+            sum(case when t.camera_monitor_status = 'STOP' or t.screen_monitor_status = 'STOP' or t.mobile_first_monitor_status = 'STOP' or t.mobile_second_monitor_status = 'STOP' then 1 else 0 end) as monitorStopCount,
+            sum(case when (t.status = 'ANSWERING' and t.client_websocket_status = 'ON_LINE') or t.status = 'RESUME_PREPARE' or t.status = 'BREAK_OFF' then 1 else 0 end) as examCount,
+            sum(t.warning_count) as warningCount,
+            sum(t.warning_unread) as warningUnread,
+            sum(t.warning_multiple_face_count) as warningMultipleFaceCount,
+            sum(t.exception_count) as exceptionCount,
+            sum(case when (t.status = 'ANSWERING' or t.status = 'PERSISTED') then 1 else 0 end) as finishCount
+        from t_e_exam_student s
+            left join t_oe_exam_record t on t.id=s.current_record_id
+        <where> 1 = 1
+            <if test="examId != null and examId != ''">
+                and s.exam_id = #{examId}
+            </if>
+            <if test="examActivityId != null and examActivityId != ''">
+                and s.exam_activity_id = #{examActivityId}
+            </if>
+            <if test="roomCode != null and roomCode != ''">
+                and s.room_code = #{roomCode}
+            </if>
+        </where>
+    </select>
+
+    <insert id="saveExamSummary">
+        INSERT INTO t_e_exam_summary
+            (${fieldName})
+        VALUES(${fieldValue})
+    </insert>
+
+    <update id="updateExamSummary">
+        update t_e_exam_summary
+        set ${fieldValue}
+        <where> 1 = 1
+            <if test="examId != null and examId != ''">
+                and exam_id = #{examId}
+            </if>
+            <if test="examActivityId != null and examActivityId != ''">
+                and exam_activity_id = #{examActivityId}
+            </if>
+            <if test="roomCode != null and roomCode != ''">
+                and room_code = #{roomCode}
+            </if>
+        </where>
+    </update>
+
+    <select id="selectExamSummaryCount" resultType="java.lang.Integer">
+        select count(1) from t_e_exam_summary
+        <where> 1 = 1
+            <if test="examId != null and examId != ''">
+                and exam_id = #{examId}
+            </if>
+            <if test="examActivityId != null and examActivityId != ''">
+                and exam_activity_id = #{examActivityId}
+            </if>
+            <if test="roomCode != null and roomCode != ''">
+                and room_code = #{roomCode}
+            </if>
+        </where>
+    </select>
 </mapper>

+ 16 - 16
themis-task/src/main/java/com/qmth/themis/task/quartz/ExamSummaryJob.java

@@ -1,14 +1,7 @@
 package com.qmth.themis.task.quartz;
 
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qmth.themis.business.bean.admin.ExamActivityTodayBean;
-import com.qmth.themis.business.constant.SystemConstant;
-import com.qmth.themis.business.entity.TEExamActivity;
-import com.qmth.themis.business.entity.TEExamStudent;
-import com.qmth.themis.business.service.TEExamActivityService;
-import com.qmth.themis.business.service.TEExamStudentService;
+import com.qmth.themis.business.service.TEExamSummaryService;
 import com.qmth.themis.business.service.ThemisCacheService;
-import com.qmth.themis.business.util.RedisUtil;
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
 import org.slf4j.Logger;
@@ -16,14 +9,10 @@ import org.slf4j.LoggerFactory;
 import org.springframework.scheduling.quartz.QuartzJobBean;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
-import org.springframework.util.LinkedMultiValueMap;
 
 import javax.annotation.Resource;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
+import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 /**
  * @Description: 考试统计
@@ -36,12 +25,23 @@ import java.util.stream.Collectors;
 public class ExamSummaryJob extends QuartzJobBean {
     private final static Logger log = LoggerFactory.getLogger(ExamSummaryJob.class);
 
-//    @Resource
-//    ThemisCacheService themisCacheService;
+    @Resource
+    ThemisCacheService themisCacheService;
+
+    @Resource
+    TEExamSummaryService teExamSummaryService;
 
     @Override
     protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
         log.info("ExamSummaryJob进来了,context:{}", context);
-//        themisCacheService.setTodayExamCache();
+        Set<Long> examIdSet = themisCacheService.getTodayExamListCache();
+        if (!CollectionUtils.isEmpty(examIdSet)) {
+            for (Long l : examIdSet) {
+                Map<String, Set<String>> map = themisCacheService.getTodayExamCache(l.toString());
+                map.forEach((k, v) -> {
+                    teExamSummaryService.examSummary(l, Long.parseLong(k), v);
+                });
+            }
+        }
     }
 }