wangliang 11 сар өмнө
parent
commit
c35ea184cd

+ 314 - 177
themis-admin/src/main/java/com/qmth/themis/admin/api/TIeInvigilateController.java

@@ -31,6 +31,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.util.CollectionUtils;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -54,6 +55,7 @@ import java.util.stream.Collectors;
 @RequestMapping(SystemConstant.PREFIX_URL_ADMIN + "/invigilate")
 @Validated
 public class TIeInvigilateController {
+
     private final static Logger log = LoggerFactory.getLogger(TIeInvigilateController.class);
 
     @Resource
@@ -101,33 +103,40 @@ public class TIeInvigilateController {
     @Resource
     TEExamSummaryService teExamSummaryService;
 
+    @Resource
+    TEExamMarkLogService teExamMarkLogService;
+
     @ApiOperation(value = "实时监控台视频列表接口")
     @RequestMapping(value = "/list/video", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考监控信息", response = InvigilateListVideoBean.class)})
-//    @RedisLimitAnnotation(key = "listVideo", period = 1, count = 1)
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考监控信息", response = InvigilateListVideoBean.class) })
+    //    @RedisLimitAnnotation(key = "listVideo", period = 1, count = 1)
     public Result listVideo(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
-                            @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
-                            @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
-                            @ApiParam(value = "试题下载状态", required = false) @RequestParam(required = false) Integer paperDownload,
-                            @ApiParam(value = "考生状态", required = false) @RequestParam(required = false) String status,
-                            @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
-                            @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
-                            @ApiParam(value = "预警量min", required = false) @RequestParam(required = false) Integer minWarningCount,
-                            @ApiParam(value = "预警量max", required = false) @RequestParam(required = false) Integer maxWarningCount,
-                            @ApiParam(value = "客户端网络通信状态", required = false) @RequestParam(required = false) String clientWebsocketStatus,
-                            @ApiParam(value = "监控设备来源", required = false) @RequestParam(required = false) String monitorVideoSource,
-                            @ApiParam(value = "摄像头监控设备推流状态('START'or'STOP')", required = false) @RequestParam(required = false) String cameraMonitorStatus,
-                            @ApiParam(value = "屏幕监控设备推流状态('START'or'STOP')", required = false) @RequestParam(required = false) String screenMonitorStatus,
-                            @ApiParam(value = "手机端主机位监控设备推流状态('START'or'STOP')", required = false) @RequestParam(required = false) String mobileFirstMonitorStatus,
-                            @ApiParam(value = "手机端辅机位监控设备推流状态('START'or'STOP')", required = false) @RequestParam(required = false) String mobileSecondMonitorStatus,
-                            @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
-                            @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
+            @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
+            @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
+            @ApiParam(value = "试题下载状态", required = false) @RequestParam(required = false) Integer paperDownload,
+            @ApiParam(value = "考生状态", required = false) @RequestParam(required = false) String status,
+            @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
+            @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
+            @ApiParam(value = "预警量min", required = false) @RequestParam(required = false) Integer minWarningCount,
+            @ApiParam(value = "预警量max", required = false) @RequestParam(required = false) Integer maxWarningCount,
+            @ApiParam(value = "客户端网络通信状态", required = false) @RequestParam(required = false) String clientWebsocketStatus,
+            @ApiParam(value = "监控设备来源", required = false) @RequestParam(required = false) String monitorVideoSource,
+            @ApiParam(value = "摄像头监控设备推流状态('START'or'STOP')", required = false) @RequestParam(required = false) String cameraMonitorStatus,
+            @ApiParam(value = "屏幕监控设备推流状态('START'or'STOP')", required = false) @RequestParam(required = false) String screenMonitorStatus,
+            @ApiParam(value = "手机端主机位监控设备推流状态('START'or'STOP')", required = false) @RequestParam(required = false) String mobileFirstMonitorStatus,
+            @ApiParam(value = "手机端辅机位监控设备推流状态('START'or'STOP')", required = false) @RequestParam(required = false) String mobileSecondMonitorStatus,
+            @ApiParam(value = "标记状态,MARK:标记,UN_MARK:撤销") @RequestParam(required = false) MarkEnum markStatus,
+            @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
+            @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         AuthDto authDto = themisCacheService.addAccountAuthCache(tbUser.getId());
         //如果有监考员角色,只能查看自己所监考的考场,巡考员和管理员则可以查看全部考场
         List<String> roomCodeList = new ArrayList<>();
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
-            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(new QueryWrapper<TBExamInvigilateUser>().lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId()).eq(TBExamInvigilateUser::getExamId, examId));
+            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(
+                    new QueryWrapper<TBExamInvigilateUser>().lambda()
+                            .eq(TBExamInvigilateUser::getUserId, tbUser.getId())
+                            .eq(TBExamInvigilateUser::getExamId, examId));
             if (!CollectionUtils.isEmpty(tbExamInvigilateUserList)) {
                 roomCodeList = tbExamInvigilateUserList.stream().map(s -> s.getRoomCode()).collect(Collectors.toList());
             }
@@ -136,7 +145,11 @@ public class TIeInvigilateController {
             roomCodeList.clear();
             roomCodeList.add(roomCode);
         }
-        IPage<InvigilateListVideoBean> invigilateListVideoBeanIPage = tOeExamRecordService.invigilatePageListVideo(new Page<>(pageNumber, pageSize), examId, examActivityId, roomCodeList, paperDownload, status, name, identity, minWarningCount, maxWarningCount, clientWebsocketStatus, cameraMonitorStatus, screenMonitorStatus, mobileFirstMonitorStatus, mobileSecondMonitorStatus, tbUser.getOrgId());
+        IPage<InvigilateListVideoBean> invigilateListVideoBeanIPage = tOeExamRecordService.invigilatePageListVideo(
+                new Page<>(pageNumber, pageSize), examId, examActivityId, roomCodeList, paperDownload, status, name,
+                identity, minWarningCount, maxWarningCount, clientWebsocketStatus, cameraMonitorStatus,
+                screenMonitorStatus, mobileFirstMonitorStatus, mobileSecondMonitorStatus, markStatus,
+                tbUser.getOrgId());
         if (Objects.nonNull(invigilateListVideoBeanIPage)) {
             List<InvigilateListVideoBean> invigilateListVideoBeanList = invigilateListVideoBeanIPage.getRecords();
             ExamCacheBean examCacheBean = null;
@@ -149,25 +162,31 @@ public class TIeInvigilateController {
                     s.setBasePhotoPath(
                             ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + s.getBasePhotoPath());
                     List<String> monitorVideoSourceList = null;
-                    if (Objects.nonNull(s.getMonitorVideoSource()) && !Objects.equals(s.getMonitorVideoSource().trim().replaceAll(" ", ""), "")) {
-                        monitorVideoSourceList = Arrays.asList(s.getMonitorVideoSource().trim().toUpperCase().replaceAll(" ", "").split(","));
+                    if (Objects.nonNull(s.getMonitorVideoSource()) && !Objects.equals(
+                            s.getMonitorVideoSource().trim().replaceAll(" ", ""), "")) {
+                        monitorVideoSourceList = Arrays.asList(
+                                s.getMonitorVideoSource().trim().toUpperCase().replaceAll(" ", "").split(","));
                     }
                     if (Objects.nonNull(monitorVideoSourceList) && monitorVideoSourceList.size() > 0) {
                         monitorVideoSourceList.forEach(l -> {
                             MonitorVideoSourceEnum source = MonitorVideoSourceEnum.valueOf(l);
                             switch (source.name()) {
-                                case "CLIENT_SCREEN":
-                                    s.setScreenMonitorStatusSource(ExamRecordCacheUtil.getMonitorStatus(s.getExamRecordId(), source));
-                                    break;
-                                case "CLIENT_CAMERA":
-                                    s.setCameraMonitorStatusSource(ExamRecordCacheUtil.getMonitorStatus(s.getExamRecordId(), source));
-                                    break;
-                                case "MOBILE_FIRST":
-                                    s.setMobileFirstMonitorStatusSource(ExamRecordCacheUtil.getMonitorStatus(s.getExamRecordId(), source));
-                                    break;
-                                default:
-                                    s.setMobileSecondMonitorStatusSource(ExamRecordCacheUtil.getMonitorStatus(s.getExamRecordId(), source));
-                                    break;
+                            case "CLIENT_SCREEN":
+                                s.setScreenMonitorStatusSource(
+                                        ExamRecordCacheUtil.getMonitorStatus(s.getExamRecordId(), source));
+                                break;
+                            case "CLIENT_CAMERA":
+                                s.setCameraMonitorStatusSource(
+                                        ExamRecordCacheUtil.getMonitorStatus(s.getExamRecordId(), source));
+                                break;
+                            case "MOBILE_FIRST":
+                                s.setMobileFirstMonitorStatusSource(
+                                        ExamRecordCacheUtil.getMonitorStatus(s.getExamRecordId(), source));
+                                break;
+                            default:
+                                s.setMobileSecondMonitorStatusSource(
+                                        ExamRecordCacheUtil.getMonitorStatus(s.getExamRecordId(), source));
+                                break;
                             }
                         });
                     }
@@ -175,11 +194,15 @@ public class TIeInvigilateController {
                     Optional.ofNullable(sysConfig).orElseThrow(() -> new BusinessException("未配置监控前缀"));
 
                     if (Objects.nonNull(monitorVideoSource)) {
-                        s.setMonitorLiveUrl(SystemConstant.setStreamId(sysConfig.getConfigValue(), s.getExamRecordId(), MonitorVideoSourceEnum.valueOf(monitorVideoSource)));
-                    } else if (Objects.nonNull(monitorVideoSourceList) && monitorVideoSourceList.contains(MonitorVideoSourceEnum.CLIENT_CAMERA.name())) {
-                        s.setMonitorLiveUrl(SystemConstant.setStreamId(sysConfig.getConfigValue(), s.getExamRecordId(), MonitorVideoSourceEnum.CLIENT_CAMERA));
+                        s.setMonitorLiveUrl(SystemConstant.setStreamId(sysConfig.getConfigValue(), s.getExamRecordId(),
+                                MonitorVideoSourceEnum.valueOf(monitorVideoSource)));
+                    } else if (Objects.nonNull(monitorVideoSourceList) && monitorVideoSourceList.contains(
+                            MonitorVideoSourceEnum.CLIENT_CAMERA.name())) {
+                        s.setMonitorLiveUrl(SystemConstant.setStreamId(sysConfig.getConfigValue(), s.getExamRecordId(),
+                                MonitorVideoSourceEnum.CLIENT_CAMERA));
                     }
-                    WebsocketStatusEnum websocketStatusEnum = ExamRecordCacheUtil.getClientWebsocketStatus(s.getExamRecordId());
+                    WebsocketStatusEnum websocketStatusEnum = ExamRecordCacheUtil.getClientWebsocketStatus(
+                            s.getExamRecordId());
                     if (Objects.nonNull(websocketStatusEnum)) {
                         s.setClientWebsocketStatus(websocketStatusEnum);
                     }
@@ -199,9 +222,11 @@ public class TIeInvigilateController {
 
     @ApiOperation(value = "实时监控台视频随机列表接口")
     @RequestMapping(value = "/list/video/random", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考监控信息", response = InvigilateListVideoBean.class)})
-//    @RedisLimitAnnotation(key = "listVideoRandom", period = 1, count = 1)
-    public Result listVideoRandom(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId, @ApiParam(value = "随机数", required = true) @RequestParam Integer randomNum) {
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考监控信息", response = InvigilateListVideoBean.class) })
+    //    @RedisLimitAnnotation(key = "listVideoRandom", period = 1, count = 1)
+    public Result listVideoRandom(
+            @ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
+            @ApiParam(value = "随机数", required = true) @RequestParam Integer randomNum) {
         if (Objects.isNull(randomNum) || Objects.equals(randomNum, "")) {
             throw new BusinessException("随机数不能为空");
         }
@@ -210,27 +235,35 @@ public class TIeInvigilateController {
         //如果有监考员角色,只能查看自己所监考的考场,巡考员和管理员则可以查看全部考场
         List<String> roomCodeList = new ArrayList<>();
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
-            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(new QueryWrapper<TBExamInvigilateUser>().lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId()).eq(TBExamInvigilateUser::getExamId, examId));
+            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(
+                    new QueryWrapper<TBExamInvigilateUser>().lambda()
+                            .eq(TBExamInvigilateUser::getUserId, tbUser.getId())
+                            .eq(TBExamInvigilateUser::getExamId, examId));
             if (!CollectionUtils.isEmpty(tbExamInvigilateUserList)) {
                 roomCodeList = tbExamInvigilateUserList.stream().map(s -> s.getRoomCode()).collect(Collectors.toList());
             }
         }
-        List<InvigilateListVideoBean> invigilateListVideoBeanList = tOeExamRecordService.invigilatePageListVideoRandom(examId, roomCodeList, randomNum, tbUser.getOrgId());
+        List<InvigilateListVideoBean> invigilateListVideoBeanList = tOeExamRecordService.invigilatePageListVideoRandom(
+                examId, roomCodeList, randomNum, tbUser.getOrgId());
         if (Objects.nonNull(invigilateListVideoBeanList) && invigilateListVideoBeanList.size() > 0) {
             invigilateListVideoBeanList.forEach(s -> {
                 ExamCacheBean examCacheBean = teExamService.getExamCacheBean(s.getExamId());
                 List<String> monitorVideoSourceList = null;
-                if (Objects.nonNull(s.getMonitorVideoSource()) && !Objects.equals(s.getMonitorVideoSource().trim().replaceAll(" ", ""), "")) {
-                    monitorVideoSourceList = Arrays.asList(s.getMonitorVideoSource().trim().toUpperCase().replaceAll(" ", "").split(","));
+                if (Objects.nonNull(s.getMonitorVideoSource()) && !Objects.equals(
+                        s.getMonitorVideoSource().trim().replaceAll(" ", ""), "")) {
+                    monitorVideoSourceList = Arrays.asList(
+                            s.getMonitorVideoSource().trim().toUpperCase().replaceAll(" ", "").split(","));
                 }
                 MonitorVideoSourceEnum mainMonitorVideoSource = SystemConstant.getMainMonitor(monitorVideoSourceList);
                 SysConfig sysConfig = themisCacheService.addSysConfigCache(SystemConstant.MONITOR_CONFIG_PREFIX);
                 Optional.ofNullable(sysConfig).orElseThrow(() -> new BusinessException("未配置监控前缀"));
 
                 if (Objects.nonNull(mainMonitorVideoSource)) {
-                    s.setMonitorLiveUrl(SystemConstant.setStreamId(sysConfig.getConfigValue(), s.getExamRecordId(), mainMonitorVideoSource));
+                    s.setMonitorLiveUrl(SystemConstant.setStreamId(sysConfig.getConfigValue(), s.getExamRecordId(),
+                            mainMonitorVideoSource));
                 }
-                WebsocketStatusEnum websocketStatusEnum = ExamRecordCacheUtil.getClientWebsocketStatus(s.getExamRecordId());
+                WebsocketStatusEnum websocketStatusEnum = ExamRecordCacheUtil.getClientWebsocketStatus(
+                        s.getExamRecordId());
                 if (Objects.nonNull(websocketStatusEnum)) {
                     s.setClientWebsocketStatus(websocketStatusEnum);
                 }
@@ -244,36 +277,42 @@ public class TIeInvigilateController {
                 }
             });
         }
-        invigilateListVideoBeanList.sort(Comparator.comparing(InvigilateListVideoBean::getClientWebsocketStatus, Comparator.naturalOrder()).thenComparing(InvigilateListVideoBean::getMonitorLiveUrl, Comparator.nullsLast(Comparator.naturalOrder())));
+        invigilateListVideoBeanList.sort(
+                Comparator.comparing(InvigilateListVideoBean::getClientWebsocketStatus, Comparator.naturalOrder())
+                        .thenComparing(InvigilateListVideoBean::getMonitorLiveUrl,
+                                Comparator.nullsLast(Comparator.naturalOrder())));
         return ResultUtil.ok(invigilateListVideoBeanList);
     }
 
     @ApiOperation(value = "监考明细管理列表接口")
     @RequestMapping(value = "/history/list", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考明细信息", response = InvigilateListHistoryBean.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考明细信息", response = InvigilateListHistoryBean.class) })
     public Result historyList(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
-                              @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
-                              @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
-                              @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
-                              @ApiParam(value = "考生状态", required = false) @RequestParam(required = false) String status,
-                              @ApiParam(value = "违纪状态", required = false) @RequestParam(required = false) Integer breachStatus,
-                              @ApiParam(value = "交卷方式", required = false) @RequestParam(required = false) String finishType,
-                              @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
-                              @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
-                              @ApiParam(value = "陌生人脸min", required = false) @RequestParam(required = false) Integer minMultipleFaceCount,
-                              @ApiParam(value = "陌生人脸max", required = false) @RequestParam(required = false) Integer maxMultipleFaceCount,
-                              @ApiParam(value = "异常处理min", required = false) @RequestParam(required = false) Integer minExceptionCount,
-                              @ApiParam(value = "异常处理max", required = false) @RequestParam(required = false) Integer maxExceptionCount,
-                              @ApiParam(value = "预警量min", required = false) @RequestParam(required = false) Integer minWarningCount,
-                              @ApiParam(value = "预警量max", required = false) @RequestParam(required = false) Integer maxWarningCount,
-                              @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
-                              @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
+            @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
+            @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
+            @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
+            @ApiParam(value = "考生状态", required = false) @RequestParam(required = false) String status,
+            @ApiParam(value = "违纪状态", required = false) @RequestParam(required = false) Integer breachStatus,
+            @ApiParam(value = "交卷方式", required = false) @RequestParam(required = false) String finishType,
+            @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
+            @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
+            @ApiParam(value = "陌生人脸min", required = false) @RequestParam(required = false) Integer minMultipleFaceCount,
+            @ApiParam(value = "陌生人脸max", required = false) @RequestParam(required = false) Integer maxMultipleFaceCount,
+            @ApiParam(value = "异常处理min", required = false) @RequestParam(required = false) Integer minExceptionCount,
+            @ApiParam(value = "异常处理max", required = false) @RequestParam(required = false) Integer maxExceptionCount,
+            @ApiParam(value = "预警量min", required = false) @RequestParam(required = false) Integer minWarningCount,
+            @ApiParam(value = "预警量max", required = false) @RequestParam(required = false) Integer maxWarningCount,
+            @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
+            @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         AuthDto authDto = themisCacheService.addAccountAuthCache(tbUser.getId());
         //如果有监考员角色,只能查看自己所监考的考场,巡考员和管理员则可以查看全部考场
         List<String> roomCodeList = new ArrayList<>();
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
-            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(new QueryWrapper<TBExamInvigilateUser>().lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId()).eq(TBExamInvigilateUser::getExamId, examId));
+            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(
+                    new QueryWrapper<TBExamInvigilateUser>().lambda()
+                            .eq(TBExamInvigilateUser::getUserId, tbUser.getId())
+                            .eq(TBExamInvigilateUser::getExamId, examId));
             if (!CollectionUtils.isEmpty(tbExamInvigilateUserList)) {
                 roomCodeList = tbExamInvigilateUserList.stream().map(s -> s.getRoomCode()).collect(Collectors.toList());
             }
@@ -282,33 +321,42 @@ public class TIeInvigilateController {
             roomCodeList.clear();
             roomCodeList.add(roomCode);
         }
-        return ResultUtil.ok(tOeExamRecordService.invigilatePageListHistory(new Page<>(pageNumber, pageSize), examId, examActivityId, roomCodeList, courseCode, status, breachStatus, finishType, name, identity, minMultipleFaceCount, maxMultipleFaceCount, minExceptionCount, maxExceptionCount, minWarningCount, maxWarningCount, tbUser.getOrgId()));
+        return ResultUtil.ok(
+                tOeExamRecordService.invigilatePageListHistory(new Page<>(pageNumber, pageSize), examId, examActivityId,
+                        roomCodeList, courseCode, status, breachStatus, finishType, name, identity,
+                        minMultipleFaceCount, maxMultipleFaceCount, minExceptionCount, maxExceptionCount,
+                        minWarningCount, maxWarningCount, tbUser.getOrgId()));
     }
 
     @ApiOperation(value = "监考明细管理列表导出接口")
     @RequestMapping(value = "/history/list/export", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考明细信息", response = InvigilateListHistoryBean.class)})
-    public void historyListExport(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
-                                  @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
-                                  @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
-                                  @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
-                                  @ApiParam(value = "考生状态", required = false) @RequestParam(required = false) String status,
-                                  @ApiParam(value = "违纪状态", required = false) @RequestParam(required = false) Integer breachStatus,
-                                  @ApiParam(value = "交卷方式", required = false) @RequestParam(required = false) String finishType,
-                                  @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
-                                  @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
-                                  @ApiParam(value = "陌生人脸min", required = false) @RequestParam(required = false) Integer minMultipleFaceCount,
-                                  @ApiParam(value = "陌生人脸max", required = false) @RequestParam(required = false) Integer maxMultipleFaceCount,
-                                  @ApiParam(value = "异常处理min", required = false) @RequestParam(required = false) Integer minExceptionCount,
-                                  @ApiParam(value = "异常处理max", required = false) @RequestParam(required = false) Integer maxExceptionCount,
-                                  @ApiParam(value = "预警量min", required = false) @RequestParam(required = false) Integer minWarningCount,
-                                  @ApiParam(value = "预警量max", required = false) @RequestParam(required = false) Integer maxWarningCount) throws Exception {
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考明细信息", response = InvigilateListHistoryBean.class) })
+    public void historyListExport(
+            @ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
+            @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
+            @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
+            @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
+            @ApiParam(value = "考生状态", required = false) @RequestParam(required = false) String status,
+            @ApiParam(value = "违纪状态", required = false) @RequestParam(required = false) Integer breachStatus,
+            @ApiParam(value = "交卷方式", required = false) @RequestParam(required = false) String finishType,
+            @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
+            @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
+            @ApiParam(value = "陌生人脸min", required = false) @RequestParam(required = false) Integer minMultipleFaceCount,
+            @ApiParam(value = "陌生人脸max", required = false) @RequestParam(required = false) Integer maxMultipleFaceCount,
+            @ApiParam(value = "异常处理min", required = false) @RequestParam(required = false) Integer minExceptionCount,
+            @ApiParam(value = "异常处理max", required = false) @RequestParam(required = false) Integer maxExceptionCount,
+            @ApiParam(value = "预警量min", required = false) @RequestParam(required = false) Integer minWarningCount,
+            @ApiParam(value = "预警量max", required = false) @RequestParam(required = false) Integer maxWarningCount)
+            throws Exception {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         AuthDto authDto = themisCacheService.addAccountAuthCache(tbUser.getId());
         //如果有监考员角色,只能查看自己所监考的考场,巡考员和管理员则可以查看全部考场
         List<String> roomCodeList = new ArrayList<>();
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
-            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(new QueryWrapper<TBExamInvigilateUser>().lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId()).eq(TBExamInvigilateUser::getExamId, examId));
+            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(
+                    new QueryWrapper<TBExamInvigilateUser>().lambda()
+                            .eq(TBExamInvigilateUser::getUserId, tbUser.getId())
+                            .eq(TBExamInvigilateUser::getExamId, examId));
             if (!CollectionUtils.isEmpty(tbExamInvigilateUserList)) {
                 roomCodeList = tbExamInvigilateUserList.stream().map(s -> s.getRoomCode()).collect(Collectors.toList());
             }
@@ -317,13 +365,17 @@ public class TIeInvigilateController {
             roomCodeList.clear();
             roomCodeList.add(roomCode);
         }
-        List<InvigilateListHistoryBean> invigilateListHistoryBeanList = tOeExamRecordService.invigilatePageListHistoryExport(examId, examActivityId, roomCodeList, courseCode, status, breachStatus, finishType, name, identity, minMultipleFaceCount, maxMultipleFaceCount, minExceptionCount, maxExceptionCount, minWarningCount, maxWarningCount, tbUser.getOrgId());
-        ExportUtils.exportEXCEL("监考明细", InvigilateListHistoryBean.class, invigilateListHistoryBeanList, ServletUtil.getResponse());
+        List<InvigilateListHistoryBean> invigilateListHistoryBeanList = tOeExamRecordService.invigilatePageListHistoryExport(
+                examId, examActivityId, roomCodeList, courseCode, status, breachStatus, finishType, name, identity,
+                minMultipleFaceCount, maxMultipleFaceCount, minExceptionCount, maxExceptionCount, minWarningCount,
+                maxWarningCount, tbUser.getOrgId());
+        ExportUtils.exportEXCEL("监考明细", InvigilateListHistoryBean.class, invigilateListHistoryBeanList,
+                ServletUtil.getResponse());
     }
 
     @ApiOperation(value = "实时监控台列表明细接口")
     @RequestMapping(value = "/list/detail", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考监控信息", response = InvigilateListDetailBean.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考监控信息", response = InvigilateListDetailBean.class) })
     public Result listDetail(@ApiParam(value = "考试记录id") @RequestParam Long examRecordId) {
         if (Objects.isNull(examRecordId) || Objects.equals(examRecordId, "")) {
             throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
@@ -341,20 +393,31 @@ public class TIeInvigilateController {
             status = tOeExamRecord.getStatus();
             breachStatus = Objects.isNull(tOeExamRecord.getBreachStatus()) ? 1 : tOeExamRecord.getBreachStatus();
             warningCount = Objects.nonNull(tOeExamRecord.getWarningCount()) ? tOeExamRecord.getWarningCount() : 0;
-            warningMultipleFaceCount = Objects.nonNull(tOeExamRecord.getWarningMultipleFaceCount()) ? tOeExamRecord.getWarningMultipleFaceCount() : 0;
+            warningMultipleFaceCount = Objects.nonNull(tOeExamRecord.getWarningMultipleFaceCount()) ?
+                    tOeExamRecord.getWarningMultipleFaceCount() :
+                    0;
             exceptionCount = Objects.nonNull(tOeExamRecord.getExceptionCount()) ? tOeExamRecord.getExceptionCount() : 0;
         } else {
             examStudentId = ExamRecordCacheUtil.getExamStudentId(examRecordId);
             examActivityId = ExamRecordCacheUtil.getExamActivityId(examRecordId);
             status = ExamRecordCacheUtil.getStatus(examRecordId);
-            breachStatus = Objects.isNull(ExamRecordCacheUtil.getBreachStatus(examRecordId)) ? 1 : ExamRecordCacheUtil.getBreachStatus(examRecordId);
-            warningCount = Objects.isNull(ExamRecordCacheUtil.getWarningCount(examRecordId)) ? 0 : ExamRecordCacheUtil.getWarningCount(examRecordId);
-            warningMultipleFaceCount = Objects.isNull(ExamRecordCacheUtil.getWarningMultipleFaceCount(examRecordId)) ? 0 : ExamRecordCacheUtil.getWarningMultipleFaceCount(examRecordId);
-            exceptionCount = Objects.isNull(ExamRecordCacheUtil.getExceptionCount(examRecordId)) ? 0 : ExamRecordCacheUtil.getExceptionCount(examRecordId);
+            breachStatus = Objects.isNull(ExamRecordCacheUtil.getBreachStatus(examRecordId)) ?
+                    1 :
+                    ExamRecordCacheUtil.getBreachStatus(examRecordId);
+            warningCount = Objects.isNull(ExamRecordCacheUtil.getWarningCount(examRecordId)) ?
+                    0 :
+                    ExamRecordCacheUtil.getWarningCount(examRecordId);
+            warningMultipleFaceCount = Objects.isNull(ExamRecordCacheUtil.getWarningMultipleFaceCount(examRecordId)) ?
+                    0 :
+                    ExamRecordCacheUtil.getWarningMultipleFaceCount(examRecordId);
+            exceptionCount = Objects.isNull(ExamRecordCacheUtil.getExceptionCount(examRecordId)) ?
+                    0 :
+                    ExamRecordCacheUtil.getExceptionCount(examRecordId);
         }
         ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
         TEStudentCacheDto teStudent = themisCacheService.addStudentAccountCache(examStudentCacheBean.getStudentId());
-        String basePhotoPath = ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + teStudent.getBasePhotoPath();
+        String basePhotoPath =
+                ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + teStudent.getBasePhotoPath();
         String identity = examStudentCacheBean.getIdentity();
         String examStudentName = examStudentCacheBean.getName();
         String courseNameCode = examStudentCacheBean.getCourseName() + "(" + examStudentCacheBean.getCourseCode() + ")";
@@ -363,32 +426,40 @@ public class TIeInvigilateController {
         ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(examActivityId);
         ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
 
-        IPage<TBExamInvigilateUserDto> tbExamInvigilateUserDtoIPage = tbExamInvigilateUserService.examInvigilateUserQuery(new Page<>(SystemConstant.PAGE_NUMBER_MIN, SystemConstant.SELECT_PAGE_SIZE_MAX), examId, roomCode, null, teStudent.getOrgId());
+        IPage<TBExamInvigilateUserDto> tbExamInvigilateUserDtoIPage = tbExamInvigilateUserService.examInvigilateUserQuery(
+                new Page<>(SystemConstant.PAGE_NUMBER_MIN, SystemConstant.SELECT_PAGE_SIZE_MAX), examId, roomCode, null,
+                teStudent.getOrgId());
         String invigilateUsers = null;
-        if (Objects.nonNull(tbExamInvigilateUserDtoIPage) && !CollectionUtils.isEmpty(tbExamInvigilateUserDtoIPage.getRecords())) {
+        if (Objects.nonNull(tbExamInvigilateUserDtoIPage) && !CollectionUtils.isEmpty(
+                tbExamInvigilateUserDtoIPage.getRecords())) {
             invigilateUsers = tbExamInvigilateUserDtoIPage.getRecords().get(0).getName();
         }
 
+        TEExamMarkLog teExamMarkLog = teExamMarkLogService.findByExamRecordId(examRecordId);
         InvigilateListDetailBean invigilateListDetailBean = new InvigilateListDetailBean(examCacheBean.getName(),
                 examActivityCacheBean.getCode(), examId, examActivityId, examStudentId, examRecordId, identity,
                 examStudentName, courseNameCode, status, roomCode, roomName, breachStatus, basePhotoPath,
-                examActivityCacheBean.getStartTime(), examActivityCacheBean.getFinishTime(), invigilateUsers, examStudentCacheBean.getClassNo());
+                examActivityCacheBean.getStartTime(), examActivityCacheBean.getFinishTime(), invigilateUsers,
+                examStudentCacheBean.getClassNo(), Objects.nonNull(teExamMarkLog) ? teExamMarkLog.getStatus() : null);
 
         //考生轨迹
         QueryWrapper<TEExamStudentLog> teExamStudentLogQueryWrapper = new QueryWrapper<>();
         teExamStudentLogQueryWrapper.lambda().eq(TEExamStudentLog::getExamStudentId, examStudentId)
                 .eq(TEExamStudentLog::getExamRecordId, examRecordId)
-//                .ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_HANDLE.name())
-//                .ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_REVOKE.name())
+                //                .ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_HANDLE.name())
+                //                .ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_REVOKE.name())
                 .orderByAsc(TEExamStudentLog::getCreateTime);
         //                .and(w -> w.ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_HANDLE.name()).or().ne(TEExamStudentLog::getType, SystemOperationEnum.BREACH_REVOKE.name()));
         List<TEExamStudentLog> teExamStudentLogList = teExamStudentLogService.list(teExamStudentLogQueryWrapper);
 
         //加入文本和语音消息轨迹
-        List<TIeExamInvigilateNotice> tIeExamInvigilateNoticeList = tIeExamInvigilateNoticeService.queryNoticeByExamRecordId(examRecordId);
+        List<TIeExamInvigilateNotice> tIeExamInvigilateNoticeList = tIeExamInvigilateNoticeService.queryNoticeByExamRecordId(
+                examRecordId);
         if (!CollectionUtils.isEmpty(tIeExamInvigilateNoticeList)) {
             for (TIeExamInvigilateNotice t : tIeExamInvigilateNoticeList) {
-                teExamStudentLogList.add(new TEExamStudentLog(teStudent.getId(), examStudentId, t.getExamRecordId(), t.getType(), t.getContent(), t.getFormUserId(), t.getFormUserName(), t.getSendTime()));
+                teExamStudentLogList.add(
+                        new TEExamStudentLog(teStudent.getId(), examStudentId, t.getExamRecordId(), t.getType(),
+                                t.getContent(), t.getFormUserId(), t.getFormUserName(), t.getSendTime()));
             }
         }
 
@@ -396,7 +467,9 @@ public class TIeInvigilateController {
         List<TIeExamMediaLog> tIeExamMediaLogList = tIeExamMediaLogService.queryMediaByExamRecordId(examRecordId);
         if (!CollectionUtils.isEmpty(tIeExamMediaLogList)) {
             for (TIeExamMediaLog t : tIeExamMediaLogList) {
-                teExamStudentLogList.add(new TEExamStudentLog(teStudent.getId(), examStudentId, t.getExamRecordId(), t.getType(), t.getContent(), t.getCreateTime()));
+                teExamStudentLogList.add(
+                        new TEExamStudentLog(teStudent.getId(), examStudentId, t.getExamRecordId(), t.getType(),
+                                t.getContent(), t.getCreateTime()));
             }
         }
         Collections.sort(teExamStudentLogList);
@@ -418,7 +491,8 @@ public class TIeInvigilateController {
             tOeExamRecordService.updateWarningUnreadByDb(examRecordId, 0);
             tOeExamRecordService.updateWarningUnreadCache(examRecordId, 0, false);
 
-            teExamSummaryService.updateExamSummaryWarningUnread(examId, examActivityId, examStudentCacheBean.getRoomCode());
+            teExamSummaryService.updateExamSummaryWarningUnread(examId, examActivityId,
+                    examStudentCacheBean.getRoomCode());
             themisCacheService.updateExamSummaryCache(examId);
             themisCacheService.updateExamSummaryCache(examId, examActivityId);
             themisCacheService.updateExamSummaryCache(examId, examActivityId, examStudentCacheBean.getRoomCode());
@@ -431,16 +505,17 @@ public class TIeInvigilateController {
 
     @ApiOperation(value = "强制/手动交卷接口")
     @RequestMapping(value = "/finish", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class) })
     public Result finish(@ApiJsonObject(name = "invigilateFinish", value = {
             @ApiJsonProperty(key = "examRecordId", type = "long", example = "1", description = "考试记录id"),
-            @ApiJsonProperty(key = "type", description = "收卷类型,手动/强制")
-    }) @ApiParam(value = "考试记录信息", required = true) @RequestBody Map<String, Object> mapParameter) {
-        if (Objects.isNull(mapParameter.get(SystemConstant.EXAM_RECORD_ID)) || Objects.equals(mapParameter.get(SystemConstant.EXAM_RECORD_ID), "")) {
+            @ApiJsonProperty(key = "type", description = "收卷类型,手动/强制") }) @ApiParam(value = "考试记录信息", required = true) @RequestBody Map<String, Object> mapParameter) {
+        if (Objects.isNull(mapParameter.get(SystemConstant.EXAM_RECORD_ID)) || Objects.equals(
+                mapParameter.get(SystemConstant.EXAM_RECORD_ID), "")) {
             throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
         }
         List<String> recordIdList = (List<String>) mapParameter.get(SystemConstant.EXAM_RECORD_ID);
-        if (Objects.isNull(mapParameter.get(SystemConstant.TYPE)) || Objects.equals(mapParameter.get(SystemConstant.TYPE), "")) {
+        if (Objects.isNull(mapParameter.get(SystemConstant.TYPE)) || Objects.equals(
+                mapParameter.get(SystemConstant.TYPE), "")) {
             throw new BusinessException(ExceptionResultEnum.FINISH_TYPE_IS_NULL);
         }
         if (recordIdList.size() > 0) {
@@ -451,7 +526,9 @@ public class TIeInvigilateController {
             if (Objects.equals(type, FinishTypeEnum.INTERRUPT)) {
                 mqTagEnum = MqTagEnum.OE_MONITOR_FINISH;
                 recordIdList.forEach(s -> {
-                    Integer breachStatus = Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(Long.parseLong(s))) ? ExamRecordCacheUtil.getBreachStatus(Long.parseLong(s)) : 1;
+                    Integer breachStatus = Objects.nonNull(ExamRecordCacheUtil.getBreachStatus(Long.parseLong(s))) ?
+                            ExamRecordCacheUtil.getBreachStatus(Long.parseLong(s)) :
+                            1;
                     if (Objects.nonNull(breachStatus) && breachStatus.intValue() == 1) {
                         throw new BusinessException("只有标记为违纪的考生才能强制交卷");
                     }
@@ -459,11 +536,12 @@ public class TIeInvigilateController {
             } else if (Objects.equals(type, FinishTypeEnum.BREACH)) {
                 mqTagEnum = MqTagEnum.OE_WARNING_FINISH;
             }
-//            else {
-//                mqTagEnum = MqTagEnum.OE_HARD_FINISH;
-//            }
+            //            else {
+            //                mqTagEnum = MqTagEnum.OE_HARD_FINISH;
+            //            }
             if (Objects.nonNull(mqTagEnum)) {
-                MqDto mqDto = new MqDto(mqUtil.getTopic(), mqTagEnum.name(), JacksonUtil.parseJson(recordIdList), mqTagEnum, String.valueOf(tbUser.getId()), mapParameter, tbUser.getName());
+                MqDto mqDto = new MqDto(mqUtil.getTopic(), mqTagEnum.name(), JacksonUtil.parseJson(recordIdList),
+                        mqTagEnum, String.valueOf(tbUser.getId()), mapParameter, tbUser.getName());
                 mqDtoService.assembleSendAsyncOrderMsg(mqDto);
             }
             //发送mq给客户端强制收卷end
@@ -473,28 +551,31 @@ public class TIeInvigilateController {
 
     @ApiOperation(value = "在线巡考列表接口")
     @RequestMapping(value = "/patrol/list", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考监控信息", response = InvigilateListPatrolBean.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考监控信息", response = InvigilateListPatrolBean.class) })
     public Result patrolList(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
-                             @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
-                             @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
-                             @ApiParam(value = "考生状态", required = false) @RequestParam(required = false) String status,
-                             @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
-                             @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
-                             @ApiParam(value = "陌生人脸min", required = false) @RequestParam(required = false) Integer minMultipleFaceCount,
-                             @ApiParam(value = "陌生人脸max", required = false) @RequestParam(required = false) Integer maxMultipleFaceCount,
-                             @ApiParam(value = "异常处理min", required = false) @RequestParam(required = false) Integer minExceptionCount,
-                             @ApiParam(value = "异常处理max", required = false) @RequestParam(required = false) Integer maxExceptionCount,
-                             @ApiParam(value = "预警量min", required = false) @RequestParam(required = false) Integer minWarningCount,
-                             @ApiParam(value = "预警量max", required = false) @RequestParam(required = false) Integer maxWarningCount,
-                             @ApiParam(value = "客户端网络通信状态", required = false) @RequestParam(required = false) String clientWebsocketStatus,
-                             @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
-                             @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
+            @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
+            @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
+            @ApiParam(value = "考生状态", required = false) @RequestParam(required = false) String status,
+            @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
+            @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
+            @ApiParam(value = "陌生人脸min", required = false) @RequestParam(required = false) Integer minMultipleFaceCount,
+            @ApiParam(value = "陌生人脸max", required = false) @RequestParam(required = false) Integer maxMultipleFaceCount,
+            @ApiParam(value = "异常处理min", required = false) @RequestParam(required = false) Integer minExceptionCount,
+            @ApiParam(value = "异常处理max", required = false) @RequestParam(required = false) Integer maxExceptionCount,
+            @ApiParam(value = "预警量min", required = false) @RequestParam(required = false) Integer minWarningCount,
+            @ApiParam(value = "预警量max", required = false) @RequestParam(required = false) Integer maxWarningCount,
+            @ApiParam(value = "客户端网络通信状态", required = false) @RequestParam(required = false) String clientWebsocketStatus,
+            @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
+            @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         AuthDto authDto = themisCacheService.addAccountAuthCache(tbUser.getId());
         //如果有监考员角色,只能查看自己所监考的考场,巡考员和管理员则可以查看全部考场
         List<String> roomCodeList = new ArrayList<>();
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
-            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(new QueryWrapper<TBExamInvigilateUser>().lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId()).eq(TBExamInvigilateUser::getExamId, examId));
+            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(
+                    new QueryWrapper<TBExamInvigilateUser>().lambda()
+                            .eq(TBExamInvigilateUser::getUserId, tbUser.getId())
+                            .eq(TBExamInvigilateUser::getExamId, examId));
             if (!CollectionUtils.isEmpty(tbExamInvigilateUserList)) {
                 roomCodeList = tbExamInvigilateUserList.stream().map(s -> s.getRoomCode()).collect(Collectors.toList());
             }
@@ -503,7 +584,10 @@ public class TIeInvigilateController {
             roomCodeList.clear();
             roomCodeList.add(roomCode);
         }
-        IPage<InvigilateListPatrolBean> invigilateListPatrolBeanIPage = tOeExamRecordService.invigilatePagePatrolList(new Page<>(pageNumber, pageSize), examId, examActivityId, roomCodeList, status, name, identity, minMultipleFaceCount, maxMultipleFaceCount, minExceptionCount, maxExceptionCount, minWarningCount, maxWarningCount, clientWebsocketStatus, tbUser.getOrgId());
+        IPage<InvigilateListPatrolBean> invigilateListPatrolBeanIPage = tOeExamRecordService.invigilatePagePatrolList(
+                new Page<>(pageNumber, pageSize), examId, examActivityId, roomCodeList, status, name, identity,
+                minMultipleFaceCount, maxMultipleFaceCount, minExceptionCount, maxExceptionCount, minWarningCount,
+                maxWarningCount, clientWebsocketStatus, tbUser.getOrgId());
         if (Objects.nonNull(invigilateListPatrolBeanIPage)) {
             List<InvigilateListPatrolBean> invigilateListPatrolBeanList = invigilateListPatrolBeanIPage.getRecords();
             if (Objects.nonNull(invigilateListPatrolBeanList) && invigilateListPatrolBeanList.size() > 0) {
@@ -513,7 +597,8 @@ public class TIeInvigilateController {
                 }
                 ExamCacheBean finalExamCacheBean = examCacheBean;
                 invigilateListPatrolBeanList.forEach(s -> {
-                    WebsocketStatusEnum websocketStatusEnum = ExamRecordCacheUtil.getClientWebsocketStatus(s.getExamRecordId());
+                    WebsocketStatusEnum websocketStatusEnum = ExamRecordCacheUtil.getClientWebsocketStatus(
+                            s.getExamRecordId());
                     if (Objects.nonNull(websocketStatusEnum)) {
                         s.setClientWebsocketStatus(websocketStatusEnum);
                     }
@@ -529,23 +614,27 @@ public class TIeInvigilateController {
 
     @ApiOperation(value = "进度查询列表接口")
     @RequestMapping(value = "/progress/list", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考进度信息", response = InvigilateListProgressBean.class)})
-    public Result progressList(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
-                               @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
-                               @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
-                               @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
-                               @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
-                               @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
-                               @ApiParam(value = "状态", required = false) @RequestParam(required = false) Integer status,
-                               @ApiParam(value = "违纪状态,0:违纪,1:正常", required = false) @RequestParam(required = false) Integer breachStatus,
-                               @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
-                               @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考进度信息", response = InvigilateListProgressBean.class) })
+    public Result progressList(
+            @ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
+            @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
+            @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
+            @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
+            @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
+            @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
+            @ApiParam(value = "状态", required = false) @RequestParam(required = false) Integer status,
+            @ApiParam(value = "违纪状态,0:违纪,1:正常", required = false) @RequestParam(required = false) Integer breachStatus,
+            @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) int pageNumber,
+            @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) int pageSize) {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         AuthDto authDto = themisCacheService.addAccountAuthCache(tbUser.getId());
         //如果有监考员角色,只能查看自己所监考的考场,巡考员和管理员则可以查看全部考场
         List<String> roomCodeList = new ArrayList<>();
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
-            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(new QueryWrapper<TBExamInvigilateUser>().lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId()).eq(TBExamInvigilateUser::getExamId, examId));
+            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(
+                    new QueryWrapper<TBExamInvigilateUser>().lambda()
+                            .eq(TBExamInvigilateUser::getUserId, tbUser.getId())
+                            .eq(TBExamInvigilateUser::getExamId, examId));
             if (!CollectionUtils.isEmpty(tbExamInvigilateUserList)) {
                 roomCodeList = tbExamInvigilateUserList.stream().map(s -> s.getRoomCode()).collect(Collectors.toList());
             }
@@ -554,26 +643,32 @@ public class TIeInvigilateController {
             roomCodeList.clear();
             roomCodeList.add(roomCode);
         }
-        return ResultUtil.ok(tOeExamRecordService.invigilatePageProgressList(new Page<>(pageNumber, pageSize), examId, examActivityId, roomCodeList, courseCode, name, identity, status, tbUser.getOrgId(), breachStatus));
+        return ResultUtil.ok(tOeExamRecordService.invigilatePageProgressList(new Page<>(pageNumber, pageSize), examId,
+                examActivityId, roomCodeList, courseCode, name, identity, status, tbUser.getOrgId(), breachStatus));
     }
 
     @ApiOperation(value = "进度查询列表导出接口")
     @RequestMapping(value = "/progress/list/export", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考进度信息", response = InvigilateListProgressBean.class)})
-    public void progressListExport(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
-                                   @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
-                                   @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
-                                   @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
-                                   @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
-                                   @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
-                                   @ApiParam(value = "状态", required = false) @RequestParam(required = false) Integer status,
-                                   @ApiParam(value = "违纪状态,0:违纪,1:正常", required = false) @RequestParam(required = false) Integer breachStatus) throws Exception {
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考进度信息", response = InvigilateListProgressBean.class) })
+    public void progressListExport(
+            @ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long examId,
+            @ApiParam(value = "考试场次id", required = false) @RequestParam(required = false) Long examActivityId,
+            @ApiParam(value = "虚拟考场代码", required = false) @RequestParam(required = false) String roomCode,
+            @ApiParam(value = "科目代码", required = false) @RequestParam(required = false) String courseCode,
+            @ApiParam(value = "姓名", required = false) @RequestParam(required = false) String name,
+            @ApiParam(value = "证件号", required = false) @RequestParam(required = false) String identity,
+            @ApiParam(value = "状态", required = false) @RequestParam(required = false) Integer status,
+            @ApiParam(value = "违纪状态,0:违纪,1:正常", required = false) @RequestParam(required = false) Integer breachStatus)
+            throws Exception {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         AuthDto authDto = themisCacheService.addAccountAuthCache(tbUser.getId());
         //如果有监考员角色,只能查看自己所监考的考场,巡考员和管理员则可以查看全部考场
         List<String> roomCodeList = new ArrayList<>();
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
-            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(new QueryWrapper<TBExamInvigilateUser>().lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId()).eq(TBExamInvigilateUser::getExamId, examId));
+            List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(
+                    new QueryWrapper<TBExamInvigilateUser>().lambda()
+                            .eq(TBExamInvigilateUser::getUserId, tbUser.getId())
+                            .eq(TBExamInvigilateUser::getExamId, examId));
             if (!CollectionUtils.isEmpty(tbExamInvigilateUserList)) {
                 roomCodeList = tbExamInvigilateUserList.stream().map(s -> s.getRoomCode()).collect(Collectors.toList());
             }
@@ -582,36 +677,41 @@ public class TIeInvigilateController {
             roomCodeList.clear();
             roomCodeList.add(roomCode);
         }
-        List<InvigilateListProgressExcelBean> invigilateListProgressExcelBeanList = tOeExamRecordService.invigilatePageProgressListExport(examId, examActivityId, roomCodeList, courseCode, name, identity, status, tbUser.getOrgId(), breachStatus);
+        List<InvigilateListProgressExcelBean> invigilateListProgressExcelBeanList = tOeExamRecordService.invigilatePageProgressListExport(
+                examId, examActivityId, roomCodeList, courseCode, name, identity, status, tbUser.getOrgId(),
+                breachStatus);
         if (!CollectionUtils.isEmpty(invigilateListProgressExcelBeanList)) {
             for (InvigilateListProgressExcelBean i : invigilateListProgressExcelBeanList) {
                 i.setCourseName(i.getCourseName() + "(" + i.getCourseCode() + ")");
                 i.setRoomName(i.getRoomName() + "(" + i.getRoomCode() + ")");
             }
         }
-        ExportUtils.exportEXCEL("进度信息", InvigilateListProgressExcelBean.class, invigilateListProgressExcelBeanList, ServletUtil.getResponse());
+        ExportUtils.exportEXCEL("进度信息", InvigilateListProgressExcelBean.class, invigilateListProgressExcelBeanList,
+                ServletUtil.getResponse());
     }
 
     @ApiOperation(value = "违纪处理接口")
     @RequestMapping(value = "/breach", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class) })
     public Result breach(@ApiJsonObject(name = "invigilateBreach", value = {
             @ApiJsonProperty(key = "examRecordId", type = "long", example = "1", description = "考试记录id", required = true),
             @ApiJsonProperty(key = "type", description = "违规类型", required = true),
             @ApiJsonProperty(key = "description", description = "描述", required = true),
             @ApiJsonProperty(key = "status", type = "int", example = "1", description = "新建/撤销", required = true),
-            @ApiJsonProperty(key = "breachLogId", type = "long", example = "1", description = "违纪日志id", required = true)
-    }) @ApiParam(value = "考试记录信息", required = true) @RequestBody Map<String, Object> mapParameter) {
-        if (Objects.isNull(mapParameter.get(SystemConstant.EXAM_RECORD_ID)) || Objects.equals(mapParameter.get(SystemConstant.EXAM_RECORD_ID), "")) {
+            @ApiJsonProperty(key = "breachLogId", type = "long", example = "1", description = "违纪日志id", required = true) }) @ApiParam(value = "考试记录信息", required = true) @RequestBody Map<String, Object> mapParameter) {
+        if (Objects.isNull(mapParameter.get(SystemConstant.EXAM_RECORD_ID)) || Objects.equals(
+                mapParameter.get(SystemConstant.EXAM_RECORD_ID), "")) {
             throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
         }
-        if (Objects.isNull(mapParameter.get(SystemConstant.TYPE)) || Objects.equals(mapParameter.get(SystemConstant.TYPE), "")) {
+        if (Objects.isNull(mapParameter.get(SystemConstant.TYPE)) || Objects.equals(
+                mapParameter.get(SystemConstant.TYPE), "")) {
             throw new BusinessException(ExceptionResultEnum.BREACH_TYPE_IS_NULL);
         }
         if (Objects.isNull(mapParameter.get("description")) || Objects.equals(mapParameter.get("description"), "")) {
             throw new BusinessException(ExceptionResultEnum.BREACH_DESC_IS_NULL);
         }
-        if (Objects.isNull(mapParameter.get(SystemConstant.STATUS)) || Objects.equals(mapParameter.get(SystemConstant.STATUS), "")) {
+        if (Objects.isNull(mapParameter.get(SystemConstant.STATUS)) || Objects.equals(
+                mapParameter.get(SystemConstant.STATUS), "")) {
             throw new BusinessException(ExceptionResultEnum.BREACH_STATUS_IS_NULL);
         }
         teExamBreachLogService.breachLogic(mapParameter);
@@ -619,40 +719,70 @@ public class TIeInvigilateController {
         return ResultUtil.ok(true);
     }
 
+    @ApiOperation(value = "重点标记接口")
+    @RequestMapping(value = "/mark", method = RequestMethod.POST)
+    @ApiResponses({ @ApiResponse(code = 200, message = "标记成功", response = Result.class) })
+    @Transactional
+    public Result mark(@ApiParam(value = "考试记录id", required = true) @RequestParam Long examRecordId,
+            @ApiParam(value = "状态,MARK:标记,UN_MARK:撤销", required = true) @RequestParam MarkEnum status) {
+        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
+        TEExamMarkLog teExamMarkLog = teExamMarkLogService.findByExamRecordId(examRecordId);
+        TOeExamRecord tOeExamRecord = tOeExamRecordService.getById(examRecordId);
+        Objects.requireNonNull(tOeExamRecord, ExceptionResultEnum.NOT_FOUND_EXAM_RECORD.getMessage());
+        if (tOeExamRecord.getStatus() == ExamRecordStatusEnum.FINISHED
+                || tOeExamRecord.getStatus() == ExamRecordStatusEnum.PERSISTED) {
+            throw new BusinessException("考试已结束无法标记");
+        }
+        if (Objects.isNull(teExamMarkLog)) {
+            Objects.requireNonNull(tOeExamRecord, ExceptionResultEnum.NOT_FOUND_EXAM_RECORD.getMessage());
+            teExamMarkLog = new TEExamMarkLog(tOeExamRecord, tbUser.getId());
+        } else {
+            if (teExamMarkLog.getStatus() == status) {
+                throw new BusinessException("已是" + status.getTitle() + "状态,无需修改");
+            } else {
+                teExamMarkLog.setStatus(status);
+                teExamMarkLog.updateInfo(tbUser.getId());
+            }
+        }
+        return ResultUtil.ok(teExamMarkLogService.saveOrUpdate(teExamMarkLog));
+    }
+
     @ApiOperation(value = "监考消息通知接口")
     @RequestMapping(value = "/notice", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class) })
     public Result notice(@ApiJsonObject(name = "invigilateNotice", value = {
             @ApiJsonProperty(key = "examRecordId", type = "long", example = "1", description = "考试记录id", required = true),
             @ApiJsonProperty(key = "type", description = "消息类型,text/audio", required = true),
-            @ApiJsonProperty(key = "content", description = "消息内容", required = true)
-    }) @ApiParam(value = "考试记录信息", required = true) @RequestBody Map<String, Object> mapParameter) {
-        if (Objects.isNull(mapParameter.get(SystemConstant.EXAM_RECORD_ID)) || Objects.equals(mapParameter.get(SystemConstant.EXAM_RECORD_ID), "")) {
+            @ApiJsonProperty(key = "content", description = "消息内容", required = true) }) @ApiParam(value = "考试记录信息", required = true) @RequestBody Map<String, Object> mapParameter) {
+        if (Objects.isNull(mapParameter.get(SystemConstant.EXAM_RECORD_ID)) || Objects.equals(
+                mapParameter.get(SystemConstant.EXAM_RECORD_ID), "")) {
             throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
         }
         Long recordId = Long.parseLong(String.valueOf(mapParameter.get(SystemConstant.EXAM_RECORD_ID)));
-        if (Objects.isNull(mapParameter.get(SystemConstant.TYPE)) || Objects.equals(mapParameter.get(SystemConstant.TYPE), "")) {
+        if (Objects.isNull(mapParameter.get(SystemConstant.TYPE)) || Objects.equals(
+                mapParameter.get(SystemConstant.TYPE), "")) {
             throw new BusinessException(ExceptionResultEnum.MESSAGE_TYPE_IS_NULL);
         }
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         //发送mq给客户端监考消息start
         mapParameter.put(SystemConstant.FORM_USER_ID, tbUser.getId());
-        MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.OE_IM_CLUSTERING.name(), recordId, MqTagEnum.OE_IM_CLUSTERING, String.valueOf(recordId), mapParameter, tbUser.getName());
+        MqDto mqDto = new MqDto(mqUtil.getTopic(), MqTagEnum.OE_IM_CLUSTERING.name(), recordId,
+                MqTagEnum.OE_IM_CLUSTERING, String.valueOf(recordId), mapParameter, tbUser.getName());
         mqDtoService.assembleSendAsyncOrderMsg(mqDto);
         //发送mq给客户端监考消息end
 
-//        //发送mq给客户端监考强制活体验证start
-//        mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.OE_LIVENESS_VERIFY.name(), recordId, MqTagEnum.OE_LIVENESS_VERIFY, String.valueOf(recordId), mapParameter, tbUser.getName());
-//        mqDtoService.assembleSendOneOrderMsg(mqDto);
-//        //发送mq给客户端监考强制活体验证end
+        //        //发送mq给客户端监考强制活体验证start
+        //        mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.OE_LIVENESS_VERIFY.name(), recordId, MqTagEnum.OE_LIVENESS_VERIFY, String.valueOf(recordId), mapParameter, tbUser.getName());
+        //        mqDtoService.assembleSendOneOrderMsg(mqDto);
+        //        //发送mq给客户端监考强制活体验证end
         return ResultUtil.ok(true);
     }
 
     @ApiOperation(value = "结束监考接口")
     @RequestMapping(value = "/exam/finish", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class) })
     public Result examFinish(@ApiParam(value = "考试id", required = true) @RequestParam Long examId,
-                             @ApiParam(value = "监考状态", required = true) @RequestParam InvigilateMonitorStatusEnum status) {
+            @ApiParam(value = "监考状态", required = true) @RequestParam InvigilateMonitorStatusEnum status) {
         Optional.ofNullable(examId).orElseThrow(() -> new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL));
         Optional.ofNullable(status).orElseThrow(() -> new BusinessException("监考状态不能为空"));
 
@@ -675,13 +805,20 @@ public class TIeInvigilateController {
     private String getRemainTime(ExamModeEnum mode, Long recordId) {
         String remainTime = null;
         Integer forceFinish = ExamRecordCacheUtil.getForceFinish(recordId);
-        Integer maxDurationSeconds = Objects.isNull(ExamRecordCacheUtil.getMaxDurationSeconds(recordId)) ? 0 : ExamRecordCacheUtil.getMaxDurationSeconds(recordId);
-        Integer durationSeconds = Objects.isNull(ExamRecordCacheUtil.getDurationSeconds(recordId)) ? 0 : ExamRecordCacheUtil.getDurationSeconds(recordId);
-        Long endTime = Objects.isNull(ExamRecordCacheUtil.getEndTime(recordId)) ? 0 : ExamRecordCacheUtil.getEndTime(recordId);
+        Integer maxDurationSeconds = Objects.isNull(ExamRecordCacheUtil.getMaxDurationSeconds(recordId)) ?
+                0 :
+                ExamRecordCacheUtil.getMaxDurationSeconds(recordId);
+        Integer durationSeconds = Objects.isNull(ExamRecordCacheUtil.getDurationSeconds(recordId)) ?
+                0 :
+                ExamRecordCacheUtil.getDurationSeconds(recordId);
+        Long endTime = Objects.isNull(ExamRecordCacheUtil.getEndTime(recordId)) ?
+                0 :
+                ExamRecordCacheUtil.getEndTime(recordId);
         if (Objects.nonNull(mode) && Objects.equals(mode, ExamModeEnum.ANYTIME)) {
             Long diffTime = (maxDurationSeconds.longValue() - durationSeconds.longValue()) * 1000;
             remainTime = diffTime.intValue() == 0 ? "00:00:00" : SystemConstant.getRemainTime(diffTime);
-        } else if (Objects.nonNull(mode) && Objects.equals(mode, ExamModeEnum.TOGETHER) && Objects.nonNull(forceFinish) && forceFinish.intValue() == 1) {
+        } else if (Objects.nonNull(mode) && Objects.equals(mode, ExamModeEnum.TOGETHER) && Objects.nonNull(forceFinish)
+                && forceFinish.intValue() == 1) {
             Long diffTime = endTime - System.currentTimeMillis();
             remainTime = diffTime.intValue() == 0 ? "00:00:00" : SystemConstant.getRemainTime(diffTime);
         } else {

+ 13 - 0
themis-business/src/main/java/com/qmth/themis/business/base/BaseEntity.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.qmth.themis.business.util.UidUtil;
 import io.swagger.annotations.ApiModelProperty;
 
 import java.io.Serializable;
@@ -17,6 +18,7 @@ import java.io.Serializable;
  * @Date: 2019/12/6
  */
 public class BaseEntity implements Serializable {
+
     private static final long serialVersionUID = 1L;
 
     @JsonSerialize(using = ToStringSerializer.class)
@@ -42,6 +44,17 @@ public class BaseEntity implements Serializable {
     @ApiModelProperty(value = "修改时间")
     private Long updateTime;
 
+    public void insertInfo(Long userId) {
+        this.id = UidUtil.nextId();
+        this.createId = userId;
+        this.createTime = System.currentTimeMillis();
+    }
+
+    public void updateInfo(Long userId) {
+        this.updateId = userId;
+        this.updateTime = System.currentTimeMillis();
+    }
+
     public static long getSerialVersionUID() {
         return serialVersionUID;
     }

+ 17 - 4
themis-business/src/main/java/com/qmth/themis/business/bean/admin/InvigilateListDetailBean.java

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.qmth.themis.business.entity.TEExamStudentLog;
 import com.qmth.themis.business.enums.ExamRecordStatusEnum;
+import com.qmth.themis.business.enums.MarkEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -102,6 +103,17 @@ public class InvigilateListDetailBean implements Serializable {
     @ApiModelProperty(name = "班级")
     private String classNo;
 
+    @ApiModelProperty(name = "标记状态,MARK:标记,UN_MARK:撤销")
+    private MarkEnum markStatus;
+
+    public MarkEnum getMarkStatus() {
+        return markStatus;
+    }
+
+    public void setMarkStatus(MarkEnum markStatus) {
+        this.markStatus = markStatus;
+    }
+
     public String getClassNo() {
         return classNo;
     }
@@ -167,10 +179,10 @@ public class InvigilateListDetailBean implements Serializable {
     }
 
     public InvigilateListDetailBean(String examName, String examActivityCode, Long examId, Long examActivityId,
-                                    Long examStudentId, Long examRecordId, String identity, String examStudentName,
-                                    String courseNameCode, ExamRecordStatusEnum statusCode, String roomCode, String roomName,
-                                    Integer breachStatus, String basePhotoPath, Long examActivityStartTime,
-                                    Long examActivityEndTime, String invigilateUsers, String classNo) {
+            Long examStudentId, Long examRecordId, String identity, String examStudentName, String courseNameCode,
+            ExamRecordStatusEnum statusCode, String roomCode, String roomName, Integer breachStatus,
+            String basePhotoPath, Long examActivityStartTime, Long examActivityEndTime, String invigilateUsers,
+            String classNo, MarkEnum markStatus) {
         this.examName = examName;
         this.examActivityCode = examActivityCode;
         this.examId = examId;
@@ -189,6 +201,7 @@ public class InvigilateListDetailBean implements Serializable {
         this.examActivityEndTime = examActivityEndTime;
         this.invigilateUsers = invigilateUsers;
         this.classNo = classNo;
+        this.markStatus = markStatus;
     }
 
     public String getMonitorRecord() {

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

@@ -0,0 +1,16 @@
+package com.qmth.themis.business.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qmth.themis.business.entity.TEExamMarkLog;
+
+/**
+ * <p>
+ * 考生重点标记表 Mapper 接口
+ * </p>
+ *
+ * @author wangliang
+ * @since 2024-07-22
+ */
+public interface TEExamMarkLogMapper extends BaseMapper<TEExamMarkLog> {
+
+}

+ 124 - 152
themis-business/src/main/java/com/qmth/themis/business/dao/TOeExamRecordMapper.java

@@ -46,20 +46,16 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     public IPage<InvigilateListVideoBean> invigilatePageListVideo(IPage<Map> iPage, @Param("examId") Long examId,
-                                                                  @Param("examActivityId") Long examActivityId,
-                                                                  @Param("roomCodeList") List<String> roomCodeList,
-                                                                  @Param("paperDownload") Integer paperDownload,
-                                                                  @Param("status") String status,
-                                                                  @Param("name") String name,
-                                                                  @Param("identity") String identity,
-                                                                  @Param("minWarningCount") Integer minWarningCount,
-                                                                  @Param("maxWarningCount") Integer maxWarningCount,
-                                                                  @Param("clientWebsocketStatus") String clientWebsocketStatus,
-                                                                  @Param("cameraMonitorStatus") String cameraMonitorStatus,
-                                                                  @Param("screenMonitorStatus") String screenMonitorStatus,
-                                                                  @Param("mobileFirstMonitorStatus") String mobileFirstMonitorStatus,
-                                                                  @Param("mobileSecondMonitorStatus") String mobileSecondMonitorStatus,
-                                                                  @Param("orgId") Long orgId);
+            @Param("examActivityId") Long examActivityId, @Param("roomCodeList") List<String> roomCodeList,
+            @Param("paperDownload") Integer paperDownload, @Param("status") String status, @Param("name") String name,
+            @Param("identity") String identity, @Param("minWarningCount") Integer minWarningCount,
+            @Param("maxWarningCount") Integer maxWarningCount,
+            @Param("clientWebsocketStatus") String clientWebsocketStatus,
+            @Param("cameraMonitorStatus") String cameraMonitorStatus,
+            @Param("screenMonitorStatus") String screenMonitorStatus,
+            @Param("mobileFirstMonitorStatus") String mobileFirstMonitorStatus,
+            @Param("mobileSecondMonitorStatus") String mobileSecondMonitorStatus,
+            @Param("markStatus") String markStatus, @Param("orgId") Long orgId);
 
     /**
      * 实时监控台视频随机列表
@@ -70,7 +66,9 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param orgId
      * @return
      */
-    public List<InvigilateListVideoBean> invigilatePageListVideoRandom(@Param("examId") Long examId, @Param("roomCodeList") List<String> roomCodeList, @Param("randomNum") Integer randomNum, @Param("orgId") Long orgId);
+    public List<InvigilateListVideoBean> invigilatePageListVideoRandom(@Param("examId") Long examId,
+            @Param("roomCodeList") List<String> roomCodeList, @Param("randomNum") Integer randomNum,
+            @Param("orgId") Long orgId);
 
     /**
      * 查询在线巡考列表
@@ -93,19 +91,14 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     public IPage<InvigilateListPatrolBean> invigilatePagePatrolList(IPage<Map> iPage, @Param("examId") Long examId,
-                                                                    @Param("examActivityId") Long examActivityId,
-                                                                    @Param("roomCodeList") List<String> roomCodeList,
-                                                                    @Param("status") String status,
-                                                                    @Param("name") String name,
-                                                                    @Param("identity") String identity,
-                                                                    @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
-                                                                    @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
-                                                                    @Param("minExceptionCount") Integer minExceptionCount,
-                                                                    @Param("maxExceptionCount") Integer maxExceptionCount,
-                                                                    @Param("minWarningCount") Integer minWarningCount,
-                                                                    @Param("maxWarningCount") Integer maxWarningCount,
-                                                                    @Param("clientWebsocketStatus") String clientWebsocketStatus,
-                                                                    @Param("orgId") Long orgId);
+            @Param("examActivityId") Long examActivityId, @Param("roomCodeList") List<String> roomCodeList,
+            @Param("status") String status, @Param("name") String name, @Param("identity") String identity,
+            @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
+            @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
+            @Param("minExceptionCount") Integer minExceptionCount,
+            @Param("maxExceptionCount") Integer maxExceptionCount, @Param("minWarningCount") Integer minWarningCount,
+            @Param("maxWarningCount") Integer maxWarningCount,
+            @Param("clientWebsocketStatus") String clientWebsocketStatus, @Param("orgId") Long orgId);
 
     /**
      * 预警提醒列表
@@ -127,18 +120,13 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     public IPage<InvigilateListWarningBean> invigilatePageWarningList(IPage<Map> iPage, @Param("examId") Long examId,
-                                                                      @Param("examActivityId") Long examActivityId,
-                                                                      @Param("roomCodeList") List<String> roomCodeList,
-                                                                      @Param("approveStatus") Integer approveStatus,
-                                                                      @Param("name") String name,
-                                                                      @Param("identity") String identity,
-                                                                      @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
-                                                                      @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
-                                                                      @Param("minExceptionCount") Integer minExceptionCount,
-                                                                      @Param("maxExceptionCount") Integer maxExceptionCount,
-                                                                      @Param("minWarningCount") Integer minWarningCount,
-                                                                      @Param("maxWarningCount") Integer maxWarningCount,
-                                                                      @Param("orgId") Long orgId);
+            @Param("examActivityId") Long examActivityId, @Param("roomCodeList") List<String> roomCodeList,
+            @Param("approveStatus") Integer approveStatus, @Param("name") String name,
+            @Param("identity") String identity, @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
+            @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
+            @Param("minExceptionCount") Integer minExceptionCount,
+            @Param("maxExceptionCount") Integer maxExceptionCount, @Param("minWarningCount") Integer minWarningCount,
+            @Param("maxWarningCount") Integer maxWarningCount, @Param("orgId") Long orgId);
 
     /**
      * 预警提醒清除未阅列表
@@ -158,19 +146,14 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param orgId
      * @return
      */
-    public Integer approveStatusListUpdate(@Param("examId") Long examId,
-                                           @Param("examActivityId") Long examActivityId,
-                                           @Param("roomCodeList") List<String> roomCodeList,
-                                           @Param("approveStatus") Integer approveStatus,
-                                           @Param("name") String name,
-                                           @Param("identity") String identity,
-                                           @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
-                                           @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
-                                           @Param("minExceptionCount") Integer minExceptionCount,
-                                           @Param("maxExceptionCount") Integer maxExceptionCount,
-                                           @Param("minWarningCount") Integer minWarningCount,
-                                           @Param("maxWarningCount") Integer maxWarningCount,
-                                           @Param("orgId") Long orgId);
+    public Integer approveStatusListUpdate(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId,
+            @Param("roomCodeList") List<String> roomCodeList, @Param("approveStatus") Integer approveStatus,
+            @Param("name") String name, @Param("identity") String identity,
+            @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
+            @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
+            @Param("minExceptionCount") Integer minExceptionCount,
+            @Param("maxExceptionCount") Integer maxExceptionCount, @Param("minWarningCount") Integer minWarningCount,
+            @Param("maxWarningCount") Integer maxWarningCount, @Param("orgId") Long orgId);
 
     /**
      * 进度查询列表
@@ -188,14 +171,9 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     public IPage<InvigilateListProgressBean> invigilatePageProgressList(IPage<Map> iPage, @Param("examId") Long examId,
-                                                                        @Param("examActivityId") Long examActivityId,
-                                                                        @Param("roomCodeList") List<String> roomCodeList,
-                                                                        @Param("courseCode") String courseCode,
-                                                                        @Param("name") String name,
-                                                                        @Param("identity") String identity,
-                                                                        @Param("status") Integer status,
-                                                                        @Param("orgId") Long orgId,
-                                                                        @Param("breachStatus") Integer breachStatus);
+            @Param("examActivityId") Long examActivityId, @Param("roomCodeList") List<String> roomCodeList,
+            @Param("courseCode") String courseCode, @Param("name") String name, @Param("identity") String identity,
+            @Param("status") Integer status, @Param("orgId") Long orgId, @Param("breachStatus") Integer breachStatus);
 
     /**
      * 进度查询列表导出
@@ -212,14 +190,9 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     public List<InvigilateListProgressExcelBean> invigilatePageProgressListExport(@Param("examId") Long examId,
-                                                                                  @Param("examActivityId") Long examActivityId,
-                                                                                  @Param("roomCodeList") List<String> roomCodeList,
-                                                                                  @Param("courseCode") String courseCode,
-                                                                                  @Param("name") String name,
-                                                                                  @Param("identity") String identity,
-                                                                                  @Param("status") Integer status,
-                                                                                  @Param("orgId") Long orgId,
-                                                                                  @Param("breachStatus") Integer breachStatus);
+            @Param("examActivityId") Long examActivityId, @Param("roomCodeList") List<String> roomCodeList,
+            @Param("courseCode") String courseCode, @Param("name") String name, @Param("identity") String identity,
+            @Param("status") Integer status, @Param("orgId") Long orgId, @Param("breachStatus") Integer breachStatus);
 
     /**
      * 监考明细管理列表
@@ -244,21 +217,15 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     public IPage<InvigilateListHistoryBean> invigilatePageListHistory(IPage<Map> iPage, @Param("examId") Long examId,
-                                                                      @Param("examActivityId") Long examActivityId,
-                                                                      @Param("roomCodeList") List<String> roomCodeList,
-                                                                      @Param("courseCode") String courseCode,
-                                                                      @Param("status") String status,
-                                                                      @Param("breachStatus") Integer breachStatus,
-                                                                      @Param("finishType") String finishType,
-                                                                      @Param("name") String name,
-                                                                      @Param("identity") String identity,
-                                                                      @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
-                                                                      @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
-                                                                      @Param("minExceptionCount") Integer minExceptionCount,
-                                                                      @Param("maxExceptionCount") Integer maxExceptionCount,
-                                                                      @Param("minWarningCount") Integer minWarningCount,
-                                                                      @Param("maxWarningCount") Integer maxWarningCount,
-                                                                      @Param("orgId") Long orgId);
+            @Param("examActivityId") Long examActivityId, @Param("roomCodeList") List<String> roomCodeList,
+            @Param("courseCode") String courseCode, @Param("status") String status,
+            @Param("breachStatus") Integer breachStatus, @Param("finishType") String finishType,
+            @Param("name") String name, @Param("identity") String identity,
+            @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
+            @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
+            @Param("minExceptionCount") Integer minExceptionCount,
+            @Param("maxExceptionCount") Integer maxExceptionCount, @Param("minWarningCount") Integer minWarningCount,
+            @Param("maxWarningCount") Integer maxWarningCount, @Param("orgId") Long orgId);
 
     /**
      * 监考明细管理列表导出
@@ -282,25 +249,20 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     public List<InvigilateListHistoryBean> invigilatePageListHistoryExport(@Param("examId") Long examId,
-                                                                           @Param("examActivityId") Long examActivityId,
-                                                                           @Param("roomCodeList") List<String> roomCodeList,
-                                                                           @Param("courseCode") String courseCode,
-                                                                           @Param("status") String status,
-                                                                           @Param("breachStatus") Integer breachStatus,
-                                                                           @Param("finishType") String finishType,
-                                                                           @Param("name") String name,
-                                                                           @Param("identity") String identity,
-                                                                           @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
-                                                                           @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
-                                                                           @Param("minExceptionCount") Integer minExceptionCount,
-                                                                           @Param("maxExceptionCount") Integer maxExceptionCount,
-                                                                           @Param("minWarningCount") Integer minWarningCount,
-                                                                           @Param("maxWarningCount") Integer maxWarningCount,
-                                                                           @Param("orgId") Long orgId);
+            @Param("examActivityId") Long examActivityId, @Param("roomCodeList") List<String> roomCodeList,
+            @Param("courseCode") String courseCode, @Param("status") String status,
+            @Param("breachStatus") Integer breachStatus, @Param("finishType") String finishType,
+            @Param("name") String name, @Param("identity") String identity,
+            @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
+            @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
+            @Param("minExceptionCount") Integer minExceptionCount,
+            @Param("maxExceptionCount") Integer maxExceptionCount, @Param("minWarningCount") Integer minWarningCount,
+            @Param("maxWarningCount") Integer maxWarningCount, @Param("orgId") Long orgId);
 
     @SuppressWarnings("MybatisXMapperMethodInspection")
-    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);
+    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);
 
     public Long getCountByExamId(@Param("examId") Long examId);
 
@@ -317,7 +279,8 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param userId
      * @return
      */
-    public List<InvigilateListPatrolReportBean> patrolReport(@Param("orgId") Long orgId, @Param("examId") Long examId, @Param("userId") Long userId);
+    public List<InvigilateListPatrolReportBean> patrolReport(@Param("orgId") Long orgId, @Param("examId") Long examId,
+            @Param("userId") Long userId);
 
     public TOeExamRecord findOneByExamId(@Param("examId") Long examId, @Param("status") String status);
 
@@ -387,7 +350,9 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param minusTime
      * @return
      */
-    public List<TimeScaleDataResult> getWarnTrend(@Param("orgId") Long orgId, @Param("timeData") List<String> timeData, @Param("currentTime") Long currentTime, @Param("interval") Integer interval, @Param("minusTime") Long minusTime);
+    public List<TimeScaleDataResult> getWarnTrend(@Param("orgId") Long orgId, @Param("timeData") List<String> timeData,
+            @Param("currentTime") Long currentTime, @Param("interval") Integer interval,
+            @Param("minusTime") Long minusTime);
 
     public void updateHasAnswerFile(@Param("recordId") Long recordId, @Param("hasAnswerFile") Integer hasAnswerFile);
 
@@ -400,7 +365,8 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param examStudentId
      * @return
      */
-    public List<TOeExamRecord> findMaxObjectiveScore(@Param("examId") Long examId, @Param("examStudentId") Long examStudentId, @Param("examStudentBreachPush") Boolean examStudentBreachPush);
+    public List<TOeExamRecord> findMaxObjectiveScore(@Param("examId") Long examId,
+            @Param("examStudentId") Long examStudentId, @Param("examStudentBreachPush") Boolean examStudentBreachPush);
 
     /**
      * 根据orgId查找 在线人数/已待考/考试人数
@@ -417,7 +383,8 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param roomCodeSet
      * @return
      */
-    List<CountStopBean> findByStopInfo(@Param("examId") Long examId, @Param("roomCodeSet") Set<String> roomCodeSet, @Param("examActivityId") Long examActivityId);
+    List<CountStopBean> findByStopInfo(@Param("examId") Long examId, @Param("roomCodeSet") Set<String> roomCodeSet,
+            @Param("examActivityId") Long examActivityId);
 
     /**
      * 查找在线消息
@@ -427,7 +394,8 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param examActivityId
      * @return
      */
-    List<Integer> findByOnlineInfo(@Param("examId") Long examId, @Param("roomCodeSet") Set<String> roomCodeSet, @Param("examActivityId") Long examActivityId);
+    List<Integer> findByOnlineInfo(@Param("examId") Long examId, @Param("roomCodeSet") Set<String> roomCodeSet,
+            @Param("examActivityId") Long examActivityId);
 
     /**
      * 管理员报表
@@ -439,7 +407,9 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param courseCode
      * @return
      */
-    List<Integer> findByViewAdmin(@Param("orgId") Long orgId, @Param("examId") Long examId, @Param("examActivityId") Long examActivityId, @Param("roomCode") String roomCode, @Param("courseCode") String courseCode, @Param("monitorStatus") String monitorStatus);
+    List<Integer> findByViewAdmin(@Param("orgId") Long orgId, @Param("examId") Long examId,
+            @Param("examActivityId") Long examActivityId, @Param("roomCode") String roomCode,
+            @Param("courseCode") String courseCode, @Param("monitorStatus") String monitorStatus);
 
     /**
      * 考试明细查询接口
@@ -454,14 +424,10 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param identity
      * @return
      */
-    public IPage<ExamRecordDetailBean> examRecordDetailQuery(IPage<Map> iPage,
-                                                             @Param("examId") Long examId,
-                                                             @Param("examActivityId") Long examActivityId,
-                                                             @Param("courseCode") String courseCode,
-                                                             @Param("roomCode") String roomCode,
-                                                             @Param("finishType") String finishType,
-                                                             @Param("name") String name,
-                                                             @Param("identity") String identity);
+    public IPage<ExamRecordDetailBean> examRecordDetailQuery(IPage<Map> iPage, @Param("examId") Long examId,
+            @Param("examActivityId") Long examActivityId, @Param("courseCode") String courseCode,
+            @Param("roomCode") String roomCode, @Param("finishType") String finishType, @Param("name") String name,
+            @Param("identity") String identity);
 
     /**
      * 考试明细查询接口
@@ -471,7 +437,8 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param identityList
      * @return
      */
-    public List<String> examRecordDetailListQuery(@Param("examId") Long examId, @Param("courseCodeList") List<String> courseCodeList, @Param("identityList") List<String> identityList);
+    public List<String> examRecordDetailListQuery(@Param("examId") Long examId,
+            @Param("courseCodeList") List<String> courseCodeList, @Param("identityList") List<String> identityList);
 
     /**
      * 获取时间尺度
@@ -481,7 +448,8 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     @SuppressWarnings("MybatisXMapperMethodInspection")
-    public Map<String, String> getTimeScale(@Param("timeSize") List<Integer> timeSize, @Param("currentDate") String currentDate);
+    public Map<String, String> getTimeScale(@Param("timeSize") List<Integer> timeSize,
+            @Param("currentDate") String currentDate);
 
     /**
      * 获取时间尺度数据
@@ -492,7 +460,9 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param minusTime
      * @return
      */
-    public List<TimeOnlineDataResult> getTimeOnlineData(@Param("orgId") Long orgId, @Param("timeData") List<String> timeData, @Param("currentTime") Long currentTime, @Param("minusTime") Long minusTime);
+    public List<TimeOnlineDataResult> getTimeOnlineData(@Param("orgId") Long orgId,
+            @Param("timeData") List<String> timeData, @Param("currentTime") Long currentTime,
+            @Param("minusTime") Long minusTime);
 
     /**
      * 查询没有视频地址的考试记录
@@ -509,7 +479,8 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param examActivityId
      * @return
      */
-    public List<TOeExamRecord> findExamRecordByExamIdAndExamActivityId(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId);
+    public List<TOeExamRecord> findExamRecordByExamIdAndExamActivityId(@Param("examId") Long examId,
+            @Param("examActivityId") Long examActivityId);
 
     /**
      * 根据考试批次id或考试场次id查找
@@ -518,7 +489,8 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param examActivityId
      * @return
      */
-    public Integer findByExamIdOrExamActivityIdCount(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId);
+    public Integer findByExamIdOrExamActivityIdCount(@Param("examId") Long examId,
+            @Param("examActivityId") Long examActivityId);
 
     /**
      * 获取所有待阅卷的考试记录
@@ -529,7 +501,9 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param examStudentBreachPush
      * @return
      */
-    public List<TOeExamRecord> findExamRecordNeedMarkAll(@Param("examId") Long examId, @Param("examPaperIdSet") Set<Long> examPaperIdSet, @Param("many") Boolean many, @Param("examStudentBreachPush") Boolean examStudentBreachPush);
+    public List<TOeExamRecord> findExamRecordNeedMarkAll(@Param("examId") Long examId,
+            @Param("examPaperIdSet") Set<Long> examPaperIdSet, @Param("many") Boolean many,
+            @Param("examStudentBreachPush") Boolean examStudentBreachPush);
 
     /**
      * 修正作答记录缓存到数据库
@@ -539,7 +513,8 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param status
      * @return
      */
-    public List<TOeExamRecord> persistedAnswerBatch(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId, @Param("status") String status);
+    public List<TOeExamRecord> persistedAnswerBatch(@Param("examId") Long examId,
+            @Param("examActivityId") Long examActivityId, @Param("status") String status);
 
     /**
      * 清除考试缓存
@@ -550,26 +525,26 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
     @SuppressWarnings("MybatisXMapperMethodInspection")
     public List<Map> cleanExamFirstPrepareCache(@Param("examIds") Set<Long> examIds);
 
-//    /**
-//     * 数据统计
-//     *
-//     * @return
-//     */
-//    List<Long> dataCount();
+    //    /**
+    //     * 数据统计
+    //     *
+    //     * @return
+    //     */
+    //    List<Long> dataCount();
 
-//    /**
-//     * 机构数据统计
-//     *
-//     * @return
-//     */
-//    List<OrgDataCountBean> orgDataCount();
+    //    /**
+    //     * 机构数据统计
+    //     *
+    //     * @return
+    //     */
+    //    List<OrgDataCountBean> orgDataCount();
 
-//    /**
-//     * 地图数据统计
-//     *
-//     * @return
-//     */
-//    List<MapDataCountBean> mapDataCount();
+    //    /**
+    //     * 地图数据统计
+    //     *
+    //     * @return
+    //     */
+    //    List<MapDataCountBean> mapDataCount();
 
     /**
      * 根据id更新预警数量
@@ -604,17 +579,13 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      */
     List<TOeExamRecord> findExamRecordByWarning(@Param("examId") Long examId,
-                                                @Param("examActivityId") Long examActivityId,
-                                                @Param("roomCodeList") List<String> roomCodeList,
-                                                @Param("name") String name,
-                                                @Param("identity") String identity,
-                                                @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
-                                                @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
-                                                @Param("minExceptionCount") Integer minExceptionCount,
-                                                @Param("maxExceptionCount") Integer maxExceptionCount,
-                                                @Param("minWarningCount") Integer minWarningCount,
-                                                @Param("maxWarningCount") Integer maxWarningCount,
-                                                @Param("orgId") Long orgId);
+            @Param("examActivityId") Long examActivityId, @Param("roomCodeList") List<String> roomCodeList,
+            @Param("name") String name, @Param("identity") String identity,
+            @Param("minMultipleFaceCount") Integer minMultipleFaceCount,
+            @Param("maxMultipleFaceCount") Integer maxMultipleFaceCount,
+            @Param("minExceptionCount") Integer minExceptionCount,
+            @Param("maxExceptionCount") Integer maxExceptionCount, @Param("minWarningCount") Integer minWarningCount,
+            @Param("maxWarningCount") Integer maxWarningCount, @Param("orgId") Long orgId);
 
     /**
      * 查找完成人数
@@ -624,5 +595,6 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @param roomCode
      * @return
      */
-    Integer findExamRecordByFinish(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId, @Param("roomCode") String roomCode);
+    Integer findExamRecordByFinish(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId,
+            @Param("roomCode") String roomCode);
 }

+ 122 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TEExamMarkLog.java

@@ -0,0 +1,122 @@
+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.base.BaseEntity;
+import com.qmth.themis.business.enums.MarkEnum;
+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 2024-07-22
+ */
+@ApiModel(value = "TEExamMarkLog对象", description = "考生重点标记表")
+public class TEExamMarkLog extends BaseEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long id;
+
+    @ApiModelProperty(value = "考试ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examId;
+
+    @ApiModelProperty(value = "场次ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examActivityId;
+
+    @ApiModelProperty(value = "考试记录ID")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examRecordId;
+
+    @ApiModelProperty(value = "考生id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examStudentId;
+
+    @ApiModelProperty(value = "状态,MARK:标记,UN_MARK:撤销")
+    private MarkEnum status;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    public TEExamMarkLog() {
+
+    }
+
+    public TEExamMarkLog(TOeExamRecord tOeExamRecord, Long userId) {
+        insertInfo(userId);
+        this.examId = tOeExamRecord.getExamId();
+        this.examActivityId = tOeExamRecord.getExamActivityId();
+        this.examRecordId = tOeExamRecord.getId();
+        this.examStudentId = tOeExamRecord.getExamStudentId();
+        this.status = MarkEnum.MARK;
+    }
+
+    @Override
+    public Long getId() {
+        return id;
+    }
+
+    @Override
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public Long getExamActivityId() {
+        return examActivityId;
+    }
+
+    public void setExamActivityId(Long examActivityId) {
+        this.examActivityId = examActivityId;
+    }
+
+    public Long getExamRecordId() {
+        return examRecordId;
+    }
+
+    public void setExamRecordId(Long examRecordId) {
+        this.examRecordId = examRecordId;
+    }
+
+    public Long getExamStudentId() {
+        return examStudentId;
+    }
+
+    public void setExamStudentId(Long examStudentId) {
+        this.examStudentId = examStudentId;
+    }
+
+    public MarkEnum getStatus() {
+        return status;
+    }
+
+    public void setStatus(MarkEnum status) {
+        this.status = status;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+}

+ 25 - 0
themis-business/src/main/java/com/qmth/themis/business/enums/MarkEnum.java

@@ -0,0 +1,25 @@
+package com.qmth.themis.business.enums;
+
+/**
+ * @Description: 题目类型 enum
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2020/10/21
+ */
+public enum MarkEnum {
+
+    MARK("标记"),
+
+    UN_MARK("撤销");
+
+    private String title;
+
+    private MarkEnum(String title) {
+        this.title = title;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+}

+ 23 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TEExamMarkLogService.java

@@ -0,0 +1,23 @@
+package com.qmth.themis.business.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.themis.business.entity.TEExamMarkLog;
+
+/**
+ * <p>
+ * 考生重点标记表 服务类
+ * </p>
+ *
+ * @author wangliang
+ * @since 2024-07-22
+ */
+public interface TEExamMarkLogService extends IService<TEExamMarkLog> {
+
+    /**
+     * 根据考试记录id查找标记信息
+     *
+     * @param examRecordId
+     * @return
+     */
+    TEExamMarkLog findByExamRecordId(Long examRecordId);
+}

+ 2 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TOeExamRecordService.java

@@ -102,6 +102,7 @@ public interface TOeExamRecordService extends IService<TOeExamRecord> {
      * @param screenMonitorStatus
      * @param mobileFirstMonitorStatus
      * @param mobileSecondMonitorStatus
+     * @param markStatus
      * @param orgId
      * @return
      */
@@ -119,6 +120,7 @@ public interface TOeExamRecordService extends IService<TOeExamRecord> {
                                                                   String screenMonitorStatus,
                                                                   String mobileFirstMonitorStatus,
                                                                   String mobileSecondMonitorStatus,
+                                                                  MarkEnum markStatus,
                                                                   Long orgId);
 
     /**

+ 32 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamMarkLogServiceImpl.java

@@ -0,0 +1,32 @@
+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.dao.TEExamMarkLogMapper;
+import com.qmth.themis.business.entity.TEExamMarkLog;
+import com.qmth.themis.business.service.TEExamMarkLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 考生重点标记表 服务实现类
+ * </p>
+ *
+ * @author wangliang
+ * @since 2024-07-22
+ */
+@Service
+public class TEExamMarkLogServiceImpl extends ServiceImpl<TEExamMarkLogMapper, TEExamMarkLog>
+        implements TEExamMarkLogService {
+
+    /**
+     * 根据考试记录id查找标记信息
+     *
+     * @param examRecordId
+     * @return
+     */
+    @Override
+    public TEExamMarkLog findByExamRecordId(Long examRecordId) {
+        return this.getOne(new QueryWrapper<TEExamMarkLog>().lambda().eq(TEExamMarkLog::getExamRecordId, examRecordId));
+    }
+}

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 357 - 312
themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java


+ 26 - 0
themis-business/src/main/resources/db/log/1.3.0.log

@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS `t_e_exam_mark_log`;
+CREATE TABLE `t_e_exam_mark_log` (
+  `id` bigint NOT NULL COMMENT '主键',
+  `exam_id` bigint NOT NULL COMMENT '考试ID',
+  `exam_activity_id` bigint NOT NULL COMMENT '场次ID',
+  `exam_record_id` bigint NOT NULL COMMENT '考试记录ID',
+  `exam_student_id` bigint NOT NULL COMMENT '考生id',
+  `status` varchar(30) DEFAULT NULL COMMENT '状态,MARK:标记,UN_MARK:撤销',
+  `remark` mediumtext COMMENT '备注',
+  `create_time` bigint DEFAULT NULL COMMENT '创建时间',
+  `create_id` bigint DEFAULT NULL COMMENT '创建人',
+  `update_time` bigint DEFAULT NULL COMMENT '更新时间',
+  `update_id` bigint DEFAULT NULL COMMENT '更新人',
+  PRIMARY KEY (`id`),
+    KEY `t_e_exam_mark_log_exam_record_id_IDX` (`exam_record_id`,`exam_id`,`exam_activity_id`,`exam_student_id`,`status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考生重点标记表';
+
+INSERT INTO t_b_privilege
+(id, name, url, `type`, parent_id, `sequence`, remark, create_time)
+VALUES(210, '重点标记接口', '/api/admin/invigilate/mark', 'LINK', 10, 12, NULL, 1600932652000);
+INSERT INTO t_b_role_privilege
+(id, role_code, privilege_id)
+VALUES(260, 'ADMIN', 210);
+INSERT INTO t_b_role_privilege
+(id, role_code, privilege_id)
+VALUES(261, 'INVIGILATE', 210);

+ 5 - 0
themis-business/src/main/resources/mapper/TEExamMarkLogMapper.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.TEExamMarkLogMapper">
+
+</mapper>

+ 3 - 0
themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml

@@ -68,6 +68,9 @@
         left join t_e_exam_activity teea on teea.id = s.exam_activity_id
         left join t_e_student tes on s.student_id = tes.id
         left join t_oe_exam_record toer on toer.id = s.current_record_id
+        <if test="markStatus != null and markStatus != '' and markStatus == 'MARK'">
+            join t_e_exam_mark_log teeml on teeml.exam_record_id = toer.id and teeml.status = #{markStatus}
+        </if>
         WHERE 1 = 1
         <choose>
             <when test="status != null and status != '' and status == 'UN_FINISH'">

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно