Bladeren bron

考情监考-大屏报表时间趋势修改

wangliang 2 jaren geleden
bovenliggende
commit
f6d41e7297
18 gewijzigde bestanden met toevoegingen van 611 en 263 verwijderingen
  1. 5 1
      themis-admin/src/main/java/com/qmth/themis/admin/api/TIeReportController.java
  2. 48 0
      themis-business/src/main/java/com/qmth/themis/business/bean/result/TimeOnlineDataResult.java
  3. 48 0
      themis-business/src/main/java/com/qmth/themis/business/bean/result/TimeScaleDataResult.java
  4. 2 0
      themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java
  5. 16 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TEExamStudentOnlineLogMapper.java
  6. 22 10
      themis-business/src/main/java/com/qmth/themis/business/dao/TOeExamRecordMapper.java
  7. 107 0
      themis-business/src/main/java/com/qmth/themis/business/entity/TEExamStudentOnlineLog.java
  8. 2 1
      themis-business/src/main/java/com/qmth/themis/business/enums/MqTagEnum.java
  9. 22 0
      themis-business/src/main/java/com/qmth/themis/business/service/TEExamStudentOnlineLogService.java
  10. 13 1
      themis-business/src/main/java/com/qmth/themis/business/service/TIeReportService.java
  11. 43 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamStudentOnlineLogServiceImpl.java
  12. 55 63
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TIeReportServiceImpl.java
  13. 4 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TIpRegionServiceImpl.java
  14. 15 0
      themis-business/src/main/java/com/qmth/themis/business/util/WebsocketUtil.java
  15. 5 0
      themis-business/src/main/resources/mapper/TEExamStudentOnlineLogMapper.xml
  16. 195 186
      themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml
  17. 8 0
      themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java
  18. 1 1
      themis-task/src/main/java/com/qmth/themis/task/start/StartRunning.java

+ 5 - 1
themis-admin/src/main/java/com/qmth/themis/admin/api/TIeReportController.java

@@ -1,10 +1,14 @@
 package com.qmth.themis.admin.api;
 
+import cn.hutool.core.date.DateUtil;
 import com.qmth.themis.business.bean.admin.InvigilateListPatrolReportBean;
+import com.qmth.themis.business.bean.result.TimeScaleDataResult;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.entity.TBUser;
 import com.qmth.themis.business.service.TIeReportService;
+import com.qmth.themis.business.util.JacksonUtil;
 import com.qmth.themis.business.util.ServletUtil;
+import com.qmth.themis.common.contanst.Constants;
 import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.util.Result;
@@ -19,7 +23,7 @@ import org.springframework.web.bind.annotation.RestController;
 import javax.annotation.Resource;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
-import java.util.Objects;
+import java.util.*;
 
 /**
  * 监考报表

+ 48 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/result/TimeOnlineDataResult.java

@@ -0,0 +1,48 @@
+package com.qmth.themis.business.bean.result;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * @Description: 时间尺度数据
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2022/8/22
+ */
+public class TimeOnlineDataResult implements Serializable {
+
+    @ApiModelProperty(value = "日期格式=小时:分")
+    private String hour;
+
+    @ApiModelProperty(name = "在线人数")
+    private Integer onlineCount;
+
+    @ApiModelProperty(value = "离线人数")
+    private Integer offlineCount;
+
+    public String getHour() {
+        return hour;
+    }
+
+    public void setHour(String hour) {
+        this.hour = hour;
+    }
+
+    public Integer getOnlineCount() {
+        return onlineCount;
+    }
+
+    public void setOnlineCount(Integer onlineCount) {
+        this.onlineCount = onlineCount;
+    }
+
+    public Integer getOfflineCount() {
+        return offlineCount;
+    }
+
+    public void setOfflineCount(Integer offlineCount) {
+        this.offlineCount = offlineCount;
+    }
+}

+ 48 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/result/TimeScaleDataResult.java

@@ -0,0 +1,48 @@
+package com.qmth.themis.business.bean.result;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * @Description: 时间尺度数据
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2022/8/22
+ */
+public class TimeScaleDataResult implements Serializable {
+
+    @ApiModelProperty(value = "日期格式=小时:分")
+    private String hour;
+
+    @ApiModelProperty(value = "在线人数")
+    private Integer onlineCount = 0;
+
+    @ApiModelProperty(value = "预警人数")
+    private Integer warnCount = 0;
+
+    public String getHour() {
+        return hour;
+    }
+
+    public void setHour(String hour) {
+        this.hour = hour;
+    }
+
+    public Integer getOnlineCount() {
+        return onlineCount;
+    }
+
+    public void setOnlineCount(Integer onlineCount) {
+        this.onlineCount = onlineCount;
+    }
+
+    public Integer getWarnCount() {
+        return warnCount;
+    }
+
+    public void setWarnCount(Integer warnCount) {
+        this.warnCount = warnCount;
+    }
+}

+ 2 - 0
themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java

@@ -87,6 +87,8 @@ public class SystemConstant {
      */
     public volatile static Searcher SEARCHER = null;
     public static final String SYS_CONFIG_KEY_CHARSETS = "sys.txt.charset";
+    public static final String ONLINE_WARN_INTERVAL = "online.warn.interval";
+    public static final String ONLINE_WARN_SCALESIZE = "online.warn.scaleSize";
     public static final String METHOD = "post";
     public static final int PAGE_SIZE_MIN = 10;
     public static final int PAGE_SIZE_MAX = 1000;

+ 16 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TEExamStudentOnlineLogMapper.java

@@ -0,0 +1,16 @@
+package com.qmth.themis.business.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qmth.themis.business.entity.TEExamStudentOnlineLog;
+
+/**
+ * <p>
+ * 考生上线日志 Mapper 接口
+ * </p>
+ *
+ * @author wangliang
+ * @since 2022-08-22
+ */
+public interface TEExamStudentOnlineLogMapper extends BaseMapper<TEExamStudentOnlineLog> {
+
+}

+ 22 - 10
themis-business/src/main/java/com/qmth/themis/business/dao/TOeExamRecordMapper.java

@@ -3,6 +3,8 @@ package com.qmth.themis.business.dao;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.qmth.themis.business.bean.admin.*;
+import com.qmth.themis.business.bean.result.TimeOnlineDataResult;
+import com.qmth.themis.business.bean.result.TimeScaleDataResult;
 import com.qmth.themis.business.cache.bean.ExamRecordDetailBean;
 import com.qmth.themis.business.entity.TOeExamRecord;
 import org.apache.ibatis.annotations.Mapper;
@@ -308,9 +310,6 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
                                                                            Long userId,
                                                                            Long orgId);
 
-    public List<Map<String, Object>> getDoneCount(@Param("orgId") Long orgId, @Param("examId") Long examId, @Param("activityId") Long activityId,
-                                                  @Param("roomCode") String roomCode, @Param("courseCode") String courseCode);
-
     public List<Map<String, Object>> getDoneCountByDay(@Param("orgId") Long orgId, @Param("examId") Long examId, @Param("activityId") Long activityId,
                                                        @Param("roomCode") String roomCode, @Param("courseCode") String courseCode);
 
@@ -389,13 +388,7 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      */
     public List<ExaminationMonitorMapBean> getMap(@Param("orgId") Long orgId);
 
-    public List<Map<String, Object>> getOrgExamingCount(@Param("orgId") Long orgId);
-
-    public List<Map<String, Object>> getOrgDistribution(@Param("orgId") Long orgId);
-
-    public List<Map<String, Object>> getTypeDistribution(@Param("orgId") Long orgId);
-
-    public List<ExaminationMonitorHourWarnCountBean> getWarnTrend(@Param("orgId") Long orgId, @Param("startTime") Long startTime);
+    public List<TimeScaleDataResult> getWarnTrend(@Param("orgId") Long orgId, @Param("timeData") List<String> timeData, @Param("currentDate") String currentDate, @Param("interval") Integer interval);
 
     public void updateHasAnswerFile(@Param("recordId") Long recordId, @Param("hasAnswerFile") Integer hasAnswerFile);
 
@@ -479,4 +472,23 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     public List<String> examRecordDetailListQuery(@Param("examId") Long examId, @Param("courseCodeList") List<String> courseCodeList, @Param("identityList") List<String> identityList);
+
+    /**
+     * 获取时间尺度
+     *
+     * @param timeSize
+     * @param currentDate
+     * @return
+     */
+    public Map<String, String> getTimeScale(@Param("timeSize") List<Integer> timeSize, @Param("currentDate") String currentDate);
+
+    /**
+     * 获取时间尺度数据
+     *
+     * @param orgId
+     * @param currentDate
+     * @param scaleSize
+     * @return
+     */
+    public List<TimeOnlineDataResult> getTimeOnlineData(@Param("orgId") Long orgId, @Param("currentDate") String currentDate, @Param("scaleSize") Integer scaleSize);
 }

+ 107 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TEExamStudentOnlineLog.java

