Explorar el Código

Merge branch 'dev'
111

wangliang hace 4 años
padre
commit
ecfddd9c01
Se han modificado 40 ficheros con 604 adiciones y 147 borrados
  1. 2 1
      themis-backend/src/main/java/com/qmth/themis/backend/api/SysController.java
  2. 2 2
      themis-backend/src/main/java/com/qmth/themis/backend/api/TBExamInvigilateUserController.java
  3. 8 17
      themis-backend/src/main/java/com/qmth/themis/backend/api/TEExamController.java
  4. 68 14
      themis-backend/src/main/java/com/qmth/themis/backend/api/TIeInvigilateCallMobileController.java
  5. 14 0
      themis-backend/src/main/java/com/qmth/themis/backend/api/TIeReportController.java
  6. 1 1
      themis-backend/src/main/resources/application.properties
  7. 105 0
      themis-business/src/main/java/com/qmth/themis/business/bean/backend/ExamViewCountListBean.java
  8. 33 10
      themis-business/src/main/java/com/qmth/themis/business/bean/backend/InvigilateListBean.java
  9. 11 0
      themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java
  10. 2 10
      themis-business/src/main/java/com/qmth/themis/business/dao/TBExamInvigilateUserMapper.java
  11. 2 1
      themis-business/src/main/java/com/qmth/themis/business/dao/TEExamMapper.java
  12. 17 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TEExamStudentMapper.java
  13. 3 2
      themis-business/src/main/java/com/qmth/themis/business/dao/TIeExamInvigilateCallMapper.java
  14. 1 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TOeExamRecordMapper.java
  15. 9 22
      themis-business/src/main/java/com/qmth/themis/business/dto/ExamPropCountDto.java
  16. 24 2
      themis-business/src/main/java/com/qmth/themis/business/dto/response/TBExamInvigilateUserDto.java
  17. 16 2
      themis-business/src/main/java/com/qmth/themis/business/entity/TBExamInvigilateUser.java
  18. 12 0
      themis-business/src/main/java/com/qmth/themis/business/entity/TOeExamRecord.java
  19. 2 10
      themis-business/src/main/java/com/qmth/themis/business/service/TBExamInvigilateUserService.java
  20. 2 1
      themis-business/src/main/java/com/qmth/themis/business/service/TEExamService.java
  21. 10 0
      themis-business/src/main/java/com/qmth/themis/business/service/TEExamStudentService.java
  22. 3 2
      themis-business/src/main/java/com/qmth/themis/business/service/TIeExamInvigilateCallService.java
  23. 5 0
      themis-business/src/main/java/com/qmth/themis/business/service/TIeReportService.java
  24. 3 14
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TBExamInvigilateUserServiceImpl.java
  25. 3 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamActivityServiceImpl.java
  26. 3 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamCourseServiceImpl.java
  27. 3 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamPaperServiceImpl.java
  28. 3 2
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java
  29. 16 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamStudentServiceImpl.java
  30. 11 2
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TIeExamInvigilateCallServiceImpl.java
  31. 72 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TIeReportServiceImpl.java
  32. 1 1
      themis-business/src/main/java/com/qmth/themis/business/templete/service/impl/TempleteLogicServiceImpl.java
  33. 16 0
      themis-business/src/main/resources/db/init.sql
  34. 11 15
      themis-business/src/main/resources/mapper/TBExamInvigilateUserMapper.xml
  35. 13 1
      themis-business/src/main/resources/mapper/TEExamMapper.xml
  36. 53 0
      themis-business/src/main/resources/mapper/TEExamStudentMapper.xml
  37. 4 3
      themis-business/src/main/resources/mapper/TIeExamInvigilateCallMapper.xml
  38. 23 12
      themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml
  39. 6 0
      themis-exam/src/main/java/com/qmth/themis/exam/api/TEStudentController.java
  40. 11 0
      themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java

+ 2 - 1
themis-backend/src/main/java/com/qmth/themis/backend/api/SysController.java

@@ -272,7 +272,7 @@ public class SysController {
     @RequestMapping(value = "/examRoom/query", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "角色信息", response = RoomCodeQueryDto.class)})
     public Result examRoomQuery(@ApiParam(value = "考场名称", required = false) @RequestParam(required = false) String roomName) {
-        return ResultUtil.ok(tbExamInvigilateUserService.examRoomQuery(roomName));
+        return ResultUtil.ok(teExamStudentService.examRoomQuery(roomName));
     }
 
     @ApiOperation(value = "根据权限获取场次和考场接口")
@@ -290,6 +290,7 @@ public class SysController {
         //首先查询当前用户所要监控的roomCode
         QueryWrapper<TBExamInvigilateUser> examInvigilateUserQueryWrapper = new QueryWrapper<>();
         examInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getOrgId, tbUser.getOrgId())
+                .eq(TBExamInvigilateUser::getExamId, examId)
                 .eq(TBExamInvigilateUser::getUserId, tbUser.getId());
         List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(examInvigilateUserQueryWrapper);
         Set<String> roomCodeSet = null;

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

@@ -62,8 +62,8 @@ public class TBExamInvigilateUserController {
     @ApiOperation(value = "监考员查询接口")
     @RequestMapping(value = "/query", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "监考员信息", response = TBExamInvigilateUserDto.class)})
-    public Result query(@ApiParam(value = "考场代码", required = false) @RequestParam(required = false) String roomCode, @ApiParam(value = "用户id", required = false) @RequestParam(required = false) Long userId, @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber, @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
-        IPage<TBExamInvigilateUserDto> examInvigilateUserDtoIPage = tbExamInvigilateUserService.examInvigilateUserQuery(new Page<>(pageNumber, pageSize), roomCode, userId);
+    public Result query(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId,@ApiParam(value = "考场代码", required = false) @RequestParam(required = false) String roomCode, @ApiParam(value = "用户id", required = false) @RequestParam(required = false) Long userId, @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber, @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
+        IPage<TBExamInvigilateUserDto> examInvigilateUserDtoIPage = tbExamInvigilateUserService.examInvigilateUserQuery(new Page<>(pageNumber, pageSize), examId,roomCode, userId);
         BasePage basePage = new BasePage(examInvigilateUserDtoIPage.getRecords(), examInvigilateUserDtoIPage.getCurrent(), examInvigilateUserDtoIPage.getSize(), examInvigilateUserDtoIPage.getTotal());
         return ResultUtil.ok(basePage);
     }

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

@@ -11,7 +11,6 @@ import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.AuthDto;
 import com.qmth.themis.business.dto.ExamPropCountDto;
 import com.qmth.themis.business.dto.MqDto;
-import com.qmth.themis.business.dto.cache.TEStudentCacheDto;
 import com.qmth.themis.business.dto.request.TEExamDto;
 import com.qmth.themis.business.dto.response.TEExamQueryDto;
 import com.qmth.themis.business.entity.*;
@@ -152,7 +151,7 @@ public class TEExamController {
                     teExamActivityList.forEach(s -> {
                         teExamActivityService.updateExamActivityCacheBean(s.getId());
                     });
-                }else{
+                } else {
                     TEExamActivity teExamActivity = new TEExamActivity(teExam.getId(), teExam.getPrepareSeconds(), teExam.getMaxDurationSeconds(), teExam.getOpeningSeconds(), teExam.getStartTime(), teExam.getEndTime(), tbUser.getId());
                     teExamActivity.setCode(String.valueOf(redisUtil.getRedisActivityCodeSequence()));
                     teExamActivity.setEnable(1);
@@ -205,8 +204,8 @@ public class TEExamController {
     @ApiOperation(value = "考试批次查询接口")
     @RequestMapping(value = "/query", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "考试批次信息", response = TEExam.class)})
-    public Result query(@ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long id, @ApiParam(value = "考试批次编码", required = false) @RequestParam(required = false) String code, @ApiParam(value = "考试批次名称", required = false) @RequestParam(required = false) String name, @ApiParam(value = "考试批次模式", required = false) @RequestParam(required = false) String mode, @ApiParam(value = "是否启用", required = false) @RequestParam(required = false) Integer enable, @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber, @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
-        IPage<TEExamQueryDto> teExamQueryDtoIPage = teExamService.examQuery(new Page<>(pageNumber, pageSize), id, code, name, mode, enable);
+    public Result query(@ApiParam(value = "用户id", required = false) @RequestParam(required = false) Long userId, @ApiParam(value = "考试批次id", required = false) @RequestParam(required = false) Long id, @ApiParam(value = "考试批次编码", required = false) @RequestParam(required = false) String code, @ApiParam(value = "考试批次名称", required = false) @RequestParam(required = false) String name, @ApiParam(value = "考试批次模式", required = false) @RequestParam(required = false) String mode, @ApiParam(value = "是否启用", required = false) @RequestParam(required = false) Integer enable, @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber, @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
+        IPage<TEExamQueryDto> teExamQueryDtoIPage = teExamService.examQuery(new Page<>(pageNumber, pageSize), userId, id, code, name, mode, enable);
         BasePage basePage = new BasePage(teExamQueryDtoIPage.getRecords(), teExamQueryDtoIPage.getCurrent(), teExamQueryDtoIPage.getSize(), teExamQueryDtoIPage.getTotal());
         return ResultUtil.ok(basePage);
     }
@@ -346,7 +345,8 @@ public class TEExamController {
         QueryWrapper<TBExamInvigilateUser> examInvigilateUserQueryWrapper = new QueryWrapper<>();
         AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.userOauth + "::" + tbUser.getId());
         //如果有监考员角色,只能查看自己所监考的考场,巡考员和管理员则可以查看全部考场
-        examInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getOrgId, tbUser.getOrgId());
+        examInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getOrgId, tbUser.getOrgId())
+                .eq(TBExamInvigilateUser::getExamId, examId);
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
             examInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId());
         }
