Bläddra i källkod

Merge branch 'dev'

# Conflicts:
#	themis-backend/src/main/java/com/qmth/themis/backend/api/TEExamController.java
#	themis-exam/src/main/java/com/qmth/themis/exam/api/TEStudentController.java
wangliang 4 år sedan
förälder
incheckning
2d0e355b8a
19 ändrade filer med 309 tillägg och 128 borttagningar
  1. 3 3
      themis-backend/src/main/java/com/qmth/themis/backend/api/TEExamController.java
  2. 17 2
      themis-backend/src/main/java/com/qmth/themis/backend/api/TIeInvigilateController.java
  3. 11 0
      themis-business/src/main/java/com/qmth/themis/business/bean/backend/InvigilateListDetailBean.java
  4. 16 3
      themis-business/src/main/java/com/qmth/themis/business/entity/TEExamStudentLog.java
  5. 20 13
      themis-business/src/main/java/com/qmth/themis/business/enums/ExamRecordStatusEnum.java
  6. 18 11
      themis-business/src/main/java/com/qmth/themis/business/enums/ExamTypeEnum.java
  7. 15 8
      themis-business/src/main/java/com/qmth/themis/business/enums/ExceptionEnum.java
  8. 23 10
      themis-business/src/main/java/com/qmth/themis/business/enums/LivenessTypeEnum.java
  9. 20 9
      themis-business/src/main/java/com/qmth/themis/business/enums/SystemOperationEnum.java
  10. 26 19
      themis-business/src/main/java/com/qmth/themis/business/enums/VerifyExceptionEnum.java
  11. 13 6
      themis-business/src/main/java/com/qmth/themis/business/enums/WarningLevelEnum.java
  12. 8 0
      themis-business/src/main/java/com/qmth/themis/business/service/TEExamBreachLogService.java
  13. 68 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamBreachLogServiceImpl.java
  14. 11 7
      themis-business/src/main/java/com/qmth/themis/business/service/impl/WarningServiceImpl.java
  15. 1 0
      themis-business/src/main/resources/db/init.sql
  16. 11 12
      themis-business/src/main/resources/mapper/TEExamStudentLogMapper.xml
  17. 6 6
      themis-exam/src/main/java/com/qmth/themis/exam/api/TEStudentController.java
  18. 3 3
      themis-exam/src/main/java/com/qmth/themis/exam/listener/service/impl/MqOeLogicServiceImpl.java
  19. 19 16
      themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java

+ 3 - 3
themis-backend/src/main/java/com/qmth/themis/backend/api/TEExamController.java

@@ -224,9 +224,9 @@ public class TEExamController {
         AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.userOauth + "::" + tbUser.getId());
         Long uId = null;
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INSPECTION.name())) {
-        	uId = null;
-        }else {
-        	uId=userId;
+            uId = null;
+        } else {
+            uId = userId;
         }
         return ResultUtil.ok(teExamService.examQuery(new Page<>(pageNumber, pageSize), uId, id, code, name, mode, enable, tbUser.getOrgId()));
     }

+ 17 - 2
themis-backend/src/main/java/com/qmth/themis/backend/api/TIeInvigilateController.java

@@ -32,6 +32,7 @@ import com.qmth.themis.common.util.ResultUtil;
 import io.swagger.annotations.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
@@ -276,7 +277,10 @@ public class TIeInvigilateController {
         //考生轨迹
         QueryWrapper<TEExamStudentLog> teExamStudentLogQueryWrapper = new QueryWrapper<>();
         teExamStudentLogQueryWrapper.lambda().eq(TEExamStudentLog::getExamRecordId, examRecordId)
-                .eq(TEExamStudentLog::getExamStudentId, examStudentId);
+                .eq(TEExamStudentLog::getExamStudentId, examStudentId)
+                .ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_HANDLE.name())
+                .ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_REVOKE.name());
+//                .and(w -> w.ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_HANDLE.name()).or().ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_REVOKE.name()));
         List<TEExamStudentLog> teExamStudentLogList = teExamStudentLogService.list(teExamStudentLogQueryWrapper);
         invigilateListDetailBean.setExamStudentLogList(teExamStudentLogList);
 
@@ -306,6 +310,7 @@ public class TIeInvigilateController {
         tIeExamInvigilateNoticeUpdateWrapper.lambda().set(TIeInvigilateWarnInfo::getApproveStatus, 1)
                 .eq(TIeInvigilateWarnInfo::getExamRecordId, examRecordId);
         tIeInvigilateWarnInfoService.update(tIeExamInvigilateNoticeUpdateWrapper);
+        invigilateListDetailBean.setMonitorVideoSource(examCacheBean.getMonitorVideoSource());
         return ResultUtil.ok(invigilateListDetailBean);
     }
 