@@ -0,0 +1,107 @@
+package com.qmth.themis.business.entity;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.themis.business.enums.WebsocketStatusEnum;
+import com.qmth.themis.business.util.UidUtil;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 考生上线日志
+ * </p>
+ *
+ * @author wangliang
+ * @since 2022-08-22
+ */
+@ApiModel(value = "TEExamStudentOnlineLog对象", description = "考生上线日志")
+public class TEExamStudentOnlineLog implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
+    @ApiModelProperty(value = "学生id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long studentId;
+
+    @ApiModelProperty(value = "考生id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examStudentId;
+
+    @ApiModelProperty(value = "考试记录id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examRecordId;
+
+    @ApiModelProperty(value = "类型,ON_LINE:上线,OFF_LINE:下线")
+    private WebsocketStatusEnum type;
+
+    @ApiModelProperty(value = "创建时间")
+    private Long createTime;
+
+    public TEExamStudentOnlineLog(Long studentId, Long examStudentId, Long examRecordId, WebsocketStatusEnum type, Long createTime) {
+        this.id = UidUtil.nextId();
+        this.studentId = studentId;
+        this.examStudentId = examStudentId;
+        this.examRecordId = examRecordId;
+        this.type = type;
+        this.createTime = createTime;
+    }
+
+    public TEExamStudentOnlineLog() {
+
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Long studentId) {
+        this.studentId = studentId;
+    }
+
+    public Long getExamStudentId() {
+        return examStudentId;
+    }
+
+    public void setExamStudentId(Long examStudentId) {
+        this.examStudentId = examStudentId;
+    }
+
+    public Long getExamRecordId() {
+        return examRecordId;
+    }
+
+    public void setExamRecordId(Long examRecordId) {
+        this.examRecordId = examRecordId;
+    }
+
+    public WebsocketStatusEnum getType() {
+        return type;
+    }
+
+    public void setType(WebsocketStatusEnum type) {
+        this.type = type;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+}

+ 2 - 1
themis-business/src/main/java/com/qmth/themis/business/enums/MqTagEnum.java

@@ -55,7 +55,8 @@ public enum MqTagEnum {
     EXAM_START("考试移动端监控开始标签", "考试移动端开始", "broadcast", 47),
     OE_WEBSOCKET_MOBILE_MONITOR_STATUS("通知客户端移动端当前监控状态标签", "通知客户端移动端当前监控状态", "broadcast", 48),
     TENCENT_VIDEO("腾讯云视频回调标签", "腾讯云视频回调", "delay", 49),
-    MARK_CLOUD_SCORE_PUSH("同步云阅卷成绩任务标签", "同步云阅卷成绩任务", "normal", 50);
+    MARK_CLOUD_SCORE_PUSH("同步云阅卷成绩任务标签", "同步云阅卷成绩任务", "normal", 50),
+    ONLINE_LOG("考生上下线标签", "考生上下线", "normal", 51);
 
     private MqTagEnum(String desc, String code, String type, int id) {
         this.desc = desc;

+ 22 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TEExamStudentOnlineLogService.java

@@ -0,0 +1,22 @@
+package com.qmth.themis.business.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.themis.business.entity.TEExamStudentOnlineLog;
+
+/**
+ * <p>
+ * 考生上线日志 服务类
+ * </p>
+ *
+ * @author wangliang
+ * @since 2022-08-22
+ */
+public interface TEExamStudentOnlineLogService extends IService<TEExamStudentOnlineLog> {
+
+    /**
+     * 保存考生上下线日志
+     *
+     * @param teExamStudentOnlineLog
+     */
+    void sendExamStudentOnlineLogSaveMq(TEExamStudentOnlineLog teExamStudentOnlineLog);
+}

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

@@ -2,7 +2,10 @@ package com.qmth.themis.business.service;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.qmth.themis.business.bean.admin.*;
+import com.qmth.themis.business.bean.result.TimeScaleDataResult;
 
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -214,7 +217,7 @@ public interface TIeReportService {
      *
      * @return
      */
-    public List<ExaminationMonitorHourWarnCountBean> warnTrend();
+    public List<TimeScaleDataResult> warnTrend();
 
     /**
      * 考情监控-预警消息
@@ -236,4 +239,13 @@ public interface TIeReportService {
      * @return
      */
     public List<ExaminationMonitorMapBean> map();
+
+    /**
+     * 获取时间尺度
+     *
+     * @param timeSize
+     * @param currentDate
+     * @return
+     */
+    public Map<String, String> getTimeScale(List<Integer> timeSize, String currentDate);
 }

+ 43 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamStudentOnlineLogServiceImpl.java

@@ -0,0 +1,43 @@
+package com.qmth.themis.business.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.themis.business.dao.TEExamStudentOnlineLogMapper;
+import com.qmth.themis.business.dto.MqDto;
+import com.qmth.themis.business.entity.TEExamStudentOnlineLog;
+import com.qmth.themis.business.enums.MqTagEnum;
+import com.qmth.themis.business.service.MqDtoService;
+import com.qmth.themis.business.service.TEExamStudentOnlineLogService;
+import com.qmth.themis.business.util.JacksonUtil;
+import com.qmth.themis.business.util.MqUtil;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * <p>
+ * 考生上线日志 服务实现类
+ * </p>
+ *
+ * @author wangliang
+ * @since 2022-08-22
+ */
+@Service
+public class TEExamStudentOnlineLogServiceImpl extends ServiceImpl<TEExamStudentOnlineLogMapper, TEExamStudentOnlineLog> implements TEExamStudentOnlineLogService {
+
+    @Resource
+    MqUtil mqUtil;
+
+    @Resource
+    MqDtoService mqDtoService;
+
+    /**
+     * 保存考生上下线日志
+     *
+     * @param teExamStudentOnlineLog
+     */
+    @Override
+    public void sendExamStudentOnlineLogSaveMq(TEExamStudentOnlineLog teExamStudentOnlineLog) {
+        MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.ONLINE_LOG.name(), JacksonUtil.parseJson(teExamStudentOnlineLog), MqTagEnum.ONLINE_LOG, String.valueOf(teExamStudentOnlineLog.getExamRecordId()), String.valueOf(teExamStudentOnlineLog.getExamRecordId()));
+        mqDtoService.assembleSendOneWayMsg(mqDto);
+    }
+}

+ 55 - 63
themis-business/src/main/java/com/qmth/themis/business/service/impl/TIeReportServiceImpl.java

@@ -1,8 +1,11 @@
 package com.qmth.themis.business.service.impl;
 
+import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.themis.business.bean.admin.*;
+import com.qmth.themis.business.bean.result.TimeOnlineDataResult;
+import com.qmth.themis.business.bean.result.TimeScaleDataResult;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.dao.*;
 import com.qmth.themis.business.entity.TBOrg;
@@ -11,15 +14,14 @@ import com.qmth.themis.business.entity.TEExamActivity;
 import com.qmth.themis.business.enums.InvigilateMonitorStatusEnum;
 import com.qmth.themis.business.service.*;
 import com.qmth.themis.business.util.ServletUtil;
-import org.apache.commons.lang3.time.DateUtils;
+import com.qmth.themis.common.contanst.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
-import java.text.SimpleDateFormat;
 import java.util.*;
-import java.util.stream.Collectors;
 
 /**
  * @Description: 报表数据
@@ -371,11 +373,6 @@ public class TIeReportServiceImpl implements TIeReportService {
     @Override
     public List<ExaminationMonitorWarnDistributionBean> warnDistribution() {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
-//        ExaminationMonitorWarnDistributionBean ret = new ExaminationMonitorWarnDistributionBean();
-//        ret.setOrgDistribution(tOeExamRecordMapper.getOrgDistribution(tbUser.getOrgId()));
-//        List<Map<String, Object>> typeList = tOeExamRecordMapper.getTypeDistribution(tbUser.getOrgId());
-//        ret.setTypeDistribution(typeList);
-//        return ret;
         return tOeExamRecordMapper.getWarnDistribution(tbUser.getOrgId());
     }
 
@@ -383,73 +380,56 @@ public class TIeReportServiceImpl implements TIeReportService {
      * 考情监控-预警时间趋势
      */
     @Override
-    public List<ExaminationMonitorHourWarnCountBean> warnTrend() {
+    public List<TimeScaleDataResult> warnTrend() {
+        int scaleSize = 30, interval = 1;
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
-        List<ExaminationMonitorHourWarnCountBean> ret = new ArrayList<ExaminationMonitorHourWarnCountBean>();
-        SimpleDateFormat sd = new SimpleDateFormat("HH");
-        Date start = null;
-        Date now = new Date();
-        for (int i = 11; i >= 0; i--) {
-            ExaminationMonitorHourWarnCountBean b = new ExaminationMonitorHourWarnCountBean();
-            Date before = DateUtils.addHours(now, -i);
-            b.setHour(sd.format(before));
-            b.setCount(0L);
-            ret.add(b);
-            if (i == 11) {
-                start = before;
+        List<Integer> timeSize = new ArrayList<>(scaleSize);
+        for (int i = interval; i <= scaleSize * interval; i = i + interval) {
+            timeSize.add(i);
+        }
+        String currentDate = DateUtil.format(new Date(), Constants.DEFAULT_DATE_PATTERN);
+        Map<String, String> map = this.getTimeScale(timeSize, currentDate);
+        List<TimeScaleDataResult> timeScaleDataResultList = tOeExamRecordMapper.getWarnTrend(tbUser.getOrgId(), new ArrayList<>(map.values()), currentDate, interval);
+        List<TimeOnlineDataResult> timeOnlineDataResultList = tOeExamRecordMapper.getTimeOnlineData(tbUser.getOrgId(), currentDate, scaleSize);
+        Map<String, TimeOnlineDataResult> onlineMap = null;
+        if (!CollectionUtils.isEmpty(timeOnlineDataResultList)) {
+            onlineMap = new LinkedHashMap<>();
+            for (TimeOnlineDataResult t : timeOnlineDataResultList) {
+                if (!onlineMap.containsKey(t.getHour())) {
+                    onlineMap.put(t.getHour(), t);
+                } else {
+                    TimeOnlineDataResult temp = onlineMap.get(t.getHour());
+                    temp.setOnlineCount(temp.getOnlineCount() + t.getOnlineCount());
+                    temp.setOfflineCount(temp.getOfflineCount() + t.getOfflineCount());
+                }
             }
         }
-        start = DateUtils.setMinutes(start, 0);
-        start = DateUtils.setSeconds(start, 0);
-        start = DateUtils.setMilliseconds(start, 0);
-        List<ExaminationMonitorHourWarnCountBean> list = tOeExamRecordMapper.getWarnTrend(tbUser.getOrgId(), start.getTime());
-        if (list != null && list.size() > 0) {
-            Map<String, Long> map = list.stream().collect(Collectors.toMap(ExaminationMonitorHourWarnCountBean::getHour,
-                    ExaminationMonitorHourWarnCountBean::getCount, (key1, key2) -> key2));
-            for (ExaminationMonitorHourWarnCountBean b : ret) {
-                Long c = map.get(b.getHour());
-                if (c != null) {
-                    b.setCount(c);
+        int beforeOnlineCount = 0;
+        TimeScaleDataResult beforeT = null;
+        if (!CollectionUtils.isEmpty(timeScaleDataResultList) && !CollectionUtils.isEmpty(onlineMap)) {
+            for (int i = 0; i < timeScaleDataResultList.size(); i++) {
+                TimeScaleDataResult t = timeScaleDataResultList.get(i);
+                if (onlineMap.containsKey(t.getHour())) {
+                    if (i > 0) {
+                        beforeT = timeScaleDataResultList.get(i - 1);
+                        beforeOnlineCount = beforeT.getOnlineCount();
+                    }
+                    t.setOnlineCount(onlineMap.get(t.getHour()).getOnlineCount() + beforeOnlineCount - onlineMap.get(t.getHour()).getOfflineCount());
+                } else {
+                    if (i > 0) {
+                        beforeT = timeScaleDataResultList.get(i - 1);
+                        t.setOnlineCount(beforeT.getOnlineCount());
+                    }
                 }
-                b.setHour(b.getHour() + ":00");
             }
         }
-        return ret;
+        return timeScaleDataResultList;
     }
 
     @Override
     public List<WarningNotifyBean> warnMsg() {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         return invigilateWarnInfoMapper.findLastMsg(6, tbUser.getOrgId());
-//        List<ExaminationMonitorWarnMsgBean> ret = new ArrayList<ExaminationMonitorWarnMsgBean>();
-//        List<WarningNotifyBean> list = invigilateWarnInfoMapper.findLastMsg(6, tbUser.getOrgId());
-//        if (list != null && list.size() > 0) {
-//            for (WarningNotifyBean b : list) {
-//                ExaminationMonitorWarnMsgBean bean = new ExaminationMonitorWarnMsgBean();
-//                bean.setTime(b.getCreateTime());
-//                StringBuilder sb = new StringBuilder();
-//                sb.append(b.getName()).append(" (证件号:").append(b.getIdentity()).append(") ").append(b.getInfo());
-//                List<Map<String, String>> users = examInvigilateUserMapper.getInvigilateUsers(b.getExamId(), b.getRoomCode());
-//                if (users != null && users.size() > 0) {
-//                    StringBuilder usersb = new StringBuilder();
-//                    for (Map<String, String> map : users) {
-//                        if (map != null) {
-//                            String lname = map.get("loginName");
-//                            String name = map.get(SystemConstant.NAME);
-//                            if (StringUtils.isNotBlank(lname) && StringUtils.isNotBlank(name)) {
-//                                usersb.append(lname).append("(账号:").append(name).append(") ");
-//                            }
-//                        }
-//                    }
-//                    if (usersb.length() > 0) {
-//                        sb.append(",系统已提示").append(usersb).append("进行人工干预");
-//                    }
-//                }
-//                bean.setContent(sb.toString());
-//                ret.add(bean);
-//            }
-//        }
-//        return ret;
     }
 
     /**
@@ -473,4 +453,16 @@ public class TIeReportServiceImpl implements TIeReportService {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         return tOeExamRecordMapper.getMap(tbUser.getOrgId());
     }
+
+    /**
+     * 获取时间尺度
+     *
+     * @param timeSize
+     * @param currentDate
+     * @return
+     */
+    @Override
+    public Map<String, String> getTimeScale(List<Integer> timeSize, String currentDate) {
+        return tOeExamRecordMapper.getTimeScale(timeSize, currentDate);
+    }
 }

+ 4 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TIpRegionServiceImpl.java

@@ -40,6 +40,10 @@ public class TIpRegionServiceImpl extends ServiceImpl<TIpRegionMapper, TIpRegion
                 String region = IpUtil.getIpInfo(SystemConstant.SEARCHER, ip);
                 if (Objects.nonNull(region)) {
                     String[] strs = region.split("\\|");
+                    if (strs.length != 5) {
+                        log.error("ip region error:{}", region);
+                        throw new BusinessException("ip信息格式错误");
+                    }
                     QueryWrapper<TIpRegion> tIpRegionQueryWrapper = new QueryWrapper<>();
                     tIpRegionQueryWrapper.lambda().eq(TIpRegion::getExamRecordId, examRecordId);
                     TIpRegion tIpRegion = this.getOne(tIpRegionQueryWrapper);

+ 15 - 0
themis-business/src/main/java/com/qmth/themis/business/util/WebsocketUtil.java

@@ -1,9 +1,13 @@
 package com.qmth.themis.business.util;
 
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
+import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.constant.SystemConstant;
+import com.qmth.themis.business.entity.TEExamStudentOnlineLog;
 import com.qmth.themis.business.enums.WebsocketStatusEnum;
+import com.qmth.themis.business.service.TEExamStudentOnlineLogService;
+import com.qmth.themis.business.service.TEExamStudentService;
 import com.qmth.themis.business.service.TOeExamRecordService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -65,6 +69,17 @@ public class WebsocketUtil {
         ExamRecordCacheUtil.setClientLastSyncTime(recordId, clientLastSyncTime);
         TOeExamRecordService tOeExamRecordService = SpringContextHolder.getBean(TOeExamRecordService.class);
         tOeExamRecordService.sendExamRecordDataSaveMq(recordId, timestamp);
+
+        Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
+        if (Objects.nonNull(examStudentId)) {
+            TEExamStudentService teExamStudentService = SpringContextHolder.getBean(TEExamStudentService.class);
+            ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
+
+            if (Objects.nonNull(examStudentCacheBean)) {
+                TEExamStudentOnlineLogService teExamStudentOnlineLogService = SpringContextHolder.getBean(TEExamStudentOnlineLogService.class);
+                teExamStudentOnlineLogService.sendExamStudentOnlineLogSaveMq(new TEExamStudentOnlineLog(examStudentCacheBean.getStudentId(), examStudentId, recordId, websocketStatusEnum, timestamp));
+            }
+        }
     }
 
     /**

+ 5 - 0
themis-business/src/main/resources/mapper/TEExamStudentOnlineLogMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!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.TEExamStudentOnlineLogMapper">
+
+</mapper>

+ 195 - 186
themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml

@@ -877,28 +877,6 @@
         <include refid="invigilatePageListHistorySql"/>
     </select>
 
-    <select id="getDoneCount" resultType="java.util.Map">
-        select f.exam_activity_id
-        activityId,count(distinct(f.exam_student_id)) cc from t_oe_exam_record
-        f
-        left join t_e_exam_student t on f.exam_student_id=t.id
-        left join t_e_student h on t.student_id=h.id
-        where f.exam_id = #{examId}
-        <if test="orgId != null and orgId != ''">
-            and h.org_id=#{orgId}
-        </if>
-        <if test="activityId != null and activityId != ''">
-            and f.exam_activity_id = #{activityId}
-        </if>
-        <if test="roomCode != null and roomCode != ''">
-            and t.room_code =#{roomCode}
-        </if>
-        <if test="courseCode != null and courseCode != ''">
-            and t.course_code = #{courseCode}
-        </if>
-        group by f.exam_activity_id
-    </select>
-
     <select id="getDoneCountByDay" resultType="java.util.Map">
         select
         FROM_UNIXTIME(f.first_prepare_time / 1000,'%Y-%m-%d') AS day,
@@ -1061,194 +1039,132 @@
         AND t.id IS NOT NULL
     </select>
 
-    <select id="getWarnDistribution" resultType="com.qmth.themis.business.bean.admin.ExaminationMonitorWarnDistributionBean">
+    <select id="getWarnDistribution"
+            resultType="com.qmth.themis.business.bean.admin.ExaminationMonitorWarnDistributionBean">
         select
-            tiiwi.info as type,
-            count(tiiwi.exam_record_id) as warnCount
+        tiiwi.info as type,
+        count(tiiwi.exam_record_id) as warnCount
         from
-            t_ie_invigilate_warn_info tiiwi
-            join t_oe_exam_record toer on tiiwi.exam_record_id = toer.id
-            join t_e_exam tee on toer.exam_id = tee.id
+        t_ie_invigilate_warn_info tiiwi
+        join t_oe_exam_record toer on tiiwi.exam_record_id = toer.id
+        join t_e_exam tee on toer.exam_id = tee.id
         WHERE 1 = 1
-            <if test="orgId != null and orgId != ''">
-                and tee.org_id = #{orgId}
-            </if>
-            and (toer.STATUS = 'FIRST_PREPARE' or toer.STATUS = 'ANSWERING'
-            or toer.STATUS = 'BREAK_OFF' or toer.STATUS = 'RESUME_PREPARE')
+        <if test="orgId != null and orgId != ''">
+            and tee.org_id = #{orgId}
+        </if>
+        and (toer.STATUS = 'FIRST_PREPARE' or toer.STATUS = 'ANSWERING'
+        or toer.STATUS = 'BREAK_OFF' or toer.STATUS = 'RESUME_PREPARE')
         group by
-            tiiwi.`info`
+        tiiwi.`info`
     </select>
 
-    <select id="getWarnRegionDistribution" resultType="com.qmth.themis.business.bean.admin.ExaminationMonitorWarnRegionDistributionBean">
+    <select id="getWarnRegionDistribution"
+            resultType="com.qmth.themis.business.bean.admin.ExaminationMonitorWarnRegionDistributionBean">
         select
-            tir.country,
-            tir.province,
-            count(tiiwi.exam_record_id) as warnCount
+        tir.country,
+        tir.province,
+        count(tiiwi.exam_record_id) as warnCount
         from
-            t_ip_region tir
-                join t_oe_exam_record toer on
-                tir.exam_record_id = toer.id
-                left join t_ie_invigilate_warn_info tiiwi on
-                tiiwi.exam_record_id = toer.id
-                join t_e_exam tee on toer.exam_id = tee.id
+        t_ip_region tir
+        join t_oe_exam_record toer on
+        tir.exam_record_id = toer.id
+        left join t_ie_invigilate_warn_info tiiwi on
+        tiiwi.exam_record_id = toer.id
+        join t_e_exam tee on toer.exam_id = tee.id
         WHERE 1 = 1
-            <if test="orgId != null and orgId != ''">
-                and tee.org_id = #{orgId}
-            </if>
-            and (toer.STATUS = 'FIRST_PREPARE' or toer.STATUS = 'ANSWERING'
-            or toer.STATUS = 'BREAK_OFF' or toer.STATUS = 'RESUME_PREPARE')
+        <if test="orgId != null and orgId != ''">
+            and tee.org_id = #{orgId}
+        </if>
+        and (toer.STATUS = 'FIRST_PREPARE' or toer.STATUS = 'ANSWERING'
+        or toer.STATUS = 'BREAK_OFF' or toer.STATUS = 'RESUME_PREPARE')
         group by
-            tir.country,
-            tir.province;
+        tir.country,
+        tir.province;
     </select>
 
     <select id="getMap" resultType="com.qmth.themis.business.bean.admin.ExaminationMonitorMapBean">
         select
-            t.country,
-            t.province,
-            sum(t.onlineCount) as onlineCount,
-            sum(t.warnCount) as warnCount
+        t.country,
+        t.province,
+        sum(t.onlineCount) as onlineCount,
+        sum(t.warnCount) as warnCount
         from
-            (
-                select
-                    tir.country,
-                    tir.province,
-                    count(toer.id) as onlineCount,
-                    0 as warnCount
-                from
-                    t_ip_region tir
-                        join t_oe_exam_record toer on
-                        tir.exam_record_id = toer.id
-                        join t_e_exam tee on
-                        toer.exam_id = tee.id
-                WHERE 1 = 1
-                    <if test="orgId != null and orgId != ''">
-                        and tee.org_id = #{orgId}
-                    </if>
-                  and toer.client_websocket_status = 'ON_LINE'
-                  and (toer.STATUS = 'FIRST_PREPARE'
-                    or toer.STATUS = 'ANSWERING'
-                    or toer.STATUS = 'BREAK_OFF'
-                    or toer.STATUS = 'RESUME_PREPARE')
-                group by
-                    tir.country,
-                    tir.province
-                union all
-                select
-                    tir.country,
-                    tir.province,
-                    0 as onlineCount,
-                    count(tiiwi.exam_record_id) as warnCount
-                from
-                    t_ip_region tir
-                        join t_oe_exam_record toer on
-                        tir.exam_record_id = toer.id
-                        left join t_ie_invigilate_warn_info tiiwi on
-                        tiiwi.exam_record_id = tir.exam_record_id
-                        join t_e_exam tee on
-                        toer.exam_id = tee.id
-                WHERE 1 = 1
-                <if test="orgId != null and orgId != ''">
-                    and tee.org_id = #{orgId}
-                </if>
-                  and (toer.STATUS = 'FIRST_PREPARE'
-                    or toer.STATUS = 'ANSWERING'
-                    or toer.STATUS = 'BREAK_OFF'
-                    or toer.STATUS = 'RESUME_PREPARE')
-                group by
-                    tir.country,
-                    tir.province) t
-        group by
-            t.country,
-            t.province
-    </select>
-
-    <select id="getOrgExamingCount" resultType="java.util.Map">
-        SELECT
-        o. NAME orgName,
-        tem.cc count
-        FROM
-        (
-        SELECT
-        h.org_id orgId,
-        count(DISTINCT(h.id)) cc
-        FROM
-        t_oe_exam_record f
-        LEFT JOIN t_e_exam_student t ON f.exam_student_id = t.id
-        LEFT JOIN t_e_student h ON t.student_id = h.id
-        WHERE 1 = 1
-        <if test="orgId != null and orgId != ''">
-            and h.org_id=#{orgId}
-        </if>
-        and (f.STATUS = 'FIRST_PREPARE' or f.STATUS = 'ANSWERING'
-        or f.STATUS = 'BREAK_OFF' or f.STATUS = 'RESUME_PREPARE')
-        AND f.client_websocket_status='ON_LINE'
-        GROUP BY
-        h.org_id
-        ) tem
-        LEFT JOIN t_b_org o ON o.id = tem.orgId
-    </select>
-
-    <select id="getOrgDistribution" resultType="java.util.Map">
-        SELECT
-        o. NAME orgName,
-        tem.cc count
-        FROM
         (
-        SELECT
-        h.org_id orgId,
-        count(DISTINCT(w.id)) cc
-        FROM
-        t_oe_exam_record f
-        LEFT JOIN t_ie_invigilate_warn_info w ON f.id = w.exam_record_id
-        LEFT JOIN t_e_exam_student t ON f.exam_student_id = t.id
-        LEFT JOIN t_e_student h ON t.student_id = h.id
+        select
+        tir.country,
+        tir.province,
+        count(toer.id) as onlineCount,
+        0 as warnCount
+        from
+        t_ip_region tir
+        join t_oe_exam_record toer on
+        tir.exam_record_id = toer.id
+        join t_e_exam tee on
+        toer.exam_id = tee.id
         WHERE 1 = 1
         <if test="orgId != null and orgId != ''">
-            and h.org_id=#{orgId}
+            and tee.org_id = #{orgId}
         </if>
-        and (f.STATUS = 'FIRST_PREPARE' or f.STATUS = 'ANSWERING'
-        or f.STATUS = 'BREAK_OFF' or f.STATUS = 'RESUME_PREPARE')
-        AND w.id IS NOT NULL
-        AND w.type!='NONE'
-        GROUP BY
-        h.org_id
-        ) tem
-        LEFT JOIN t_b_org o ON o.id = tem.orgId
-    </select>
-
-    <select id="getTypeDistribution" resultType="java.util.Map">
-        SELECT
-        substring(w.info,instr(w.info,"【") + 1,instr(w.info,"】") - 2) as type,
-        count(DISTINCT(w.id)) count
-        FROM
-        t_oe_exam_record f
-        LEFT JOIN t_ie_invigilate_warn_info w ON f.id = w.exam_record_id
-        left join t_e_exam h on f.exam_id=h.id
+        and toer.client_websocket_status = 'ON_LINE'
+        and (toer.STATUS = 'FIRST_PREPARE'
+        or toer.STATUS = 'ANSWERING'
+        or toer.STATUS = 'BREAK_OFF'
+        or toer.STATUS = 'RESUME_PREPARE')
+        group by
+        tir.country,
+        tir.province
+        union all
+        select
+        tir.country,
+        tir.province,
+        0 as onlineCount,
+        count(tiiwi.exam_record_id) as warnCount
+        from
+        t_ip_region tir
+        join t_oe_exam_record toer on
+        tir.exam_record_id = toer.id
+        left join t_ie_invigilate_warn_info tiiwi on
+        tiiwi.exam_record_id = tir.exam_record_id
+        join t_e_exam tee on
+        toer.exam_id = tee.id
         WHERE 1 = 1
         <if test="orgId != null and orgId != ''">
-            and h.org_id=#{orgId}
+            and tee.org_id = #{orgId}
         </if>
-        and (f.STATUS = 'FIRST_PREPARE' or f.STATUS = 'ANSWERING'
-        or f.STATUS = 'BREAK_OFF' or f.STATUS = 'RESUME_PREPARE')
-        AND w.id IS NOT NULL
-        AND w.type!='NONE'
-        GROUP BY
-        w.info
+        and (toer.STATUS = 'FIRST_PREPARE'
+        or toer.STATUS = 'ANSWERING'
+        or toer.STATUS = 'BREAK_OFF'
+        or toer.STATUS = 'RESUME_PREPARE')
+        group by
+        tir.country,
+        tir.province) t
+        group by
+        t.country,
+        t.province
     </select>
 
-    <select id="getWarnTrend" resultType="com.qmth.themis.business.bean.admin.ExaminationMonitorHourWarnCountBean">
-        SELECT
-        FROM_UNIXTIME(w.create_time / 1000,'%H') hour,
-        count(1) count
-        FROM t_ie_invigilate_warn_info w
-        left join t_e_exam h on w.exam_id=h.id
-        WHERE w.type!='NONE' and w.create_time&gt;=#{startTime}
-        <if test="orgId != null and orgId != ''">
-            and h.org_id=#{orgId}
-        </if>
-        GROUP BY
-        FROM_UNIXTIME(w.create_time / 1000,'%H')
+    <select id="getWarnTrend" resultType="com.qmth.themis.business.bean.result.TimeScaleDataResult">
+        select
+        t.hour,
+        sum(t.warnCount) as warnCount
+        from
+        (
+        <foreach collection="timeData" item="item" index="index">
+            <choose>
+                <when test="index == 0">
+                    <include refid="getWarnTrendCommon" />
+                </when>
+                <otherwise>
+                    union all
+                    <include refid="getWarnTrendCommon" />
+                </otherwise>
+            </choose>
+        </foreach>
+        ) t
+        group by
+        t.hour
+        order by
+        t.hour
     </select>
 
     <update id="updateHasAnswerFile">
@@ -1648,4 +1564,97 @@
         </where>
         order by tees.id
     </select>
+
+    <select id="getTimeScale" resultType="java.util.Map">
+        select
+        <foreach collection="timeSize" item="item" index="index" separator=",">
+            DATE_FORMAT(date_sub(#{currentDate}, interval #{item} minute),'%Y-%m-%d %H:%i:00') as '${item}'
+        </foreach>
+    </select>
+
+    <sql id="getWarnTrendCommon">
+        <!--select
+            t.hour,
+            count(distinct t.examRecordId) as onlineCount,
+            0 as warnCount
+        from
+            (
+                select
+                    DATE_FORMAT(#{item}, '%H:%i') as hour,
+                    teesol.exam_record_id as examRecordId,
+                    DATE_FORMAT(FROM_UNIXTIME(teesol.create_time / 1000), '%Y-%m-%d %H:%i:00') as createTime
+                from
+                    t_e_exam_student_online_log teesol
+                    join t_oe_exam_record toer on toer.id = teesol.exam_record_id
+                    join t_e_exam tee on toer.exam_id = tee.id
+                    WHERE 1 = 1
+                    <if test="orgId != null and orgId != ''">
+                        and tee.org_id = #{orgId}
+                    </if>
+                  and (teesol.create_time <![CDATA[ >= ]]> unix_timestamp(date_sub(#{currentDate}, interval 30 minute)) * 1000
+                  and teesol.create_time <![CDATA[ <= ]]> unix_timestamp(#{currentDate}) * 1000)) t
+        where
+            (t.createTime <![CDATA[ >= ]]> #{item} and t.createTime <![CDATA[ < ]]> date_add(#{item}, interval #{interval} minute))
+        union all
+          -->
+            select
+                t.hour,
+                <!--0 as onlineCount,-->
+                count(t.examRecordId) as warnCount
+                from
+                (
+                select
+                DATE_FORMAT(#{item}, '%H:%i') as hour,
+                tiiwi.exam_record_id as examRecordId,
+                DATE_FORMAT(FROM_UNIXTIME(tiiwi.create_time / 1000), '%Y-%m-%d %H:%i:00') as createTime
+                from
+                t_oe_exam_record toer
+                join t_ie_invigilate_warn_info tiiwi on
+                    tiiwi.exam_record_id = toer.id
+                join t_e_exam tee on toer.exam_id = tee.id
+                WHERE 1 = 1
+                <if test="orgId != null and orgId != ''">
+                    and tee.org_id = #{orgId}
+                </if>
+                and (tiiwi.create_time <![CDATA[ >= ]]> unix_timestamp(date_sub(#{currentDate}, interval 30 minute)) * 1000
+                and tiiwi.create_time <![CDATA[ <= ]]> unix_timestamp(#{currentDate}) * 1000)) t
+                where
+                (t.createTime <![CDATA[ >= ]]> #{item} and t.createTime <![CDATA[ < ]]> date_add(#{item}, interval #{interval} minute))
+    </sql>
+
+    <select id="getTimeOnlineData" resultType="com.qmth.themis.business.bean.result.TimeOnlineDataResult">
+        select t.* from
+        (
+        select
+        DATE_FORMAT(FROM_UNIXTIME(teesol.create_time / 1000), '%H:%i') as hour,
+        count(distinct teesol.exam_record_id) as onlineCount,
+        0 as offlineCount
+        from
+        t_e_exam_student_online_log teesol
+        join t_oe_exam_record toer on toer.id = teesol.exam_record_id
+        join t_e_exam tee on toer.exam_id = tee.id
+        where 1 = 1
+        <if test="orgId != null and orgId != ''">
+            and tee.org_id = #{orgId}
+        </if>
+        and (teesol.create_time <![CDATA[ >= ]]> unix_timestamp(date_sub(#{currentDate}, interval #{scaleSize} minute)) * 1000
+        and teesol.create_time <![CDATA[ <= ]]> unix_timestamp(#{currentDate}) * 1000)
+        and teesol.`type` = 'ON_LINE' group by teesol.create_time
+        union all
+        select
+        DATE_FORMAT(FROM_UNIXTIME(teesol.create_time / 1000), '%H:%i') as hour,
+        0 as onlineCount,
+        count(distinct teesol.exam_record_id) as offlineCount
+        from
+        t_e_exam_student_online_log teesol
+        join t_oe_exam_record toer on toer.id = teesol.exam_record_id
+        join t_e_exam tee on toer.exam_id = tee.id
+        where 1 = 1
+        <if test="orgId != null and orgId != ''">
+            and tee.org_id = #{orgId}
+        </if>
+        and (teesol.create_time <![CDATA[ >= ]]> unix_timestamp(date_sub(#{currentDate}, interval #{scaleSize} minute)) * 1000
+        and teesol.create_time <![CDATA[ <= ]]> unix_timestamp(#{currentDate}) * 1000)
+        and teesol.`type` = 'OFF_LINE' group by teesol.create_time) t order by t.hour;
+    </select>
 </mapper>

+ 8 - 0
themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java

@@ -127,6 +127,9 @@ public class MqLogicServiceImpl implements MqLogicService {
     @Resource
     TIpRegionService tIpRegionService;
 
+    @Resource
+    TEExamStudentOnlineLogService teExamStudentOnlineLogService;
+
     /**
      * mq最大重试次数逻辑
      *
@@ -823,6 +826,11 @@ public class MqLogicServiceImpl implements MqLogicService {
                         .eq(TEExamStudentLog::getObjId, breakId);
                 teExamStudentLogService.update(teExamStudentLogUpdateWrapper);
             }
+        } else if (Objects.equals(MqTagEnum.ONLINE_LOG.name(), tag)) {//考生上下线
+            TEExamStudentOnlineLog teExamStudentOnlineLog = JacksonUtil.readJson(String.valueOf(mqDto.getBody()), TEExamStudentOnlineLog.class);
+            if (Objects.nonNull(teExamStudentOnlineLog)) {
+                teExamStudentOnlineLogService.save(teExamStudentOnlineLog);
+            }
         }
         tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
     }

+ 1 - 1
themis-task/src/main/java/com/qmth/themis/task/start/StartRunning.java

@@ -83,7 +83,7 @@ public class StartRunning implements CommandLineRunner {
         /**
          * log
          */
-        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.LOG_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXCEPTION_LOG.name() + "||" + MqTagEnum.MONITOR_LOG.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(LogConcurrentlyImpl.class));
+        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.LOG_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXCEPTION_LOG.name() + "||" + MqTagEnum.MONITOR_LOG.name() + "||" + MqTagEnum.ONLINE_LOG.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(LogConcurrentlyImpl.class));
         /**
          * task
          */