@@ -367,10 +367,9 @@ public class TEExamController {
         Set<String> studentSet = null;
         Set<Long> examActivityIdSet = null;
         Integer allCount = 0;
-        Integer loginCount = 0;
         AtomicReference<Integer> prepareCount = new AtomicReference<>(0);
         AtomicReference<Integer> examCount = new AtomicReference<>(0);
-        AtomicReference<Integer> clientCommunicationStatusCount = new AtomicReference<>(0);
+        AtomicReference<Integer> clientWebsocketStatusCount = new AtomicReference<>(0);
         AtomicReference<Integer> monitorStatusSourceCount = new AtomicReference<>(0);
         AtomicReference<Integer> alreadyComplete = new AtomicReference<>(0);
         Integer notComplete = 0;
@@ -386,14 +385,6 @@ public class TEExamController {
             allCount = studentSet.size();
         }
 
-        if (Objects.nonNull(studentSet)) {
-            //获取已登录学生
-            List<TEStudentCacheDto> teStudentCacheDtoList = (List<TEStudentCacheDto>) redisUtil.multiGet(studentSet);
-            if (Objects.nonNull(teStudentCacheDtoList) && teStudentCacheDtoList.size() > 0) {
-                loginCount = teStudentCacheDtoList.stream().filter(s -> Objects.nonNull(s)).collect(Collectors.toList()).size();
-            }
-        }
-
         if (Objects.nonNull(examActivityIdSet)) {
             //获取已待考、考试中、已完成学生
             examActivityIdSet.forEach(s -> {
@@ -405,7 +396,7 @@ public class TEExamController {
                             //客户端通讯状态
                             WebsocketStatusEnum clientStatus = Objects.isNull(recordIdObjectMap.get("clientWebsocketStatus")) ? null : WebsocketStatusEnum.valueOf(String.valueOf(recordIdObjectMap.get("clientWebsocketStatus")));
                             if (Objects.nonNull(clientStatus) && Objects.equals(clientStatus, WebsocketStatusEnum.OFF_LINE)) {
-                                clientCommunicationStatusCount.getAndSet(clientCommunicationStatusCount.get() + 1);
+                                clientWebsocketStatusCount.getAndSet(clientWebsocketStatusCount.get() + 1);
                             }
                             //监控端通讯状态
                             MonitorVideoSourceEnum source = null;
@@ -442,7 +433,7 @@ public class TEExamController {
         }
         notComplete = allCount - alreadyComplete.get();
         BigDecimal completionRate = new BigDecimal(alreadyComplete.get()).divide(new BigDecimal(allCount)).setScale(2, BigDecimal.ROUND_HALF_UP);
-        ExamPropCountDto examPropCountDto = new ExamPropCountDto(examId, allCount, loginCount, prepareCount.get(), examCount.get(), clientCommunicationStatusCount.get(), monitorStatusSourceCount.get(), alreadyComplete.get(), notComplete, completionRate);
+        ExamPropCountDto examPropCountDto = new ExamPropCountDto(examId, allCount, prepareCount.get(), examCount.get(), clientWebsocketStatusCount.get(), monitorStatusSourceCount.get(), alreadyComplete.get(), notComplete, completionRate);
         return ResultUtil.ok(examPropCountDto);
     }
 }

+ 68 - 14
themis-backend/src/main/java/com/qmth/themis/backend/api/TIeInvigilateCallMobileController.java

@@ -12,12 +12,11 @@ import com.qmth.themis.business.cache.RedisKeyHelper;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.AuthDto;
 import com.qmth.themis.business.dto.MqDto;
-import com.qmth.themis.business.entity.TBSession;
-import com.qmth.themis.business.entity.TBUser;
-import com.qmth.themis.business.entity.TIeExamInvigilateCall;
-import com.qmth.themis.business.entity.TIeExamInvigilateCallLog;
+import com.qmth.themis.business.entity.*;
 import com.qmth.themis.business.enums.*;
 import com.qmth.themis.business.service.MqDtoService;
+import com.qmth.themis.business.service.TBExamInvigilateUserService;
+import com.qmth.themis.business.service.TEExamStudentService;
 import com.qmth.themis.business.service.TIeExamInvigilateCallService;
 import com.qmth.themis.business.util.RedisUtil;
 import com.qmth.themis.business.util.ServletUtil;
@@ -33,10 +32,8 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @Description: mobile监考监控通话信息 前端控制器
@@ -63,11 +60,21 @@ public class TIeInvigilateCallMobileController {
     @Resource
     TencentYunUtil tencentYunUtil;
 
+    @Resource
+    TBExamInvigilateUserService tbExamInvigilateUserService;
+
+    @Resource
+    TEExamStudentService teExamStudentService;
+
     @ApiOperation(value = "监考监控通话查询接口")
     @RequestMapping(value = "/call/list", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "监考监控信息", response = TIeExamInvigilateCall.class)})
-    public Result callList(@ApiParam(value = "场次id", required = false) @RequestParam(required = false) Long examActivityId, @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber, @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
-        IPage<TIeExamInvigilateCall> tIeExamInvigilateCallIPage = tIeExamInvigilateCallService.examInvigilateCallQuery(new Page<>(pageNumber, pageSize), examActivityId, MonitorStatusSourceEnum.START.name());
+    public Result callList(@ApiParam(value = "考试批次id", required = true) @RequestParam(required = true) Long examId, @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber, @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
+        if (Objects.isNull(examId) || Objects.equals(examId, "")) {
+            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
+        }
+        Set<Long> examActivityIdSet = this.getExamActivityIds(examId);
+        IPage<TIeExamInvigilateCall> tIeExamInvigilateCallIPage = tIeExamInvigilateCallService.examInvigilateCallQuery(new Page<>(pageNumber, pageSize), examActivityIdSet, MonitorStatusSourceEnum.START.name());
         BasePage basePage = new BasePage(tIeExamInvigilateCallIPage.getRecords(), tIeExamInvigilateCallIPage.getCurrent(), tIeExamInvigilateCallIPage.getSize(), tIeExamInvigilateCallIPage.getTotal());
         return ResultUtil.ok(basePage);
     }
@@ -75,12 +82,13 @@ public class TIeInvigilateCallMobileController {
     @ApiOperation(value = "监考监控通话提醒接口")
     @RequestMapping(value = "/call/count", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "监考监控信息", response = Integer.class)})
-    public Result callCount(@ApiParam(value = "场次id", required = true) @RequestParam Long examActivityId) {
-        if (Objects.isNull(examActivityId) || Objects.equals(examActivityId, "")) {
-            throw new BusinessException(ExceptionResultEnum.EXAM_ACTIVITY_ID_IS_NULL);
+    public Result callCount(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId) {
+        if (Objects.isNull(examId) || Objects.equals(examId, "")) {
+            throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
         }
+        Set<Long> examActivityIdSet = this.getExamActivityIds(examId);
         QueryWrapper<TIeExamInvigilateCall> examInvigilateCallQueryWrapper = new QueryWrapper<>();
-        examInvigilateCallQueryWrapper.lambda().eq(TIeExamInvigilateCall::getExamActivityId, examActivityId).eq(TIeExamInvigilateCall::getStatus, MonitorStatusSourceEnum.START.name());
+        examInvigilateCallQueryWrapper.lambda().in(TIeExamInvigilateCall::getExamActivityId, examActivityIdSet).eq(TIeExamInvigilateCall::getStatus, MonitorStatusSourceEnum.START.name());
         int count = tIeExamInvigilateCallService.count(examInvigilateCallQueryWrapper);
         return ResultUtil.ok(Collections.singletonMap("count", count));
     }
@@ -152,4 +160,50 @@ public class TIeInvigilateCallMobileController {
         map.put("monitorUserSig", monitorUserSig);
         return ResultUtil.ok(map);
     }
+
+    /**
+     * 获取考试批次
+     *
+     * @param examId
+     * @return
+     */
+    public Set<Long> getExamActivityIds(Long examId) {
+        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
+        TBSession tbSession = (TBSession) ServletUtil.getRequestSession();
+        if (Objects.isNull(tbSession)) {
+            throw new BusinessException(ExceptionResultEnum.LOGIN_NO);
+        }
+        //首先查询当前用户所要监控的roomCode
+        QueryWrapper<TBExamInvigilateUser> examInvigilateUserQueryWrapper = new QueryWrapper<>();
+        AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.userOauth + "::" + tbUser.getId());
+        //如果有监考员角色,只能查看自己所监考的考场,巡考员和管理员则可以查看全部考场
+        examInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getOrgId, tbUser.getOrgId())
+                .eq(TBExamInvigilateUser::getExamId, examId);
+        if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
+            examInvigilateUserQueryWrapper.lambda().eq(TBExamInvigilateUser::getUserId, tbUser.getId());
+        }
+        List<TBExamInvigilateUser> tbExamInvigilateUserList = tbExamInvigilateUserService.list(examInvigilateUserQueryWrapper);
+        Set<String> roomCodeSet = null;
+        if (Objects.nonNull(tbExamInvigilateUserList) && tbExamInvigilateUserList.size() > 0) {
+            roomCodeSet = tbExamInvigilateUserList.stream().map(s -> s.getRoomCode()).collect(Collectors.toSet());
+        }
+        if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name()) && (Objects.isNull(roomCodeSet) || roomCodeSet.size() == 0)) {
+            throw new BusinessException("当前监考老师未设置任何监考考场");
+        } else if (Objects.isNull(roomCodeSet) || roomCodeSet.size() == 0) {
+            throw new BusinessException("当前考试批次未设置任何监考考场");
+        }
+        //根据roomCode获取当前老师所要监考的全部应考学生数
+        QueryWrapper<TEExamStudent> teExamStudentQueryWrapper = new QueryWrapper<>();
+        teExamStudentQueryWrapper.lambda().in(TEExamStudent::getRoomCode, roomCodeSet);
+        List<TEExamStudent> teExamStudentList = teExamStudentService.list(teExamStudentQueryWrapper);
+        Set<Long> examActivityIdSet = null;
+        if (Objects.nonNull(teExamStudentList) && teExamStudentList.size() > 0) {
+            examActivityIdSet = new HashSet<>();
+            Set<Long> finalExamActivityIdSet = examActivityIdSet;
+            teExamStudentList.forEach(s -> {
+                finalExamActivityIdSet.add(s.getExamActivityId());
+            });
+        }
+        return examActivityIdSet;
+    }
 }