@@ -432,6 +437,7 @@ public class TIeInvigilateController {
     @ApiOperation(value = "违纪处理接口")
     @RequestMapping(value = "/breach", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
+    @Transactional
     public Result breach(@ApiJsonObject(name = "invigilateBreach", value = {
             @ApiJsonProperty(key = "examRecordId", type = "long", example = "1", description = "考试记录id", required = true),
             @ApiJsonProperty(key = "type", description = "违规类型", required = true),
@@ -482,7 +488,8 @@ public class TIeInvigilateController {
             } else {//撤销违纪
                 BreachCancelTypeEnum type = BreachCancelTypeEnum.valueOf(String.valueOf(mapParameter.get("type")));
                 QueryWrapper<TEExamBreachLog> teExamBreachLogQueryWrapper = new QueryWrapper<>();
-                teExamBreachLogQueryWrapper.lambda().in(TEExamBreachLog::getExamRecordId, recordIdList);
+                teExamBreachLogQueryWrapper.lambda().in(TEExamBreachLog::getExamRecordId, recordIdList)
+                        .eq(TEExamBreachLog::getStatus, 0);
                 teExamBreachLogList = teExamBreachLogService.list(teExamBreachLogQueryWrapper);
                 teExamBreachLogList.forEach(s -> {
                     s.setType(type.name());
@@ -493,6 +500,14 @@ public class TIeInvigilateController {
                 });
             }
             for (TEExamBreachLog eb : teExamBreachLogList) {
+                Map<String, Object> properties = new HashMap<>();
+                properties.put("type", eb.getDescription());
+                properties.put("remark", eb.getType());
+                properties.put("examStudentId", eb.getExamStudentId());
+                properties.put("examRecordId", eb.getExamRecordId());
+                ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(eb.getExamStudentId());
+                MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.STUDENT.name(), eb.getStatus() == 0 ? SystemOperationEnum.BREACH_HANDLE : SystemOperationEnum.BREACH_REVOKE, MqTagEnum.STUDENT, String.valueOf(examStudentCacheBean.getStudentId()), properties, examStudentCacheBean.getIdentity());
+                mqDtoService.assembleSendOneWayMsg(mqDto);
                 teExamBreachLogService.saveOrUpdate(eb);
             }
         }

+ 11 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/backend/InvigilateListDetailBean.java

@@ -81,6 +81,17 @@ public class InvigilateListDetailBean implements Serializable {
     @ApiModelProperty(name = "考生轨迹")
     private List<TEExamStudentLog> examStudentLogList;
 
+    @ApiModelProperty(name = "监控源")
+    private String monitorVideoSource;
+
+    public String getMonitorVideoSource() {
+        return monitorVideoSource;
+    }
+
+    public void setMonitorVideoSource(String monitorVideoSource) {
+        this.monitorVideoSource = monitorVideoSource;
+    }
+
     public String getBasePhotoPath() {
         return basePhotoPath;
     }

+ 16 - 3
themis-business/src/main/java/com/qmth/themis/business/entity/TEExamStudentLog.java

@@ -10,7 +10,6 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 import java.io.Serializable;
-import java.util.Date;
 
 /**
  * @Description: 考生轨迹
@@ -69,6 +68,10 @@ public class TEExamStudentLog implements Serializable {
     @TableField(value = "update_time", fill = FieldFill.UPDATE)
     private Long updateTime;
 
+    @ApiModelProperty(value = "日志标题")
+    @TableField(value = "title")
+    private String title;
+
     public TEExamStudentLog() {
 
     }
@@ -81,7 +84,7 @@ public class TEExamStudentLog implements Serializable {
         this.studentId = studentId;
     }
 
-    public TEExamStudentLog(String type, String info, String remark, Long studentId, Long examStudentId, Long examRecordId) {
+    public TEExamStudentLog(String type, String info, String remark, Long studentId, Long examStudentId, Long examRecordId, String title) {
         this.id = Constants.idGen.next();
         this.type = type;
         this.info = info;
@@ -89,9 +92,10 @@ public class TEExamStudentLog implements Serializable {
         this.studentId = studentId;
         this.examStudentId = examStudentId;
         this.examRecordId = examRecordId;
+        this.title = title;
     }
 
-    public TEExamStudentLog(String type, String info, String remark, Long studentId, Long examStudentId, Long examRecordId,Long objId) {
+    public TEExamStudentLog(String type, String info, String remark, Long studentId, Long examStudentId, Long examRecordId, Long objId, String title) {
         this.id = Constants.idGen.next();
         this.type = type;
         this.info = info;
@@ -100,6 +104,15 @@ public class TEExamStudentLog implements Serializable {
         this.examStudentId = examStudentId;
         this.examRecordId = examRecordId;
         this.objId = objId;
+        this.title = title;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
     }
 
     public Long getUpdateTime() {

+ 20 - 13
themis-business/src/main/java/com/qmth/themis/business/enums/ExamRecordStatusEnum.java

@@ -1,33 +1,40 @@
 package com.qmth.themis.business.enums;
 
 /**
-* @Description: 考试记录 enum
-* @Param:
-* @return:
-* @Author: wangliang
-* @Date: 2020/7/25
-*/
+ * @Description: 考试记录 enum
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2020/7/25
+ */
 public enum ExamRecordStatusEnum {
 
-    FIRST_PREPARE("首次候考"),
+    FIRST_PREPARE("首次候考", "进入候考"),
 
-    ANSWERING("正在答题"),
+    ANSWERING("正在答题", "进入考试"),
 
-    BREAK_OFF("已中断"),
+    BREAK_OFF("已中断", "考试中断"),
 
-    RESUME_PREPARE("断点恢复候考"),
+    RESUME_PREPARE("断点恢复候考", "断点恢复候考"),
 
-    FINISHED("已结束考试"),
+    FINISHED("已结束考试", "交卷"),
 
-    PERSISTED("数据已保存");
+    PERSISTED("数据已保存", "数据已保存");
 
     private String code;
 
-    private ExamRecordStatusEnum(String code){
+    private String title;
+
+    private ExamRecordStatusEnum(String code, String title) {
         this.code = code;
+        this.title = title;
     }
 
     public String getCode() {
         return code;
     }
+
+    public String getTitle() {
+        return title;
+    }
 }

+ 18 - 11
themis-business/src/main/java/com/qmth/themis/business/enums/ExamTypeEnum.java

@@ -1,27 +1,34 @@
 package com.qmth.themis.business.enums;
 
-/** 
-* @Description: 考试类型 enum
-* @Param:  
-* @return:  
-* @Author: wangliang
-* @Date: 2020/7/29 
-*/ 
+/**
+ * @Description: 考试类型 enum
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2020/7/29
+ */
 public enum ExamTypeEnum {
 
-	FIRST_START("首次开考"),
+    FIRST_START("首次开考", "身份识别"),
 
-	RESUME_START("恢复开考"),
+    RESUME_START("恢复开考", "身份识别"),
 
-	IN_PROCESS("过程中");
+    IN_PROCESS("过程中", "考试中");
 
     private String code;
 
-    private ExamTypeEnum(String code){
+    private String title;
+
+    private ExamTypeEnum(String code, String title) {
         this.code = code;
+        this.title = title;
     }
 
     public String getCode() {
         return code;
     }
+
+    public String getTitle() {
+        return title;
+    }
 }

+ 15 - 8
themis-business/src/main/java/com/qmth/themis/business/enums/ExceptionEnum.java

@@ -11,30 +11,37 @@ import java.util.Objects;
  */
 public enum ExceptionEnum {
 
-    NET_TIME_OUT("网络超时"),
+    NET_TIME_OUT("网络超时", "异常处理"),
 
-    MACHING_STOP("机器硬件故障、死机"),
+    MACHING_STOP("机器硬件故障、死机", "异常处理"),
 
-    NET_TIME_BREAK("网络断开"),
+    NET_TIME_BREAK("网络断开", "异常处理"),
 
-    SOFTWARE_STOP("软件故障"),
+    SOFTWARE_STOP("软件故障", "异常处理"),
 
-    POWER_CUT("停电"),
+    POWER_CUT("停电", "异常处理"),
 
-    OTHER("其它"),
+    OTHER("其它", "异常处理"),
 
-    EXIT("退出");
+    EXIT("退出", "异常处理");
 
     private String code;
 
-    private ExceptionEnum(String code) {
+    private String title;
+
+    private ExceptionEnum(String code, String title) {
         this.code = code;
+        this.title = title;
     }
 
     public String getCode() {
         return code;
     }
 
+    public String getTitle() {
+        return title;
+    }
+
     /**
      * 状态转换 toName
      *

+ 23 - 10
themis-business/src/main/java/com/qmth/themis/business/enums/LivenessTypeEnum.java

@@ -2,24 +2,37 @@ package com.qmth.themis.business.enums;
 
 /**
  * 活体验证类型
- * 
+ *
  * @Description:
  * @Author: xiatian
  * @Date: 2020-07-31
  */
 public enum LivenessTypeEnum {
 
-	FIRST_START("首次开考"),
+    FIRST_START("首次开考", "身份识别"),
 
-	RESUME_START("恢复开考"), IN_PROCESS("过程中"), WARNING_AUTO("预警自动加入"), INVIGILATE_MANUAL("监考手工加入");
+    RESUME_START("恢复开考", "身份识别"),
 
-	private String title;
+    IN_PROCESS("过程中", "考试中"),
 
-	private LivenessTypeEnum(String title) {
-		this.title = title;
-	}
+    WARNING_AUTO("预警自动加入", "预警自动加入"),
 
-	public String getTitle() {
-		return title;
-	}
+    INVIGILATE_MANUAL("监考手工加入", "监考手工加入");
+
+    private String title;
+
+    private String code;
+
+    private LivenessTypeEnum(String code, String title) {
+        this.code = code;
+        this.title = title;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public String getCode() {
+        return code;
+    }
 }

+ 20 - 9
themis-business/src/main/java/com/qmth/themis/business/enums/SystemOperationEnum.java

@@ -9,29 +9,40 @@ package com.qmth.themis.business.enums;
  */
 public enum SystemOperationEnum {
 
-    LOGIN("登录"),
+    LOGIN("登录","用户登录"),
 
-    LOGOUT("注销"),
+    LOGOUT("注销","用户注销"),
 
-    FIRST_PREPARE("首次候考"),
+    FIRST_PREPARE("首次候考", "进入候考"),
 
-    ANSWERING("正在答题"),
+    ANSWERING("正在答题","进入考试"),
 
-    BREAK_OFF("已中断"),
+    BREAK_OFF("已中断","考试中断"),
 
-    RESUME_PREPARE("断点恢复候考"),
+    RESUME_PREPARE("断点恢复候考","断点恢复候考"),
 
-    FINISHED("交卷"),
+    FINISHED("交卷","交卷"),
 
-    PERSISTED("数据已保存");
+    PERSISTED("数据已保存","数据已保存"),
+
+    BREACH_HANDLE("违纪处理","违纪处理"),
+
+    BREACH_REVOKE("撤销违纪","撤销违纪");
 
     private String code;
 
-    private SystemOperationEnum(String code) {
+    private String title;
+
+    private SystemOperationEnum(String code,String title) {
         this.code = code;
+        this.title = title;
     }
 
     public String getCode() {
         return code;
     }
+
+    public String getTitle() {
+        return title;
+    }
 }

+ 26 - 19
themis-business/src/main/java/com/qmth/themis/business/enums/VerifyExceptionEnum.java

@@ -5,39 +5,46 @@ import java.util.List;
 
 /**
  * 人脸、活检验证异常
- * 
+ *
  * @Description:
  * @Author: xiatian
  * @Date: 2020-07-31
  */
 public enum VerifyExceptionEnum {
 
-	FACE_COUNT_ERROR("人脸数量异常", Arrays.asList("D4", "D8")),
+    FACE_COUNT_ERROR("人脸数量异常", Arrays.asList("D4", "D8"), "违纪预警"),
 
-	FACE_COMPARE_ERROR("人脸比对异常", Arrays.asList("D6", "D14")),
+    FACE_COMPARE_ERROR("人脸比对异常", Arrays.asList("D6", "D14"), "违纪预警"),
 
-	EYE_CLOSE_ERROR("闭眼检测异常", Arrays.asList("-1")),
+    EYE_CLOSE_ERROR("闭眼检测异常", Arrays.asList("-1"), "违纪预警"),
 
-	LIVENESS_ACTION_ERROR("活检动作错误", Arrays.asList("-1")),
+    LIVENESS_ACTION_ERROR("活检动作错误", Arrays.asList("-1"), "违纪预警"),
 
-	NONE("无异常", Arrays.asList("-1")),
+    NONE("无异常", Arrays.asList("-1"), "违纪预警"),
 
-	REALNESS("真实性检测异常", Arrays.asList("D15"));
+    REALNESS("真实性检测异常", Arrays.asList("D15"), "违纪预警");
 
-	private String code;
+    private String code;
 
-	private List<String> level;
+    private List<String> level;
 
-	private VerifyExceptionEnum(String code, List<String> level) {
-		this.code = code;
-		this.level = level;
-	}
+    private String title;
 
-	public String getCode() {
-		return code;
-	}
+    private VerifyExceptionEnum(String code, List<String> level, String title) {
+        this.code = code;
+        this.level = level;
+        this.title = title;
+    }
 
-	public List<String> getLevel() {
-		return level;
-	}
+    public String getCode() {
+        return code;
+    }
+
+    public List<String> getLevel() {
+        return level;
+    }
+
+    public String getTitle() {
+        return title;
+    }
 }

+ 13 - 6
themis-business/src/main/java/com/qmth/themis/business/enums/WarningLevelEnum.java

@@ -9,23 +9,26 @@ package com.qmth.themis.business.enums;
  */
 public enum WarningLevelEnum {
 
-    D4("一个考试场次中未检测到人脸或有违规动作(左顾右盼、低头、转身、离开座位、人脸移除、遮挡等)次数超过3次(持续30秒连续帧画面违规记为次数1次)","【疑似违规动作】考生较长时间离座或持续有违规动作"),
+    D4("一个考试场次中未检测到人脸或有违规动作(左顾右盼、低头、转身、离开座位、人脸移除、遮挡等)次数超过3次(持续30秒连续帧画面违规记为次数1次)", "【疑似违规动作】考生较长时间离座或持续有违规动作", "违纪预警"),
 
-    D8("一个考试场次中检测到多张人脸超过3次(持续15秒连续帧画面90%存在多张人脸记为次数1次)","【疑似求助第三方】系统多次检测到镜头里有除考生之外的多张人脸"),
+    D8("一个考试场次中检测到多张人脸超过3次(持续15秒连续帧画面90%存在多张人脸记为次数1次)", "【疑似求助第三方】系统多次检测到镜头里有除考生之外的多张人脸", "违纪预警"),
 
-    D6("一个考试场次中检测到人脸与底照不符次数超过3次(持续30秒连续帧画面90%比对底照不符记为次数1次)","【疑似替考】系统多次检测到当前考生身份不符"),
+    D6("一个考试场次中检测到人脸与底照不符次数超过3次(持续30秒连续帧画面90%比对底照不符记为次数1次)", "【疑似替考】系统多次检测到当前考生身份不符", "违纪预警"),
 
-    D14("一个考试场次内人脸抓拍检测(D12)失败累计次数超过6次","疑似采用照片】系统检测到考生疑似在镜头前采用照片"),
+    D14("一个考试场次内人脸抓拍检测(D12)失败累计次数超过6次", "疑似采用照片】系统检测到考生疑似在镜头前采用照片", "违纪预警"),
 
-    D15("真实性检测失败1次以上","【疑似采用照片或虚拟摄像头】系统随机真实性检测失败");
+    D15("真实性检测失败1次以上", "【疑似采用照片或虚拟摄像头】系统随机真实性检测失败", "违纪预警");
 
     private String desc;
 
     private String title;
 
-    private WarningLevelEnum(String desc,String title) {
+    private String secondTitle;
+
+    private WarningLevelEnum(String desc, String title, String secondTitle) {
         this.desc = desc;
         this.title = title;
+        this.secondTitle = secondTitle;
     }
 
     public String getDesc() {
@@ -35,4 +38,8 @@ public enum WarningLevelEnum {
     public String getTitle() {
         return title;
     }
+
+    public String getSecondTitle() {
+        return secondTitle;
+    }
 }

+ 8 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TEExamBreachLogService.java

@@ -3,6 +3,9 @@ package com.qmth.themis.business.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.themis.business.entity.TEExamBreachLog;
 
+import java.util.List;
+import java.util.Map;
+
 /**
  * @Description: 考生违纪处理 服务类
  * @Param:
@@ -12,4 +15,9 @@ import com.qmth.themis.business.entity.TEExamBreachLog;
  */
 public interface TEExamBreachLogService extends IService<TEExamBreachLog> {
 
+    /**
+     * 违纪处理
+     * @param mapParameter
+     */
+    void breachOper(Map<String, Object> mapParameter);
 }

+ 68 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamBreachLogServiceImpl.java

@@ -1,10 +1,25 @@
 package com.qmth.themis.business.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.dao.TEExamBreachLogMapper;
+import com.qmth.themis.business.entity.TBUser;
 import com.qmth.themis.business.entity.TEExamBreachLog;
+import com.qmth.themis.business.entity.TOeExamRecord;
+import com.qmth.themis.business.enums.BreachCancelTypeEnum;
+import com.qmth.themis.business.enums.BreachTypeEnum;
 import com.qmth.themis.business.service.TEExamBreachLogService;
+import com.qmth.themis.business.service.TOeExamRecordService;
+import com.qmth.themis.business.util.ServletUtil;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 /**
  * @Description: 考生违纪处理 服务实现类
@@ -16,4 +31,57 @@ import org.springframework.stereotype.Service;
 @Service
 public class TEExamBreachLogServiceImpl extends ServiceImpl<TEExamBreachLogMapper, TEExamBreachLog> implements TEExamBreachLogService {
 
+    @Resource
+    TOeExamRecordService tOeExamRecordService;
+
+    /**
+     * 违纪处理
+     *
+     * @param mapParameter
+     */
+    @Override
+    @Transactional
+    public void breachOper(Map<String, Object> mapParameter) {
+        Integer status = Integer.parseInt(String.valueOf(mapParameter.get("status")));
+        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
+        List<String> recordIdList = (List<String>) mapParameter.get("examRecordId");
+        List<TEExamBreachLog> teExamBreachLogList = new ArrayList<>();
+        if (status == 0) {//新建违纪
+            BreachTypeEnum type = BreachTypeEnum.valueOf(String.valueOf(mapParameter.get("type")));
+            List<TEExamBreachLog> finalTeExamBreachLogList = teExamBreachLogList;
+            for (int i = 0; i < recordIdList.size(); i++) {
+                Long l = Long.parseLong(String.valueOf(recordIdList.get(i)));
+                Long examId = ExamRecordCacheUtil.getExamId(l);
+                Long examStudentId = null;
+                Long examActivityId = null;
+                if (Objects.isNull(examId)) {
+                    TOeExamRecord tOeExamRecord = tOeExamRecordService.getById(l);
+                    examId = tOeExamRecord.getExamId();
+                    examStudentId = tOeExamRecord.getExamStudentId();
+                    examActivityId = tOeExamRecord.getExamActivityId();
+                } else {
+                    examId = ExamRecordCacheUtil.getExamId(l);
+                    examStudentId = ExamRecordCacheUtil.getExamStudentId(l);
+                    examActivityId = ExamRecordCacheUtil.getExamActivityId(l);
+                }
+                TEExamBreachLog teExamBreachLog = new TEExamBreachLog(examId, examActivityId, l, examStudentId, type.name(), String.valueOf(mapParameter.get("description")), status);
+                teExamBreachLog.setCreateId(tbUser.getId());
+                finalTeExamBreachLogList.add(teExamBreachLog);
+                ExamRecordCacheUtil.setBreachStatus(l, 0, true);
+            }
+        } else {//撤销违纪
+            BreachCancelTypeEnum type = BreachCancelTypeEnum.valueOf(String.valueOf(mapParameter.get("type")));
+            QueryWrapper<TEExamBreachLog> teExamBreachLogQueryWrapper = new QueryWrapper<>();
+            teExamBreachLogQueryWrapper.lambda().in(TEExamBreachLog::getExamRecordId, recordIdList)
+                    .eq(TEExamBreachLog::getStatus, 0);
+            teExamBreachLogList = this.list(teExamBreachLogQueryWrapper);
+            teExamBreachLogList.forEach(s -> {
+                s.setType(type.name());
+                s.setDescription(String.valueOf(mapParameter.get("description")));
+                s.setStatus(status);
+                s.setUpdateId(tbUser.getId());
+                ExamRecordCacheUtil.setBreachStatus(s.getExamRecordId(), 1, true);
+            });
+        }
+    }
 }

+ 11 - 7
themis-business/src/main/java/com/qmth/themis/business/service/impl/WarningServiceImpl.java

@@ -73,7 +73,7 @@ public class WarningServiceImpl implements WarningService {
                     TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(1), WarningLevelEnum.valueOf(warningEnum.getLevel().get(1)).getTitle(), warningEnum, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
                     tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                     this.setWarningCount(recordId);
-                    this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId);
+                    this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, teConfig.getMultipleFaceCountError());
                 }
             }
         } else if (faceCount <= 0) {//未检测到人脸
@@ -85,7 +85,7 @@ public class WarningServiceImpl implements WarningService {
                     TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(0), WarningLevelEnum.valueOf(warningEnum.getLevel().get(0)).getTitle(), warningEnum, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
                     tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                     this.setWarningCount(recordId);
-                    this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId);
+                    this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, teConfig.getNoFaceCountError());
                 }
             }
         }
@@ -115,13 +115,13 @@ public class WarningServiceImpl implements WarningService {
                 TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(0), WarningLevelEnum.valueOf(warningEnum.getLevel().get(0)).getTitle(), warningEnum, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
                 tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                 this.setWarningCount(recordId);
-                this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId);
+                this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, teConfig.getMatchFaceCompareErrorCount());
             }
             if (count >= teConfig.getTotalFaceCompareErrorCount()) {
                 TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, warningEnum.getLevel().get(1), WarningLevelEnum.valueOf(warningEnum.getLevel().get(1)).getTitle(), warningEnum, photoUrl, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
                 tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
                 this.setWarningCount(recordId);
-                this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId);
+                this.setPhotoUrls(map, tIeInvigilateWarnInfo, examStudentCacheBean, recordId, teConfig.getTotalFaceCompareErrorCount());
             }
         }
     }
@@ -168,7 +168,7 @@ public class WarningServiceImpl implements WarningService {
             TIeInvigilateWarnInfo tIeInvigilateWarnInfo = new TIeInvigilateWarnInfo(examId, examActivityId, recordId, examStudentId, WarningLevelEnum.D15.name(), WarningLevelEnum.D15.getTitle(), warningEnum, Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(recordId)) ? ExamRecordCacheUtil.getBreachStatus(recordId) : 1);
             tIeInvigilateWarnInfoService.saveOrUpdate(tIeInvigilateWarnInfo);
             this.setWarningCount(recordId);
-            TEExamStudentLog teExamStudentLog = new TEExamStudentLog(tIeInvigilateWarnInfo.getType().name(), WarningLevelEnum.valueOf(tIeInvigilateWarnInfo.getLevel()).getTitle(), tIeInvigilateWarnInfo.getType().getCode(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId);
+            TEExamStudentLog teExamStudentLog = new TEExamStudentLog(tIeInvigilateWarnInfo.getType().name(), WarningLevelEnum.valueOf(tIeInvigilateWarnInfo.getLevel()).getTitle(), tIeInvigilateWarnInfo.getType().getCode(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId, WarningLevelEnum.valueOf(tIeInvigilateWarnInfo.getLevel()).getSecondTitle());
             teExamStudentLogService.saveOrUpdate(teExamStudentLog);
         }
     }
@@ -195,17 +195,21 @@ public class WarningServiceImpl implements WarningService {
      * @param tIeInvigilateWarnInfo
      * @param examStudentCacheBean
      * @param recordId
+     * @param count
      */
-    public void setPhotoUrls(Map<String, Object> map, TIeInvigilateWarnInfo tIeInvigilateWarnInfo, ExamStudentCacheBean examStudentCacheBean, Long recordId) {
+    public void setPhotoUrls(Map<String, Object> map, TIeInvigilateWarnInfo tIeInvigilateWarnInfo, ExamStudentCacheBean examStudentCacheBean, Long recordId, Integer count) {
         List<String> photoUrls = new ArrayList();
         if (Objects.nonNull(map.get("photoUrls")) && !Objects.equals(map.get("photoUrls"), "")) {
             String[] s = String.valueOf(map.get("photoUrls")).split(",");
             Collections.addAll(photoUrls, s);
+            if (photoUrls.size() > count) {
+                photoUrls = photoUrls.subList(0, count);
+            }
         }
         JSONObject jsonObject = new JSONObject();
         jsonObject.put("PHOTOS", photoUrls);
         jsonObject.put("MIN_CREATE_TIME", map.get("createTime"));
-        TEExamStudentLog teExamStudentLog = new TEExamStudentLog(tIeInvigilateWarnInfo.getType().name(), WarningLevelEnum.valueOf(tIeInvigilateWarnInfo.getLevel()).getTitle(), jsonObject.toJSONString(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId);
+        TEExamStudentLog teExamStudentLog = new TEExamStudentLog(tIeInvigilateWarnInfo.getType().name(), WarningLevelEnum.valueOf(tIeInvigilateWarnInfo.getLevel()).getTitle(), jsonObject.toJSONString(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId, WarningLevelEnum.valueOf(tIeInvigilateWarnInfo.getLevel()).getSecondTitle());
         teExamStudentLogService.saveOrUpdate(teExamStudentLog);
     }
 }

+ 1 - 0
themis-business/src/main/resources/db/init.sql

@@ -1124,6 +1124,7 @@ CREATE TABLE `t_e_exam_student_log` (
   `create_time` bigint DEFAULT NULL COMMENT '创建时间',
   `obj_id` bigint DEFAULT NULL COMMENT '业务id',
   `update_time` bigint DEFAULT NULL COMMENT '更新时间',
+  `title` varchar(100) DEFAULT NULL COMMENT '日志标题',
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='考生轨迹';
 

+ 11 - 12
themis-business/src/main/resources/mapper/TEExamStudentLogMapper.xml

@@ -2,17 +2,16 @@
 <!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.TEExamStudentLogMapper">
 
-	<select id="getExamStudentLogList"
-		resultType="com.qmth.themis.business.bean.backend.ExamStudentLogDetailListBean">
-		SELECT
-		f.create_time
-		createTime,
-		f.type type,
-		f.info remark
-		FROM
-		t_e_exam_student_log f
-		where f.exam_student_id
-		=#{examStudentId}
-		order by f.create_time
+	<select id="getExamStudentLogList" resultType="com.qmth.themis.business.bean.backend.ExamStudentLogDetailListBean">
+		select
+			f.create_time createTime,
+			f.title type,
+			f.info remark
+		from
+			t_e_exam_student_log f
+		where
+			f.exam_student_id = #{examStudentId}
+		order by
+			f.create_time asc
 	</select>
 </mapper>

+ 6 - 6
themis-exam/src/main/java/com/qmth/themis/exam/api/TEStudentController.java

@@ -144,12 +144,12 @@ public class TEStudentController {
             throw new BusinessException(ExceptionResultEnum.PASSWORD_ERROR);
         }
         //判断是否有正在考试的
-        Long unFinishedRecordId=ExamingDataCacheUtil.getUnFinishedRecordId(user.getId());
-        if(unFinishedRecordId!=null) {
-        	WebsocketStatusEnum sta=ExamRecordCacheUtil.getClientWebsocketStatus(unFinishedRecordId);
-        	if(WebsocketStatusEnum.ON_LINE.equals(sta)) {
-        		throw new BusinessException("该学生正在考试,不能登录");
-        	}
+        Long unFinishedRecordId = ExamingDataCacheUtil.getUnFinishedRecordId(user.getId());
+        if (unFinishedRecordId != null) {
+            WebsocketStatusEnum sta = ExamRecordCacheUtil.getClientWebsocketStatus(unFinishedRecordId);
+            if (WebsocketStatusEnum.ON_LINE.equals(sta)) {
+                throw new BusinessException("该学生正在考试,不能登录");
+            }
         }
         return userLoginCommon(user, examId, orgId);
     }

+ 3 - 3
themis-exam/src/main/java/com/qmth/themis/exam/listener/service/impl/MqOeLogicServiceImpl.java

@@ -112,7 +112,7 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
                     map.put(SystemConstant.MESSAGE, FinishTypeEnum.valueOf(String.valueOf(mqDto.getProperties().get("type"))).getCode());
                     WebsocketDto websocketDto = new WebsocketDto(WebsocketTypeEnum.INVIGILATE_STOP_EXAM.name(), map);
                     webSocketOeServer.sendMessage(websocketDto);
-                    TEExamStudentLog teExamStudentLog = new TEExamStudentLog(mqDto.getType().name(), mqDto.getType().getCode(), mqDto.getType().getCode(), examStudentCacheBean.getStudentId(), examStudentId, recordId);
+                    TEExamStudentLog teExamStudentLog = new TEExamStudentLog(mqDto.getType().name(), mqDto.getType().getCode(), mqDto.getType().getCode(), examStudentCacheBean.getStudentId(), examStudentId, recordId, mqDto.getType().getCode());
                     teExamStudentLogService.save(teExamStudentLog);
                 }
             });
@@ -148,7 +148,7 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
                     map.put(SystemConstant.BREACH_STATUS, FinishTypeEnum.valueOf(String.valueOf(mqDto.getProperties().get("type"))).getCode());
                     WebsocketDto websocketDto = new WebsocketDto(WebsocketTypeEnum.BREACH_STOP_EXAM.name(), map);
                     webSocketOeServer.sendMessage(websocketDto);
-                    TEExamStudentLog teExamStudentLog = new TEExamStudentLog(mqDto.getType().name(), mqDto.getType().getCode(), mqDto.getType().getCode(), examStudentCacheBean.getStudentId(), examStudentId, recordId);
+                    TEExamStudentLog teExamStudentLog = new TEExamStudentLog(mqDto.getType().name(), mqDto.getType().getCode(), mqDto.getType().getCode(), examStudentCacheBean.getStudentId(), examStudentId, recordId, mqDto.getType().getCode());
                     teExamStudentLogService.save(teExamStudentLog);
                 }
             });