+ 14 - 0
themis-backend/src/main/java/com/qmth/themis/backend/api/TIeReportController.java

@@ -44,4 +44,18 @@ public class TIeReportController {
                              @ApiParam(value = "唯一码", required = false) @RequestParam String identity) {
         return ResultUtil.ok(reportService.examView(examId, examActivityId, roomCode, courseCode, name, identity));
     }
+    
+    @ApiOperation(value = "情况统计")
+    @RequestMapping(value = "/exam_view_count", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "结果信息")})
+    public Result examViewCount(@ApiParam(value = "考试id", required = true) @RequestParam Long examId,
+                             @ApiParam(value = "考场场次id", required = false) @RequestParam Long examActivityId,
+                             @ApiParam(value = "虚拟考场代码", required = false) @RequestParam String roomCode,
+                             @ApiParam(value = "科目编码", required = false) @RequestParam String courseCode,
+                             @ApiParam(value = "姓名", required = false) @RequestParam String name,
+                             @ApiParam(value = "唯一码", required = false) @RequestParam String identity,
+                             @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber,
+                             @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
+        return ResultUtil.ok(reportService.examViewCount(examId, examActivityId, roomCode, courseCode, name, identity,pageNumber,pageSize));
+    }
 }

+ 1 - 1
themis-backend/src/main/resources/application.properties

@@ -163,5 +163,5 @@ rocketmq.producer.customized-trace-topic=my-trace-topic
 prefix.url.admin=api/admin
 
 #\u65E0\u9700\u9274\u6743\u7684url
-no.auth.urls=/webjars/**,/druid/**,/swagger-ui.html,/doc.html,/swagger-resources/**,/v2/api-docs,/webjars/springfox-swagger-ui/**,/api/admin/user/login/account,/api/admin/sys/org/queryByOrgCode,/file/**,/upload/**,/client/**,/base_photo/**,/frontend/**,/api/admin/monitor/call/list,/api/admin/monitor/call/query
+no.auth.urls=/webjars/**,/druid/**,/swagger-ui.html,/doc.html,/swagger-resources/**,/v2/api-docs,/webjars/springfox-swagger-ui/**,/api/admin/user/login/account,/api/admin/sys/org/queryByOrgCode,/file/**,/upload/**,/client/**,/base_photo/**,/frontend/**
 common.system.urls=/api/admin/sys/getMenu,/api/admin/user/logout,/api/admin/sys/env,/api/admin/sys/file/upload,/api/admin/sys/file/download,/api/admin/sys/org/query,/api/admin/sys/role/query,/api/admin/sys/examActivity/query,/api/admin/sys/exam/query,/api/admin/sys/examRoom/query,/api/admin/sys/exam/privilegeQuery,/api/admin/student/photo/upload

+ 105 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/backend/ExamViewCountListBean.java

@@ -0,0 +1,105 @@
+package com.qmth.themis.business.bean.backend;
+
+import java.io.Serializable;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel("报表-情况统计返回对象")
+public class ExamViewCountListBean implements Serializable {
+
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = -4399923396400174947L;
+	
+	@ApiModelProperty(name = "考试名称")
+    private String examName;
+	
+	@ApiModelProperty(name = "考试id")
+    private Long examId;
+
+    @ApiModelProperty(name = "场次id")
+    private Long examActivityId;
+
+    @ApiModelProperty(name = "虚拟考场代码")
+    private String roomCode;
+
+    @ApiModelProperty(name = "虚拟考场名称")
+    private String roomName;
+
+    @ApiModelProperty(name = "应考")
+    private Long examTotal;
+    
+    @ApiModelProperty(name = "实考")
+    private Long actualExamTotal;
+    
+    @ApiModelProperty(name = "缺考")
+    private Long deficiencyExamTotal;
+
+	public String getExamName() {
+		return examName;
+	}
+
+	public void setExamName(String examName) {
+		this.examName = examName;
+	}
+
+	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 String getRoomCode() {
+		return roomCode;
+	}
+
+	public void setRoomCode(String roomCode) {
+		this.roomCode = roomCode;
+	}
+
+	public String getRoomName() {
+		return roomName;
+	}
+
+	public void setRoomName(String roomName) {
+		this.roomName = roomName;
+	}
+
+	public Long getExamTotal() {
+		return examTotal;
+	}
+
+	public void setExamTotal(Long examTotal) {
+		this.examTotal = examTotal;
+	}
+
+	public Long getActualExamTotal() {
+		return actualExamTotal;
+	}
+
+	public void setActualExamTotal(Long actualExamTotal) {
+		this.actualExamTotal = actualExamTotal;
+	}
+
+	public Long getDeficiencyExamTotal() {
+		return deficiencyExamTotal;
+	}
+
+	public void setDeficiencyExamTotal(Long deficiencyExamTotal) {
+		this.deficiencyExamTotal = deficiencyExamTotal;
+	}
+
+    
+}

+ 33 - 10
themis-business/src/main/java/com/qmth/themis/business/bean/backend/InvigilateListBean.java

@@ -1,6 +1,7 @@
 package com.qmth.themis.business.bean.backend;
 
 import com.qmth.themis.business.enums.ExamRecordStatusEnum;
+import com.qmth.themis.business.enums.MonitorStatusSourceEnum;
 import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
 import com.qmth.themis.business.enums.WebsocketStatusEnum;
 import io.swagger.annotations.ApiModel;
@@ -57,11 +58,11 @@ public class InvigilateListBean implements Serializable {
     @ApiModelProperty(name = "预警量")
     private Integer warningCount;
 
-    @ApiModelProperty(name = "客户端网络通信状态", required = false)
-    private WebsocketStatusEnum clientCommunicationStatus;
+    @ApiModelProperty(name = "客户端网络通信状态")
+    private WebsocketStatusEnum clientWebsocketStatus;
 
-    @ApiModelProperty(name = "监控通信状态", required = false)
-    private MonitorVideoSourceEnum monitorStatusSource;
+    @ApiModelProperty(name = "监控通信状态")
+    private MonitorStatusSourceEnum monitorStatusSource;
 
     @ApiModelProperty(name = "ip地址")
     private String clientCurrentIp;
@@ -72,6 +73,28 @@ public class InvigilateListBean implements Serializable {
     @ApiModelProperty(name = "更新时间")
     private Date updateTime;
 
+    @ApiModelProperty(name = "剩余时间")
+    private String remainTime;
+
+    @ApiModelProperty(name = "新增预警")
+    private Integer warningNew;
+
+    public Integer getWarningNew() {
+        return warningNew;
+    }
+
+    public void setWarningNew(Integer warningNew) {
+        this.warningNew = warningNew;
+    }
+
+    public String getRemainTime() {
+        return remainTime;
+    }
+
+    public void setRemainTime(String remainTime) {
+        this.remainTime = remainTime;
+    }
+
     public String getRoomName() {
         return roomName;
     }
@@ -203,19 +226,19 @@ public class InvigilateListBean implements Serializable {
         this.warningCount = warningCount;
     }
 
-    public WebsocketStatusEnum getClientCommunicationStatus() {
-        return clientCommunicationStatus;
+    public WebsocketStatusEnum getClientWebsocketStatus() {
+        return clientWebsocketStatus;
     }
 
-    public void setClientCommunicationStatus(WebsocketStatusEnum clientCommunicationStatus) {
-        this.clientCommunicationStatus = clientCommunicationStatus;
+    public void setClientWebsocketStatus(WebsocketStatusEnum clientWebsocketStatus) {
+        this.clientWebsocketStatus = clientWebsocketStatus;
     }
 
-    public MonitorVideoSourceEnum getMonitorStatusSource() {
+    public MonitorStatusSourceEnum getMonitorStatusSource() {
         return monitorStatusSource;
     }
 
-    public void setMonitorStatusSource(MonitorVideoSourceEnum monitorStatusSource) {
+    public void setMonitorStatusSource(MonitorStatusSourceEnum monitorStatusSource) {
         this.monitorStatusSource = monitorStatusSource;
     }
 

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

@@ -1,11 +1,22 @@
 package com.qmth.themis.business.constant;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qmth.themis.business.dto.AuthDto;
+import com.qmth.themis.business.entity.TBExamInvigilateUser;
+import com.qmth.themis.business.entity.TBSession;
+import com.qmth.themis.business.entity.TBUser;
+import com.qmth.themis.business.entity.TEExamStudent;
+import com.qmth.themis.business.enums.RoleEnum;
+import com.qmth.themis.business.util.ServletUtil;
 import com.qmth.themis.common.contanst.Constants;
+import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.enums.Platform;
 import com.qmth.themis.common.enums.Source;
+import com.qmth.themis.common.exception.BusinessException;
 
 import java.io.File;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @Description: 系统常量

+ 2 - 10
themis-business/src/main/java/com/qmth/themis/business/dao/TBExamInvigilateUserMapper.java

@@ -3,7 +3,6 @@ package com.qmth.themis.business.dao;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.qmth.themis.business.dto.RoomCodeExportDto;
-import com.qmth.themis.business.dto.response.RoomCodeQueryDto;
 import com.qmth.themis.business.dto.response.TBExamInvigilateUserDto;
 import com.qmth.themis.business.entity.TBExamInvigilateUser;
 import org.apache.ibatis.annotations.Mapper;
@@ -26,11 +25,12 @@ public interface TBExamInvigilateUserMapper extends BaseMapper<TBExamInvigilateU
      * 查询监考员
      *
      * @param iPage
+     * @param examId
      * @param roomCode
      * @param userId
      * @return
      */
-    public IPage<TBExamInvigilateUserDto> examInvigilateUserQuery(IPage<Map> iPage, @Param("roomCode") String roomCode, @Param("userId") Long userId);
+    public IPage<TBExamInvigilateUserDto> examInvigilateUserQuery(IPage<Map> iPage, @Param("examId") Long examId, @Param("roomCode") String roomCode, @Param("userId") Long userId);
 
     /**
      * 监考员导出
@@ -38,12 +38,4 @@ public interface TBExamInvigilateUserMapper extends BaseMapper<TBExamInvigilateU
      * @return
      */
     public List<RoomCodeExportDto> examInvigilateUserExport();
-
-    /**
-     * 考场查询
-     *
-     * @param roomName
-     * @return
-     */
-    public List<RoomCodeQueryDto> examRoomQuery(@Param("roomName") String roomName);
 }

+ 2 - 1
themis-business/src/main/java/com/qmth/themis/business/dao/TEExamMapper.java

@@ -25,6 +25,7 @@ public interface TEExamMapper extends BaseMapper<TEExam> {
      * 查询考试批次
      *
      * @param iPage
+     * @param userId
      * @param id
      * @param code
      * @param name
@@ -32,7 +33,7 @@ public interface TEExamMapper extends BaseMapper<TEExam> {
      * @param enable
      * @return
      */
-    public IPage<TEExamQueryDto> examQuery(IPage<Map> iPage, @Param("id") Long id, @Param("code") String code, @Param("name") String name, @Param("mode") String mode, @Param("enable") Integer enable);
+    public IPage<TEExamQueryDto> examQuery(IPage<Map> iPage, @Param("userId") Long userId, @Param("id") Long id, @Param("code") String code, @Param("name") String name, @Param("mode") String mode, @Param("enable") Integer enable);
 
     /**
      * 获取考试待考列表

+ 17 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TEExamStudentMapper.java

@@ -2,6 +2,8 @@ package com.qmth.themis.business.dao;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.qmth.themis.business.bean.backend.ExamViewCountListBean;
+import com.qmth.themis.business.dto.response.RoomCodeQueryDto;
 import com.qmth.themis.business.dto.response.TEExamStudentDto;
 import com.qmth.themis.business.entity.TEExamStudent;
 import org.apache.ibatis.annotations.Mapper;
@@ -42,4 +44,19 @@ public interface TEExamStudentMapper extends BaseMapper<TEExamStudent> {
 
     public List<Map<String, Object>> getTotalCount(@Param("examId") Long examId, @Param("activityId") Long activityId,
                                                    @Param("roomCode") String roomCode, @Param("courseCode") String courseCode);
+
+    public IPage<ExamViewCountListBean> getTotalCountInfo(IPage<Map> iPage, @Param("examId") Long examId, @Param("activityId") Long activityId,
+                                                          @Param("roomCode") String roomCode, @Param("courseCode") String courseCode);
+
+    public List<Map<String, Object>> getDoneCountByActivityIds(@Param("examId") Long examId, @Param("activityIds") List<Long> activityIds);
+
+    public List<Map<String, Object>> getAbsentCountByActivityIds(@Param("examId") Long examId, @Param("activityIds") List<Long> activityIds);
+
+    /**
+     * 考场查询
+     *
+     * @param roomName
+     * @return
+     */
+    public List<RoomCodeQueryDto> examRoomQuery(@Param("roomName") String roomName);
 }

+ 3 - 2
themis-business/src/main/java/com/qmth/themis/business/dao/TIeExamInvigilateCallMapper.java

@@ -7,6 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @Description: 监考 监控通话申请 Mapper 接口
@@ -22,9 +23,9 @@ public interface TIeExamInvigilateCallMapper extends BaseMapper<TIeExamInvigilat
      * 监考监控通话申请查询
      *
      * @param iPage
-     * @param examActivityId
+     * @param examActivityIdSet
      * @param status
      * @return
      */
-    public IPage<TIeExamInvigilateCall> examInvigilateCallQuery(IPage<Map> iPage, @Param("examActivityId") Long examActivityId, @Param("status") String status);
+    public IPage<TIeExamInvigilateCall> examInvigilateCallQuery(IPage<Map> iPage, @Param("examActivityIdSet") Set<Long> examActivityIdSet, @Param("status") String status);
 }

+ 1 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TOeExamRecordMapper.java

@@ -245,4 +245,5 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
 	
 	public List<Map<String,Object>> getDoneCountByDay(@Param("examId") Long examId, @Param("activityId") Long activityId,
 			@Param("roomCode") String roomCode,@Param("courseCode")  String courseCode);
+	
 }

+ 9 - 22
themis-business/src/main/java/com/qmth/themis/business/dto/ExamPropCountDto.java