@@ -184,7 +184,7 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
                 map.put(SystemConstant.RECORD_ID, recordId);
                 WebsocketDto websocketDto = new WebsocketDto(WebsocketTypeEnum.INVIGILATE_LIVENESS_VERIFY.name(), map);
                 webSocketOeServer.sendMessage(websocketDto);
-                TEExamStudentLog teExamStudentLog = new TEExamStudentLog(mqDto.getType().name(), mqDto.getType().getCode(), mqDto.getType().getCode(), examStudentCacheBean.getStudentId(), examStudentId, recordId);
+                TEExamStudentLog teExamStudentLog = new TEExamStudentLog(mqDto.getType().name(), mqDto.getType().getCode(), mqDto.getType().getCode(), examStudentCacheBean.getStudentId(), examStudentId, recordId, mqDto.getType().getCode());
                 teExamStudentLogService.save(teExamStudentLog);
             }
         }

+ 19 - 16
themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java

@@ -38,7 +38,10 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.io.IOException;
 import java.lang.reflect.Method;
-import java.util.*;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
 
 /**
  * @Description: mq执行逻辑 impl
@@ -143,7 +146,7 @@ public class MqLogicServiceImpl implements MqLogicService {
         } else if (Objects.equals(MqTagEnum.STUDENT.name(), tag)) {
             TEExamStudentLog teExamStudentLog = null;
             if (Objects.nonNull(mqDto.getProperties())) {
-                teExamStudentLog = new TEExamStudentLog(String.valueOf(mqDto.getBody()), SystemOperationEnum.valueOf(String.valueOf(mqDto.getBody())).getCode(), String.valueOf(mqDto.getProperties().get("remark")), Long.parseLong(String.valueOf(mqDto.getObjId())), Long.parseLong(String.valueOf(mqDto.getProperties().get("examStudentId"))), Long.parseLong(String.valueOf(mqDto.getProperties().get("examRecordId"))));
+                teExamStudentLog = new TEExamStudentLog(String.valueOf(mqDto.getBody()), Objects.nonNull(mqDto.getProperties().get("type")) ? String.valueOf(mqDto.getProperties().get("type")) : SystemOperationEnum.valueOf(String.valueOf(mqDto.getBody())).getCode(), String.valueOf(mqDto.getProperties().get("remark")), Long.parseLong(String.valueOf(mqDto.getObjId())), Long.parseLong(String.valueOf(mqDto.getProperties().get("examStudentId"))), Long.parseLong(String.valueOf(mqDto.getProperties().get("examRecordId"))), SystemOperationEnum.valueOf(String.valueOf(mqDto.getBody())).getTitle());
             } else {
                 teExamStudentLog = new TEExamStudentLog(String.valueOf(mqDto.getBody()), SystemOperationEnum.valueOf(String.valueOf(mqDto.getBody())).getCode(), SystemOperationEnum.valueOf(String.valueOf(mqDto.getBody())).getCode(), Long.parseLong(String.valueOf(mqDto.getObjId())));
             }
@@ -327,7 +330,7 @@ public class MqLogicServiceImpl implements MqLogicService {
         if (Objects.nonNull(photoUrl) && (Objects.equals(type.toUpperCase(), ExamTypeEnum.FIRST_START.name()) || Objects.equals(type.toUpperCase(), ExamTypeEnum.RESUME_START.name()))) {
             JSONObject jsonObject = new JSONObject();
             jsonObject.put(PhotoTypeEnum.FACE_VERIFY_PHOTO.name(), photoUrl);
-            TEExamStudentLog teExamStudentLog = new TEExamStudentLog(type, ExamTypeEnum.valueOf(type).getCode(), jsonObject.toJSONString(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId);
+            TEExamStudentLog teExamStudentLog = new TEExamStudentLog(type, ExamTypeEnum.valueOf(type).getCode(), jsonObject.toJSONString(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId, ExamTypeEnum.valueOf(type).getTitle());
             faceVerifyHistoryService.save(id, recordId, type, photoUrl, faceCount, similarity, realness, time, exception, null);
             teExamStudentLogService.saveOrUpdate(teExamStudentLog);
         } else if (Objects.equals(type.toUpperCase(), ExamTypeEnum.IN_PROCESS.name())) {
@@ -429,7 +432,7 @@ public class MqLogicServiceImpl implements MqLogicService {
                 if (Objects.nonNull(photoType) && Objects.nonNull(photoUrl) && Objects.equals(photoType.toLowerCase(), "startup")) {
                     JSONObject object = new JSONObject();
                     object.put(PhotoTypeEnum.LIVENESS_VERIFY_PHOTO.name(), photoUrl);
-                    TEExamStudentLog teExamStudentLog = new TEExamStudentLog(type, LivenessTypeEnum.valueOf(type).getTitle(), object.toJSONString(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId);
+                    TEExamStudentLog teExamStudentLog = new TEExamStudentLog(type, LivenessTypeEnum.valueOf(type).getCode(), object.toJSONString(), examStudentCacheBean.getStudentId(), examStudentCacheBean.getId(), recordId, LivenessTypeEnum.valueOf(type).getTitle());
                     livenessVerifyHistoryService.save(id, recordId, type, actions, retry, startTime, finishTime, exception, null);
                     teExamStudentLogService.saveOrUpdate(teExamStudentLog);
                     break;
@@ -735,24 +738,24 @@ public class MqLogicServiceImpl implements MqLogicService {
         redisUtil.setForHash(RedisKeyHelper.examBreakCacheKey(tOeExamBreakHistory.getId()), SimpleBeanUtil.objectToMap(tOeExamBreakHistory));
 
         Long clientLastSyncTime = ExamRecordCacheUtil.getClientLastSyncTime(recordId);
-        Integer diff = 0;
-        Long startTime = System.currentTimeMillis();
-        if (Objects.nonNull(clientLastSyncTime)) {//大于等于当前时间,说明未重连或重登录
-            Long l = (startTime - clientLastSyncTime) / 1000;
-            diff = l.intValue();
-        }
+//        Integer diff = 0;
+//        Long startTime = System.currentTimeMillis();
+//        if (Objects.nonNull(clientLastSyncTime)) {//大于等于当前时间,说明未重连或重登录
+//            Long l = (startTime - clientLastSyncTime) / 1000;
+//            diff = l.intValue();
+//        }
         Long examId = ExamRecordCacheUtil.getExamId(recordId);
         Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
         Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
         ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
         //增加异常日志
-        TIeInvigilateExceptionInfo tIeInvigilateExceptionInfo = new TIeInvigilateExceptionInfo(examId, examActivityId, recordId, examStudentId, ExceptionEnum.NET_TIME_OUT.getCode(), ExceptionEnum.NET_TIME_OUT, diff, ExamRecordCacheUtil.getLastBreakId(recordId));
-        if (Objects.nonNull(diff)) {
-            tIeInvigilateExceptionInfo.setCreateTime(clientLastSyncTime);
-            tIeInvigilateExceptionInfo.setUpdateTime(startTime);
-        }
+        TIeInvigilateExceptionInfo tIeInvigilateExceptionInfo = new TIeInvigilateExceptionInfo(examId, examActivityId, recordId, examStudentId, ExceptionEnum.NET_TIME_OUT.getCode(), ExceptionEnum.NET_TIME_OUT, null, ExamRecordCacheUtil.getLastBreakId(recordId));
+//        if (Objects.nonNull(diff)) {
+//            tIeInvigilateExceptionInfo.setCreateTime(clientLastSyncTime);
+//            tIeInvigilateExceptionInfo.setUpdateTime(startTime);
+//        }
         tIeInvigilateExceptionInfoService.saveOrUpdate(tIeInvigilateExceptionInfo);
-        TEExamStudentLog teExamStudentLog = new TEExamStudentLog(SystemOperationEnum.BREAK_OFF.name(), SystemOperationEnum.BREAK_OFF.getCode(), SystemOperationEnum.BREAK_OFF.getCode(), examStudentCacheBean.getStudentId(), examStudentId, recordId, ExamRecordCacheUtil.getLastBreakId(recordId));
+        TEExamStudentLog teExamStudentLog = new TEExamStudentLog(SystemOperationEnum.BREAK_OFF.name(), SystemOperationEnum.BREAK_OFF.getCode(), SystemOperationEnum.BREAK_OFF.getCode(), examStudentCacheBean.getStudentId(), examStudentId, recordId, ExamRecordCacheUtil.getLastBreakId(recordId), SystemOperationEnum.BREAK_OFF.getTitle());
         teExamStudentLogService.save(teExamStudentLog);
 
         Gson gson = new Gson();