@@ -23,9 +23,6 @@ public class ExamPropCountDto implements Serializable {
     @ApiModelProperty(name = "应考人数")
     private Integer allCount;//应考人数
 
-    @ApiModelProperty(name = "已登录")
-    private Integer loginCount;//已登录
-
     @ApiModelProperty(name = "已待考")
     private Integer prepareCount;//已待考
 
@@ -33,7 +30,7 @@ public class ExamPropCountDto implements Serializable {
     private Integer examCount;//考试中
 
     @ApiModelProperty(name = "客户端通讯故障")
-    private Integer clientCommunicationStatusCount;//客户端通讯故障
+    private Integer clientWebsocketStatusCount;//客户端通讯故障
 
     @ApiModelProperty(name = "监控设备通讯故障")
     private Integer monitorStatusSourceCount;//监控设备通讯故障
@@ -69,13 +66,12 @@ public class ExamPropCountDto implements Serializable {
 
     }
 
-    public ExamPropCountDto(Long examId, Integer allCount, Integer loginCount, Integer prepareCount, Integer examCount, Integer clientCommunicationStatusCount, Integer monitorStatusSourceCount, Integer alreadyComplete, Integer notComplete, Set<String> roomCodes, BigDecimal completionRate) {
+    public ExamPropCountDto(Long examId, Integer allCount, Integer prepareCount, Integer examCount, Integer clientWebsocketStatusCount, Integer monitorStatusSourceCount, Integer alreadyComplete, Integer notComplete, Set<String> roomCodes, BigDecimal completionRate) {
         this.examId = examId;
         this.allCount = allCount;
-        this.loginCount = loginCount;
         this.prepareCount = prepareCount;
         this.examCount = examCount;
-        this.clientCommunicationStatusCount = clientCommunicationStatusCount;
+        this.clientWebsocketStatusCount = clientWebsocketStatusCount;
         this.monitorStatusSourceCount = monitorStatusSourceCount;
         this.alreadyComplete = alreadyComplete;
         this.notComplete = notComplete;
@@ -83,13 +79,12 @@ public class ExamPropCountDto implements Serializable {
         this.completionRate = completionRate;
     }
 
-    public ExamPropCountDto(Long examId, Integer allCount, Integer loginCount, Integer prepareCount, Integer examCount, Integer clientCommunicationStatusCount, Integer monitorStatusSourceCount, Integer alreadyComplete, Integer notComplete, BigDecimal completionRate) {
+    public ExamPropCountDto(Long examId, Integer allCount, Integer prepareCount, Integer examCount, Integer clientWebsocketStatusCount, Integer monitorStatusSourceCount, Integer alreadyComplete, Integer notComplete, BigDecimal completionRate) {
         this.examId = examId;
         this.allCount = allCount;
-        this.loginCount = loginCount;
         this.prepareCount = prepareCount;
         this.examCount = examCount;
-        this.clientCommunicationStatusCount = clientCommunicationStatusCount;
+        this.clientWebsocketStatusCount = clientWebsocketStatusCount;
         this.monitorStatusSourceCount = monitorStatusSourceCount;
         this.alreadyComplete = alreadyComplete;
         this.notComplete = notComplete;
@@ -168,14 +163,6 @@ public class ExamPropCountDto implements Serializable {
         this.allCount = allCount;
     }
 
-    public Integer getLoginCount() {
-        return loginCount;
-    }
-
-    public void setLoginCount(Integer loginCount) {
-        this.loginCount = loginCount;
-    }
-
     public Integer getPrepareCount() {
         return prepareCount;
     }
@@ -192,12 +179,12 @@ public class ExamPropCountDto implements Serializable {
         this.examCount = examCount;
     }
 
-    public Integer getClientCommunicationStatusCount() {
-        return clientCommunicationStatusCount;
+    public Integer getClientWebsocketStatusCount() {
+        return clientWebsocketStatusCount;
     }
 
-    public void setClientCommunicationStatusCount(Integer clientCommunicationStatusCount) {
-        this.clientCommunicationStatusCount = clientCommunicationStatusCount;
+    public void setClientWebsocketStatusCount(Integer clientWebsocketStatusCount) {
+        this.clientWebsocketStatusCount = clientWebsocketStatusCount;
     }
 
     public Integer getMonitorStatusSourceCount() {

+ 24 - 2
themis-business/src/main/java/com/qmth/themis/business/dto/response/TBExamInvigilateUserDto.java

@@ -13,6 +13,12 @@ import java.io.Serializable;
 */ 
 public class TBExamInvigilateUserDto implements Serializable {
 
+    @ApiModelProperty(name = "考试批次id")
+    private Long examId;//考试批次id
+
+    @ApiModelProperty(name = "考试批次名称")
+    private String examName;//考试批次名称
+
     @ApiModelProperty(name = "虚拟考场代码,考试唯一")
     private String roomCode;//考场代码
 
@@ -20,10 +26,26 @@ public class TBExamInvigilateUserDto implements Serializable {
     private String roomName;//考场名称
 
     @ApiModelProperty(name = "用户id")
-    private String userId;//老师id
+    private String userId;//用户id
 
     @ApiModelProperty(name = "用户姓名")
-    private String name;//老师名称
+    private String name;//用户姓名
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getExamName() {
+        return examName;
+    }
+
+    public void setExamName(String examName) {
+        this.examName = examName;
+    }
 
     public String getRoomCode() {
         return roomCode;

+ 16 - 2
themis-business/src/main/java/com/qmth/themis/business/entity/TBExamInvigilateUser.java

@@ -24,6 +24,10 @@ public class TBExamInvigilateUser implements Serializable {
     @TableId(value = "id")
     private Long id;
 
+    @ApiModelProperty(value = "考试批次ID")
+    @TableField("exam_id")
+    private Long examId;
+
     @ApiModelProperty(value = "机构ID")
     @TableField("org_id")
     private Long orgId;
@@ -48,21 +52,31 @@ public class TBExamInvigilateUser implements Serializable {
 
     }
 
-    public TBExamInvigilateUser(Long orgId, String roomCode, String roomName) {
+    public TBExamInvigilateUser(Long examId, Long orgId, String roomCode, String roomName) {
         this.id = Constants.idGen.next();
+        this.examId = examId;
         this.orgId = orgId;
         this.roomCode = roomCode;
         this.roomName = roomName;
     }
 
-    public TBExamInvigilateUser(Long orgId, Long userId, String roomCode, String roomName) {
+    public TBExamInvigilateUser(Long examId, Long orgId, Long userId, String roomCode, String roomName) {
         this.id = Constants.idGen.next();
+        this.examId = examId;
         this.orgId = orgId;
         this.userId = userId;
         this.roomCode = roomCode;
         this.roomName = roomName;
     }
 
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
     public static long getSerialVersionUID() {
         return serialVersionUID;
     }

+ 12 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TOeExamRecord.java

@@ -172,6 +172,18 @@ public class TOeExamRecord implements Serializable {
     @TableField(value = "score_status")
     private ScoreStatusEnum scoreStatus;
 
+    @ApiModelProperty(value = "异常状态")
+    @TableField(value = "exception_status")
+    private ExceptionEnum exceptionStatus;
+
+    public ExceptionEnum getExceptionStatus() {
+        return exceptionStatus;
+    }
+
+    public void setExceptionStatus(ExceptionEnum exceptionStatus) {
+        this.exceptionStatus = exceptionStatus;
+    }
+
     public ScoreStatusEnum getScoreStatus() {
         return scoreStatus;
     }

+ 2 - 10
themis-business/src/main/java/com/qmth/themis/business/service/TBExamInvigilateUserService.java

@@ -3,7 +3,6 @@ package com.qmth.themis.business.service;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.themis.business.dto.RoomCodeExportDto;
-import com.qmth.themis.business.dto.response.RoomCodeQueryDto;
 import com.qmth.themis.business.dto.response.TBExamInvigilateUserDto;
 import com.qmth.themis.business.entity.TBExamInvigilateUser;
 
@@ -23,11 +22,12 @@ public interface TBExamInvigilateUserService extends IService<TBExamInvigilateUs
      * 查询监考员
      *
      * @param iPage
+     * @param examId
      * @param roomCode
      * @param userId
      * @return
      */
-    public IPage<TBExamInvigilateUserDto> examInvigilateUserQuery(IPage<Map> iPage, String roomCode, Long userId);
+    public IPage<TBExamInvigilateUserDto> examInvigilateUserQuery(IPage<Map> iPage, Long examId, String roomCode, Long userId);
 
     /**
      * 监考员导出
@@ -35,12 +35,4 @@ public interface TBExamInvigilateUserService extends IService<TBExamInvigilateUs
      * @return
      */
     public List<RoomCodeExportDto> examInvigilateUserExport();
-
-    /**
-     * 考场查询
-     *
-     * @param roomName
-     * @return
-     */
-    public List<RoomCodeQueryDto> examRoomQuery(String roomName);
 }

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

@@ -27,6 +27,7 @@ public interface TEExamService extends IService<TEExam> {
      * 查询考试批次
      *
      * @param iPage
+     * @param userId
      * @param id
      * @param code
      * @param name
@@ -34,7 +35,7 @@ public interface TEExamService extends IService<TEExam> {
      * @param enable
      * @return
      */
-    public IPage<TEExamQueryDto> examQuery(IPage<Map> iPage, Long id, String code, String name, String mode, Integer enable);
+    public IPage<TEExamQueryDto> examQuery(IPage<Map> iPage,Long userId, Long id, String code, String name, String mode, Integer enable);
 
     /**
      * 获取考试待考列表

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

@@ -3,9 +3,11 @@ package com.qmth.themis.business.service;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
+import com.qmth.themis.business.dto.response.RoomCodeQueryDto;
 import com.qmth.themis.business.dto.response.TEExamStudentDto;
 import com.qmth.themis.business.entity.TEExamStudent;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -50,4 +52,12 @@ public interface TEExamStudentService extends IService<TEExamStudent> {
      * @param examStudentId
      */
     void deleteExamStudentCacheBean(Long examStudentId);
+
+    /**
+     * 考场查询
+     *
+     * @param roomName
+     * @return
+     */
+    public List<RoomCodeQueryDto> examRoomQuery(String roomName);
 }

+ 3 - 2
themis-business/src/main/java/com/qmth/themis/business/service/TIeExamInvigilateCallService.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.themis.business.entity.TIeExamInvigilateCall;
 
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @Description: 监考监控通话申请 服务类
@@ -19,9 +20,9 @@ public interface TIeExamInvigilateCallService extends IService<TIeExamInvigilate
      * 监考监控通话申请查询
      *
      * @param iPage
-     * @param examActivityId
+     * @param examActivityIdSet
      * @param status
      * @return
      */
-    public IPage<TIeExamInvigilateCall> examInvigilateCallQuery(IPage<Map> iPage, Long examActivityId, String status);
+    public IPage<TIeExamInvigilateCall> examInvigilateCallQuery(IPage<Map> iPage, Set<Long> examActivityIdSet, String status);
 }

+ 5 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TIeReportService.java

@@ -2,7 +2,12 @@ package com.qmth.themis.business.service;
 
 import java.util.Map;
 
+import com.qmth.themis.business.base.BasePage;
+
 public interface TIeReportService {
 	public Map<String, Object> examView(Long examId, Long examActivityId, String roomCode, String courseCode,
 			String name, String identity);
+
+	public BasePage examViewCount(Long examId, Long examActivityId, String roomCode, String courseCode, String name,
+			String identity, int pageNumber, int pageSize);
 }

+ 3 - 14
themis-business/src/main/java/com/qmth/themis/business/service/impl/TBExamInvigilateUserServiceImpl.java

@@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.themis.business.dao.TBExamInvigilateUserMapper;
 import com.qmth.themis.business.dto.RoomCodeExportDto;
-import com.qmth.themis.business.dto.response.RoomCodeQueryDto;
 import com.qmth.themis.business.dto.response.TBExamInvigilateUserDto;
 import com.qmth.themis.business.entity.TBExamInvigilateUser;
 import com.qmth.themis.business.service.TBExamInvigilateUserService;
@@ -31,13 +30,14 @@ public class TBExamInvigilateUserServiceImpl extends ServiceImpl<TBExamInvigilat
      * 查询监考员
      *
      * @param iPage
+     * @param examId
      * @param roomCode
      * @param userId
      * @return
      */
     @Override
-    public IPage<TBExamInvigilateUserDto> examInvigilateUserQuery(IPage<Map> iPage, String roomCode, Long userId) {
-        return tbExamInvigilateUserMapper.examInvigilateUserQuery(iPage, roomCode, userId);
+    public IPage<TBExamInvigilateUserDto> examInvigilateUserQuery(IPage<Map> iPage, Long examId, String roomCode, Long userId) {
+        return tbExamInvigilateUserMapper.examInvigilateUserQuery(iPage, examId, roomCode, userId);
     }
 
     /**
@@ -49,15 +49,4 @@ public class TBExamInvigilateUserServiceImpl extends ServiceImpl<TBExamInvigilat
     public List<RoomCodeExportDto> examInvigilateUserExport() {
         return tbExamInvigilateUserMapper.examInvigilateUserExport();
     }
-
-    /**
-     * 考场查询
-     *
-     * @param roomName
-     * @return
-     */
-    @Override
-    public List<RoomCodeQueryDto> examRoomQuery(String roomName) {
-        return tbExamInvigilateUserMapper.examRoomQuery(roomName);
-    }
 }

+ 3 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamActivityServiceImpl.java

@@ -11,6 +11,7 @@ import com.qmth.themis.business.service.TEExamActivityService;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.CachePut;
 import org.springframework.cache.annotation.Cacheable;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -125,6 +126,7 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
      * @param examActivityId
      * @return
      */
+    @Async
     @Override
     @CachePut(value = "exam_activity", key = "#examActivityId", condition = "#result != null")
     public ExamActivityCacheBean updateExamActivityCacheBean(Long examActivityId) {
@@ -136,6 +138,7 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
      *
      * @param examActivityId
      */
+    @Async
     @Override
     @CacheEvict(value = "exam_activity", key = "#examActivityId")
     public void deleteExamActivityCacheBean(Long examActivityId) {

+ 3 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamCourseServiceImpl.java

@@ -14,6 +14,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.CachePut;
 import org.springframework.cache.annotation.Cacheable;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -79,6 +80,7 @@ public class TEExamCourseServiceImpl extends ServiceImpl<TEExamCourseMapper, TEE
      * @param courseCode
      * @return
      */
+    @Async
     @Override
     @CachePut(value = "exam_course", key = "#examId+'_'+#courseCode", condition = "#result != null")
     public ExamCourseCacheBean updateExamCourseCacheBean(Long examId, String courseCode) {
@@ -91,6 +93,7 @@ public class TEExamCourseServiceImpl extends ServiceImpl<TEExamCourseMapper, TEE
      * @param examId
      * @param courseCode
      */
+    @Async
     @Override
     @CacheEvict(value = "exam_course", key = "#examId+'_'+#courseCode")
     public void deleteExamCourseCacheBean(Long examId, String courseCode) {

+ 3 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamPaperServiceImpl.java

@@ -17,6 +17,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.CachePut;
 import org.springframework.cache.annotation.Cacheable;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -68,6 +69,7 @@ public class TEExamPaperServiceImpl extends ServiceImpl<TEExamPaperMapper, TEExa
      * @param paperId
      * @return
      */
+    @Async
     @Override
     @CachePut(value = "exam_paper", key = "#paperId", condition = "#result != null")
     public ExamPaperCacheBean updateExamPaperCacheBean(Long paperId) {
@@ -79,6 +81,7 @@ public class TEExamPaperServiceImpl extends ServiceImpl<TEExamPaperMapper, TEExa
      *
      * @param paperId
      */
+    @Async
     @Override
     @CacheEvict(value = "exam_paper", key = "#paperId")
     public void deleteExamPaperCacheBean(Long paperId) {

+ 3 - 2
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java

@@ -85,6 +85,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
      * 查询考试批次
      *
      * @param iPage
+     * @param userId
      * @param id
      * @param code
      * @param name
@@ -93,8 +94,8 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
      * @return
      */
     @Override
-    public IPage<TEExamQueryDto> examQuery(IPage<Map> iPage, Long id, String code, String name, String mode, Integer enable) {
-        return teExamMapper.examQuery(iPage, id, code, name, mode, enable);
+    public IPage<TEExamQueryDto> examQuery(IPage<Map> iPage, Long userId, Long id, String code, String name, String mode, Integer enable) {
+        return teExamMapper.examQuery(iPage, userId, id, code, name, mode, enable);
     }
 
     /**

+ 16 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamStudentServiceImpl.java

@@ -4,15 +4,18 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.dao.TEExamStudentMapper;
+import com.qmth.themis.business.dto.response.RoomCodeQueryDto;
 import com.qmth.themis.business.dto.response.TEExamStudentDto;
 import com.qmth.themis.business.entity.TEExamStudent;
 import com.qmth.themis.business.service.TEExamStudentService;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.CachePut;
 import org.springframework.cache.annotation.Cacheable;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -60,6 +63,7 @@ public class TEExamStudentServiceImpl extends ServiceImpl<TEExamStudentMapper, T
      * @param examStudentId
      * @return
      */
+    @Async
     @Override
     @CachePut(value = "exam_student", key = "#examStudentId", condition = "#result != null")
     public ExamStudentCacheBean updateExamStudentCacheBean(Long examStudentId) {
@@ -71,12 +75,24 @@ public class TEExamStudentServiceImpl extends ServiceImpl<TEExamStudentMapper, T
      *
      * @param examStudentId
      */
+    @Async
     @Override
     @CacheEvict(value = "exam_student", key = "#examStudentId")
     public void deleteExamStudentCacheBean(Long examStudentId) {
 
     }
 
+    /**
+     * 考场查询
+     *
+     * @param roomName
+     * @return
+     */
+    @Override
+    public List<RoomCodeQueryDto> examRoomQuery(String roomName) {
+        return null;
+    }
+
     /**
      * 缓存操作
      *

+ 11 - 2
themis-business/src/main/java/com/qmth/themis/business/service/impl/TIeExamInvigilateCallServiceImpl.java

@@ -9,6 +9,7 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @Description: 监考监控通话申请 服务实现类
@@ -23,8 +24,16 @@ public class TIeExamInvigilateCallServiceImpl extends ServiceImpl<TIeExamInvigil
     @Resource
     TIeExamInvigilateCallMapper tIeExamInvigilateCallMapper;
 
+    /**
+     * 监考监控通话申请查询
+     *
+     * @param iPage
+     * @param examActivityIdSet
+     * @param status
+     * @return
+     */
     @Override
-    public IPage<TIeExamInvigilateCall> examInvigilateCallQuery(IPage<Map> iPage, Long examActivityId, String status) {
-        return tIeExamInvigilateCallMapper.examInvigilateCallQuery(iPage, examActivityId, status);
+    public IPage<TIeExamInvigilateCall> examInvigilateCallQuery(IPage<Map> iPage, Set<Long> examActivityIdSet, String status) {
+        return tIeExamInvigilateCallMapper.examInvigilateCallQuery(iPage, examActivityIdSet, status);
     }
 }

+ 72 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TIeReportServiceImpl.java

@@ -1,18 +1,26 @@
 package com.qmth.themis.business.service.impl;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import javax.annotation.Resource;
 
 import org.springframework.stereotype.Service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.themis.business.base.BasePage;
+import com.qmth.themis.business.bean.backend.ExamViewCountListBean;
 import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
+import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.dao.TEExamStudentMapper;
 import com.qmth.themis.business.dao.TOeExamRecordMapper;
 import com.qmth.themis.business.service.TEExamActivityService;
+import com.qmth.themis.business.service.TEExamService;
 import com.qmth.themis.business.service.TIeReportService;
 
 @Service
@@ -26,6 +34,9 @@ public class TIeReportServiceImpl implements TIeReportService {
     
     @Resource
     TEExamActivityService examActivityService;
+    
+    @Resource
+    TEExamService examService;
 
 	@Override
 	public Map<String, Object> examView(Long examId, Long examActivityId, String roomCode, String courseCode,
@@ -86,5 +97,66 @@ public class TIeReportServiceImpl implements TIeReportService {
 		return ret;
 	}
 
+	@Override
+	public BasePage examViewCount(Long examId, Long examActivityId, String roomCode, String courseCode, String name,
+			String identity, int pageNumber, int pageSize) {
+		//应考人数
+		IPage<ExamViewCountListBean> total = examStudentMapper.getTotalCountInfo(new Page<>(pageNumber, pageSize),examId, examActivityId, roomCode, courseCode);
+        List<ExamViewCountListBean> data=total.getRecords();
+        BasePage basePage = new BasePage(total.getRecords(), total.getCurrent(), total.getSize(), total.getTotal());
+        if(data==null||data.size()==0) {
+        	return basePage;
+        }
+        List<Long> activityIds=data.stream().map(e -> e.getExamActivityId()).collect(Collectors.toList());
+        
+        //实考
+        List<Map<String,Object>> doneCountByDay=examStudentMapper.getDoneCountByActivityIds(examId, activityIds);
+		Map<String,Long> doneMap=new HashMap<String,Long>();
+		for(Map<String,Object> map:doneCountByDay) {
+			Long acId=(Long)map.get("activityId");
+			String roomcode=(String)map.get("roomCode");
+			Long count=(Long)map.get("cc");
+			doneMap.put(acId+"-"+roomcode, count);
+		}
+		
+		//缺考
+		List<Long> absentActivityIds=new ArrayList<>();
+		Date now = new Date();
+		for(Long acid:activityIds) {
+			ExamActivityCacheBean ac=examActivityService.getExamActivityCacheBean(acid);
+			Long end = ac.getStartTime().getTime() + (ac.getOpeningSeconds() * 1000);
+	        if (now.getTime() > end) {//场次开考时间结束,未开考的都是缺考
+	        	absentActivityIds.add(acid);
+	        }
+		}
+		
+		Map<String,Long> absentMap=new HashMap<String,Long>();
+		if(absentActivityIds.size()>0) {
+			List<Map<String,Object>> absentCountByDay=examStudentMapper.getAbsentCountByActivityIds(examId, absentActivityIds);
+			for(Map<String,Object> map:absentCountByDay) {
+				Long acId=(Long)map.get("activityId");
+				String roomcode=(String)map.get("roomCode");
+				Long count=(Long)map.get("cc");
+				absentMap.put(acId+"-"+roomcode, count);
+			}
+		}
+		ExamCacheBean exam=examService.getExamCacheBean(examId);
+		for(ExamViewCountListBean b:data) {
+			Long done=doneMap.get(b.getExamActivityId()+"-"+b.getRoomCode());
+			if(done==null) {
+				done=0L;
+			}
+			Long absent=absentMap.get(b.getExamActivityId()+"-"+b.getRoomCode());
+			if(absent==null) {
+				absent=0L;
+			}
+			b.setActualExamTotal(done);
+			b.setDeficiencyExamTotal(absent);
+			b.setExamName(exam.getName());
+		}
+		basePage = new BasePage(total.getRecords(), total.getCurrent(), total.getSize(), total.getTotal());
+		return basePage;
+	}
+
 
 }

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/templete/service/impl/TempleteLogicServiceImpl.java

@@ -195,7 +195,7 @@ public class TempleteLogicServiceImpl implements TempleteLogicService {
             roomCodeAndNameSet.forEach(s -> {
                 if (Objects.isNull(tbExamInvigilateUserMap) || (Objects.nonNull(tbExamInvigilateUserMap) && Objects.isNull(tbExamInvigilateUserMap.get(s)))) {
                     String[] strs = s.split(":");
-                    TBExamInvigilateUser tbExamInvigilateUser = new TBExamInvigilateUser(orgId, strs[0], strs[1]);
+                    TBExamInvigilateUser tbExamInvigilateUser = new TBExamInvigilateUser(examId, orgId, strs[0], strs[1]);
                     tbExamInvigilateUserService.save(tbExamInvigilateUser);
                     tbExamInvigilateUserList.add(tbExamInvigilateUser);
                     count.getAndIncrement();

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

@@ -304,6 +304,7 @@ CREATE TABLE `t_b_exam_invigilate_user` (
   `room_code` varchar(50) NOT NULL COMMENT '考场代码',
   `room_name` varchar(100) NOT NULL COMMENT '考场名称',
   `monitor_status` varchar(30) DEFAULT NULL COMMENT '监考状态,NOT_START:未开始,START:监考中,FINISHED:已结束',
+  `exam_id` bigint(20) DEFAULT NULL COMMENT '考试批次id',
   PRIMARY KEY (`id`),
   UNIQUE KEY `t_b_exam_invigilate_user_orgId_userId_roomCode_Idx` (`org_id`,`user_id`,`room_code`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='监考员设置';
@@ -505,6 +506,9 @@ INSERT INTO `t_b_privilege` VALUES (139, '监考端撤销通话申请', '/api/ad
 INSERT INTO `t_b_privilege` VALUES (140, '结束监考', '/api/admin/invigilate/exam/finish', 'LINK', 14, 12, NULL, '2020-08-01 12:08:31');
 INSERT INTO `t_b_privilege` VALUES (141, '导入导出任务', 'ImportExportTask', 'MENU', 4, 7, NULL, '2020-08-01 12:08:31');
 INSERT INTO `t_b_privilege` VALUES (142, '监考获取monitorKey', '/api/admin/monitor/getMonitorKey', 'LINK', 60, 28, NULL, '2020-08-01 12:08:31');
+INSERT INTO `t_b_privilege` VALUES (143, '监考监控通话提醒', '/api/admin/monitor/call/count', 'LINK', 60, 29, NULL, '2020-08-01 12:08:31');
+INSERT INTO `t_b_privilege` VALUES (144, '监考监控通话查询', '/api/admin/monitor/call/list', 'LINK', 60, 30, NULL, '2020-08-01 12:08:31');
+INSERT INTO `t_b_privilege` VALUES (145, '监考监控通话查询来源', '/api/admin/monitor/call/query', 'LINK', 60, 31, NULL, '2020-08-01 12:08:31');
 COMMIT;
 
 -- ----------------------------
@@ -700,6 +704,17 @@ INSERT INTO `t_b_role_privilege` VALUES (157, 'ADMIN', 25);
 INSERT INTO `t_b_role_privilege` VALUES (158, 'INVIGILATE', 142);
 INSERT INTO `t_b_role_privilege` VALUES (159, 'INSPECTION', 11);
 INSERT INTO `t_b_role_privilege` VALUES (160, 'INSPECTION', 13);
+INSERT INTO `t_b_role_privilege` VALUES (161, 'INVIGILATE', 35);
+INSERT INTO `t_b_role_privilege` VALUES (162, 'INSPECTION', 35);
+INSERT INTO `t_b_role_privilege` VALUES (163, 'ADMIN', 143);
+INSERT INTO `t_b_role_privilege` VALUES (164, 'INVIGILATE', 143);
+INSERT INTO `t_b_role_privilege` VALUES (165, 'INSPECTION', 143);
+INSERT INTO `t_b_role_privilege` VALUES (166, 'ADMIN', 144);
+INSERT INTO `t_b_role_privilege` VALUES (167, 'INVIGILATE', 144);
+INSERT INTO `t_b_role_privilege` VALUES (168, 'INSPECTION', 144);
+INSERT INTO `t_b_role_privilege` VALUES (169, 'ADMIN', 145);
+INSERT INTO `t_b_role_privilege` VALUES (170, 'INVIGILATE', 145);
+INSERT INTO `t_b_role_privilege` VALUES (171, 'INSPECTION', 145);
 COMMIT;
 
 -- ----------------------------
@@ -1455,6 +1470,7 @@ CREATE TABLE `t_oe_exam_record` (
   `monitor_status_source` varchar(30) DEFAULT NULL COMMENT '监控状态,stop:停止,start:正常',
   `monitor_live_url` varchar(100) DEFAULT NULL COMMENT '监控观看地址',
   `score_status` varchar(30) DEFAULT NULL COMMENT '算分状态,never:从未算分,calculating:正在算分,finish:算分完成',
+  `exception_status` varchar(30) DEFAULT NULL COMMENT '异常状态',
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='考试记录';
 

+ 11 - 15
themis-business/src/main/resources/mapper/TBExamInvigilateUserMapper.xml

@@ -5,7 +5,8 @@
     <sql id="queryCommon">
         (
         select
-        tbeiu.room_code as roomCode, tbeiu.room_name as roomName, tbeiu.user_id as userId, (
+        tbeiu.room_code as roomCode, tbeiu.room_name as roomName, tbeiu.user_id as userId,tee.id as examId,
+        tee.name as examName, (
         select
         tbu.name
         from
@@ -14,7 +15,12 @@
         tbu.id = tbeiu.user_id) as name
         from
         t_b_exam_invigilate_user tbeiu
+        left join t_e_exam tee on
+        tee.id = tbeiu.exam_id
         <where>
+            <if test="examId != null and examId != ''">
+                and tbeiu.exam_id = #{examId}
+            </if>
             <if test="userId != null and userId != ''">
                 and tbeiu.user_id = #{userId}
             </if>
@@ -27,6 +33,8 @@
 
     <select id="examInvigilateUserQuery" resultType="com.qmth.themis.business.dto.response.TBExamInvigilateUserDto">
         select
+        t.examId,
+        t.examName,
         t.roomCode,
         t.roomName,
         GROUP_CONCAT(t.userId) as userId,
@@ -40,6 +48,8 @@
 
     <select id="examInvigilateUserExport" resultType="com.qmth.themis.business.dto.RoomCodeExportDto">
         select
+        t.examId,
+        t.examName,
         t.roomCode,
         t.roomName,
         GROUP_CONCAT(t.name) as name
@@ -49,18 +59,4 @@
         t.roomCode,
         t.roomName
     </select>
-
-    <select id="examRoomQuery" resultType="com.qmth.themis.business.dto.response.RoomCodeQueryDto">
-        select
-            DISTINCT
-            tbeiu.room_code as roomCode,
-            tbeiu.room_name as roomName
-        from
-            t_b_exam_invigilate_user tbeiu
-        <where>
-            <if test="roomName != null and roomName != ''">
-                and tbeiu.room_name like concat('%', #{roomName}, '%')
-            </if>
-        </where>
-    </select>
 </mapper>

+ 13 - 1
themis-business/src/main/resources/mapper/TEExamMapper.xml

@@ -64,7 +64,19 @@
         where
         t1.id = t.update_id) as updateName
         from t_e_exam t
-        <where>
+        <where> 1 = 1
+            <if test="userId != null and userId != ''">
+                and EXISTS(
+                select
+                DISTINCT tees.exam_id
+                from
+                t_b_exam_invigilate_user tbeiu
+                left join t_e_exam_student tees on
+                tees.room_code = tbeiu.room_code
+                where
+                tbeiu.user_id = #{userId}
+                and t.id = tees.exam_id)
+            </if>
             <if test="id != null and id != ''">
                 and t.id = #{id}
             </if>

+ 53 - 0
themis-business/src/main/resources/mapper/TEExamStudentMapper.xml

@@ -71,4 +71,57 @@
             </if>
          group by t.exam_activity_id
     </select>
+    
+    <select id="getTotalCountInfo" resultType="com.qmth.themis.business.bean.backend.ExamViewCountListBean">
+    	select t.exam_id examId,t.exam_activity_id examActivityId,t.room_code roomCode,t.room_name roomName, count(1) examTotal from t_e_exam_student t
+    	where  t.exam_id = #{examId}
+            <if test="activityId != null and activityId != ''">
+                and t.exam_activity_id = #{activityId}
+            </if>
+            <if test="roomCode != null and roomCode != ''">
+                and t.room_code =#{roomCode}
+            </if>
+            <if test="courseCode != null and courseCode != ''">
+                and t.course_code = #{courseCode}
+            </if>
+         group by t.exam_id,t.exam_activity_id, t.room_code,t.room_name
+    </select>
+    
+    <select id="getDoneCountByActivityIds" resultType="java.util.Map">
+    	select t.exam_activity_id activityId,t.room_code roomCode,count(1) cc from t_e_exam_student t
+    	where  t.exam_id = #{examId} and t.current_record_id is not null
+        <if test="activityIds != null">
+            and t.exam_activity_id in 
+            <foreach collection="activityIds" item="acid" index="index" open="(" close=")" separator=",">
+		    	#{acid}
+		   	</foreach>
+        </if>
+        group by t.exam_activity_id, t.room_code
+    </select>
+    
+    <select id="getAbsentCountByActivityIds" resultType="java.util.Map">
+    	select t.exam_activity_id activityId,t.room_code roomCode,count(1) cc from t_e_exam_student t
+    	where  t.exam_id = #{examId} and t.current_record_id is null
+        <if test="activityIds != null">
+            and t.exam_activity_id in 
+            <foreach collection="activityIds" item="acid" index="index" open="(" close=")" separator=",">
+		    	#{acid}
+		   	</foreach>
+        </if>
+        group by t.exam_activity_id, t.room_code
+    </select>
+
+    <select id="examRoomQuery" resultType="com.qmth.themis.business.dto.response.RoomCodeQueryDto">
+        select
+        DISTINCT
+        tees.room_code as roomCode,
+        tees.room_name as roomName
+        from
+        t_e_exam_student tees
+        <where>
+            <if test="roomName != null and roomName != ''">
+                and tees.room_name like concat('%', #{roomName}, '%')
+            </if>
+        </where>
+    </select>
 </mapper>

+ 4 - 3
themis-business/src/main/resources/mapper/TIeExamInvigilateCallMapper.xml

@@ -8,9 +8,10 @@
         from
             t_ie_exam_invigilate_call tieic
         <where>
-            <if test="examActivityId != null and examActivityId != ''">
-                and tieic.exam_activity_id = #{examActivityId}
-            </if>
+            tieic.exam_activity_id in
+            <foreach collection="examActivityIdSet" item="examActivityId" index="index" open="(" close=")" separator=",">
+                #{examActivityId}
+            </foreach>
             <if test="status != null and status != ''">
                 and tieic.status = #{status}
             </if>

+ 23 - 12
themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml

@@ -92,19 +92,22 @@
             s.name name,
             s.course_name courseName,
             s.course_code courseCode,
-            t.paper_download paperDownload,
+            IFNULL(t.paper_download,1) paperDownload,
             t.status statusCode,
             t.answer_progress progress,
-            t.client_current_ip clientCurrentIp,
-            t.warning_count warningCount,
-            t.breach_status breachStatus,
-            t.client_websocket_status as clientWebsocketStatus,
-            t.monitor_status_source as monitorStatusSource
+            IFNULL(t.client_current_ip,'无') clientCurrentIp,
+            IFNULL(t.warning_count,0) as warningCount,
+            IFNULL(t.breach_status,1) as breachStatus,
+            IFNULL(t.client_websocket_status,'OFF_LINE') as clientWebsocketStatus,
+            IFNULL(t.monitor_status_source,'STOP') as monitorStatusSource,
+            t.client_last_sync_time as updateTime
     </sql>
 
     <sql id="invigilatePageMiddle">
         from t_oe_exam_record t
         left join t_e_exam_student s on t.exam_student_id = s.id
+        left join t_e_exam tee on tee.id = t.exam_id
+        left join t_e_exam_activity teea on teea.id = t.exam_activity_id
         inner join (select toer.id from t_oe_exam_record toer where EXISTS(select tees.id from t_e_exam_student tees where EXISTS (select distinct tbeiu.room_code from t_b_exam_invigilate_user tbeiu
         where
         <if test="userId != null and userId != ''">
@@ -125,7 +128,14 @@
                 and s.room_code = #{roomCode}
             </if>
             <if test="status != null and status != ''">
-                and t.status = #{status}
+                <choose>
+                    <when test="status == EXCEPTION">
+                        and t.exception_status is not null
+                    </when>
+                    <otherwise>
+                        and t.status = #{status}
+                    </otherwise>
+                </choose>
             </if>
             <if test="name != null and name !=''">
                 and s.name like CONCAT('%', #{name},'%')
@@ -151,9 +161,10 @@
 
     <select id="invigilatePageList" resultType="com.qmth.themis.business.bean.backend.InvigilateListBean">
         <include refid="invigilatePageHead" />
+        ,(select count(1) from t_ie_invigilate_warn_info tiiwi where tiiwi.exam_record_id = t.id and tiiwi.approve_status = 0) as warningNew
+        ,date_format(date_sub(date_add(teea.start_time, interval IFNULL(teea.max_duration_seconds, tee.max_duration_seconds) second), interval teea.max_duration_seconds / 60 - t.duration_seconds minute),'%H:%i:%s') as remainTime
         <include refid="invigilatePageMiddle" />
         <include refid="invigilatePageFoot" />
-            and t.status = 'ANSWERING'
         <if test="paperDownload != null and paperDownload != ''">
             and t.paper_download = #{paperDownload}
         </if>
@@ -165,7 +176,6 @@
         ,t.monitor_live_url as monitorLiveUrl
         <include refid="invigilatePageMiddle" />
         <include refid="invigilatePageFoot" />
-            and t.status = 'ANSWERING'
         <if test="paperDownload != null and paperDownload != ''">
             and t.paper_download = #{paperDownload}
         </if>
@@ -179,7 +189,7 @@
         'FACE_COUNT_ERROR' and tiiwi.`level` = 'D8') as multipleFaceCount
         <include refid="invigilatePageMiddle"/>
         <include refid="invigilatePageFoot" />
-            and t.status = 'ANSWERING' ) t
+            ) t
         <where>
             <if test="minMultipleFaceCount != null and minMultipleFaceCount != ''">
                 and t.multipleFaceCount &lt;= #{minMultipleFaceCount}
@@ -212,8 +222,9 @@
            tees.course_code as courseCode,
            tees.course_name as courseName,
            toer.status as statusCode,
-           toer.warning_count as warningCount,
-           toer.breach_status as breachStatus,
+           IFNULL(toer.warning_count,0) as warningCount,
+           IFNULL(toer.breach_status,1) as breachStatus,
+           toer.client_last_sync_time as updateTime
            tiiwi.approve_status as approveStatus
            ,(select count(1) from t_ie_invigilate_warn_info tiiwi where tiiwi.exam_record_id = toer.id and tiiwi.`type` =
             'FACE_COUNT_ERROR' and tiiwi.`level` = 'D8') as multipleFaceCount

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

@@ -1,6 +1,7 @@
 package com.qmth.themis.exam.api;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.google.gson.Gson;
 import com.qmth.themis.business.annotation.ApiJsonObject;
 import com.qmth.themis.business.annotation.ApiJsonProperty;
@@ -20,6 +21,7 @@ import com.qmth.themis.business.dto.response.TEExamDto;
 import com.qmth.themis.business.dto.response.TEExamResultDto;
 import com.qmth.themis.business.entity.TBSession;
 import com.qmth.themis.business.entity.TEConfig;
+import com.qmth.themis.business.entity.TEExamStudent;
 import com.qmth.themis.business.entity.TEStudent;
 import com.qmth.themis.business.enums.*;
 import com.qmth.themis.business.service.*;
@@ -264,6 +266,10 @@ public class TEStudentController {
         if (Objects.isNull(tbSession)) {
             throw new BusinessException(ExceptionResultEnum.LOGIN_NO);
         }
+        Long recordId = Objects.isNull(teStudent.getExamingRecordId()) ? teStudent.getUnFinishedRecordId() : teStudent.getExamingRecordId();
+        Map<String, Object> objectMap = redisUtil.getHashEntries(RedisKeyHelper.examRecordCacheKey(recordId));
+        Long examStudentId = Long.parseLong(String.valueOf(objectMap.get("examStudentId")));
+        ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
         AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.studentOauth + "::" + teStudent.getId());
         redisUtil.deleteUserSession(tbSession.getId());
         //循环检查该用户下其他平台是否存在session,不存在则删除用户缓存和鉴权缓存

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

@@ -2,6 +2,7 @@ package com.qmth.themis.mq.service.impl;
 
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.google.gson.Gson;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
@@ -484,7 +485,17 @@ public class MqLogicServiceImpl implements MqLogicService {
                 objectMap.put("lastBreakTime", new Date());
                 objectMap.put("leftBreakResumeCount", leftBreakResumeCount);
                 objectMap.put("lastStartTime", new Date());
+                objectMap.put("exceptionStatus", exceptionEnum);
                 redisUtil.setForHash(RedisKeyHelper.examRecordCacheKey(recordId), objectMap);
+                UpdateWrapper<TOeExamRecord> tOeExamRecordUpdateWrapper = new UpdateWrapper<>();
+                tOeExamRecordUpdateWrapper.lambda().set(TOeExamRecord::getLastBreakId, tOeExamBreakHistory.getId())
+                        .set(TOeExamRecord::getStatus, ExamRecordStatusEnum.RESUME_PREPARE)
+                        .set(TOeExamRecord::getLastBreakTime, objectMap.get("lastBreakTime"))
+                        .set(TOeExamRecord::getLeftBreakResumeCount, leftBreakResumeCount)
+                        .set(TOeExamRecord::getLastStartTime, objectMap.get("lastStartTime"))
+                        .set(TOeExamRecord::getExceptionStatus, exceptionEnum)
+                        .eq(TOeExamRecord::getId, recordId);
+                examRecordService.update(tOeExamRecordUpdateWrapper);
                 teExamStudentLogService.saveStudentLogInfo(SystemOperationEnum.RESUME_PREPARE.name(), SystemOperationEnum.RESUME_PREPARE.getCode(), SystemOperationEnum.RESUME_PREPARE.getCode(), examStudentCacheBean.getStudentId(), examStudentId, recordId);
             }