wangliang 4 years ago
parent
commit
792d942399

+ 55 - 21
themis-backend/src/main/java/com/qmth/themis/backend/api/TEExamReexamController.java

@@ -1,17 +1,16 @@
 package com.qmth.themis.backend.api;
 
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.themis.business.annotation.ApiJsonObject;
 import com.qmth.themis.business.annotation.ApiJsonProperty;
 import com.qmth.themis.business.bean.backend.ReexamListRequestBean;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
+import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.AuthDto;
-import com.qmth.themis.business.entity.TBUser;
-import com.qmth.themis.business.entity.TEExamReexam;
-import com.qmth.themis.business.entity.TEExamReexamAuditing;
-import com.qmth.themis.business.entity.TOeExamRecord;
+import com.qmth.themis.business.entity.*;
 import com.qmth.themis.business.enums.ReexamReasonEnum;
 import com.qmth.themis.business.enums.RoleEnum;
 import com.qmth.themis.business.service.*;
@@ -61,6 +60,9 @@ public class TEExamReexamController {
     @Resource
     TEExamReexamAuditingService teExamReexamAuditingService;
 
+    @Resource
+    TEExamStudentService teExamStudentService;
+
     @ApiOperation(value = "重考申请接口")
     @RequestMapping(value = "/apply", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
@@ -88,6 +90,7 @@ public class TEExamReexamController {
             Long examId = null, examStudentId = null, examActivityId = null;
             Integer reexamAuditing = null, status;
             List<TEExamReexamAuditing> teExamReexamAuditingList = new ArrayList<>();
+            Set<Long> examStudentIdList = new HashSet<>();
             for (String s : recordIdList) {
                 //获取考试记录缓存
                 Long recordId = Long.parseLong(s);
@@ -102,29 +105,49 @@ public class TEExamReexamController {
                     examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
                     examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
                 }
-                ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);//考试缓存
-                if (Objects.isNull(examCacheBean)) {
-                    throw new BusinessException("考试批次[" + examCacheBean + "]不存在");
-                }
-                reexamAuditing = examCacheBean.getReexamAuditing();
-                status = Objects.isNull(reexamAuditing) || reexamAuditing.intValue() == 0 ? 0 : 1;
-                TEExamReexam teExamReexam = new TEExamReexam(examId, examActivityId, Long.parseLong(s), examStudentId, model, reason, status, Objects.isNull(mapParameter.get("remark")) ? null : String.valueOf(mapParameter.get("remark")));
-                teExamReexam.setCreateId(tbUser.getId());
-                teExamReexamService.save(teExamReexam);
-                if (Objects.nonNull(status) && status.intValue() == 1) {
-                    //这里查询该机构下所有为管理员角色的账号
-                    List<TBUser> tbUserList = tbUserRoleService.userQueryByRole(tbUser.getOrgId(), RoleEnum.ADMIN.name());
-                    if (Objects.nonNull(tbUserList) && tbUserList.size() > 0) {
-                        for (TBUser t : tbUserList) {
-                            TEExamReexamAuditing teExamReexamAuditing = new TEExamReexamAuditing(teExamReexam.getId(), t.getId());
-                            teExamReexamAuditingList.add(teExamReexamAuditing);
+                if (redisUtil.lock(SystemConstant.REDIS_LOCK_EXAM_STUDENT_PREFIX + examStudentId, SystemConstant.REDIS_LOCK_REEXAM_EXAM_STUDENT_TIME_OUT)) {
+                    ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);//考试缓存
+                    if (Objects.isNull(examCacheBean)) {
+                        throw new BusinessException("考试批次[" + examCacheBean + "]不存在");
+                    }
+                    reexamAuditing = examCacheBean.getReexamAuditing();
+                    status = Objects.isNull(reexamAuditing) || reexamAuditing.intValue() == 0 ? 0 : 1;
+                    TEExamReexam teExamReexam = new TEExamReexam(examId, examActivityId, Long.parseLong(s), examStudentId, model, reason, status, Objects.isNull(mapParameter.get("remark")) ? null : String.valueOf(mapParameter.get("remark")));
+                    teExamReexam.setCreateId(tbUser.getId());
+                    teExamReexamService.save(teExamReexam);
+                    if (Objects.nonNull(status) && status.intValue() == 1) {
+                        //这里查询该机构下所有为管理员角色的账号
+                        List<TBUser> tbUserList = tbUserRoleService.userQueryByRole(tbUser.getOrgId(), RoleEnum.ADMIN.name());
+                        if (Objects.nonNull(tbUserList) && tbUserList.size() > 0) {
+                            for (TBUser t : tbUserList) {
+                                TEExamReexamAuditing teExamReexamAuditing = new TEExamReexamAuditing(teExamReexam.getId(), t.getId());
+                                teExamReexamAuditingList.add(teExamReexamAuditing);
+                            }
                         }
+                    } else if (Objects.nonNull(status) && status.intValue() == 0) {//无需审核时考生已考次数-1
+                        examStudentIdList.add(examStudentId);
                     }
                 }
             }
             if (Objects.nonNull(teExamReexamAuditingList) && teExamReexamAuditingList.size() > 0) {
                 teExamReexamAuditingService.saveBatch(teExamReexamAuditingList);
             }
+            if (Objects.nonNull(examStudentIdList) && examStudentIdList.size() > 0) {
+                examStudentIdList.forEach(s -> {
+                    ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(s);
+                    if (Objects.nonNull(examStudentCacheBean)) {
+                        Integer alreadyExamCount = Objects.nonNull(examStudentCacheBean.getAlreadyExamCount()) ? examStudentCacheBean.getAlreadyExamCount() : 0;
+                        if (alreadyExamCount > 0) {
+                            alreadyExamCount = alreadyExamCount - 1;
+                            UpdateWrapper<TEExamStudent> teExamStudentUpdateWrapper = new UpdateWrapper<>();
+                            teExamStudentUpdateWrapper.lambda().set(TEExamStudent::getAlreadyExamCount, alreadyExamCount)
+                                    .eq(TEExamStudent::getId, s);
+                            teExamStudentService.update(teExamStudentUpdateWrapper);
+                            teExamStudentService.updateExamStudentCacheBean(s);
+                        }
+                    }
+                });
+            }
         }
         return ResultUtil.ok(Collections.singletonMap("success", true));
     }
@@ -167,7 +190,18 @@ public class TEExamReexamController {
                             teExamReexam.setStatus(2);
                             teExamReexam.setUpdateId(tbUser.getId());
                             teExamReexamUpdateList.add(teExamReexam);
-                            teExamReexamService.updateById(teExamReexam);
+                            ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(teExamReexam.getExamStudentId());
+                            if (Objects.nonNull(examStudentCacheBean)) {
+                                Integer alreadyExamCount = Objects.nonNull(examStudentCacheBean.getAlreadyExamCount()) ? examStudentCacheBean.getAlreadyExamCount() : 0;
+                                if (alreadyExamCount > 0) {
+                                    alreadyExamCount = alreadyExamCount - 1;
+                                    UpdateWrapper<TEExamStudent> teExamStudentUpdateWrapper = new UpdateWrapper<>();
+                                    teExamStudentUpdateWrapper.lambda().set(TEExamStudent::getAlreadyExamCount, alreadyExamCount)
+                                            .eq(TEExamStudent::getId, teExamReexam.getExamStudentId());
+                                    teExamStudentService.update(teExamStudentUpdateWrapper);
+                                    teExamStudentService.updateExamStudentCacheBean(teExamReexam.getExamStudentId());
+                                }
+                            }
                         }
                     }
                 }

+ 6 - 1
themis-backend/src/main/java/com/qmth/themis/backend/api/TIeInvigilateController.java

@@ -1,6 +1,7 @@
 package com.qmth.themis.backend.api;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.themis.business.annotation.ApiJsonObject;
 import com.qmth.themis.business.annotation.ApiJsonProperty;
@@ -257,6 +258,11 @@ public class TIeInvigilateController {
         int multipleFaceCount = tIeInvigilateWarnInfoService.count(tIeInvigilateWarnInfoQueryWrapper);
         invigilateListDetailBean.setMultipleFaceCount(multipleFaceCount);
 
+        //清除预警未阅状态
+        UpdateWrapper<TIeInvigilateWarnInfo> tIeExamInvigilateNoticeUpdateWrapper = new UpdateWrapper<>();
+        tIeExamInvigilateNoticeUpdateWrapper.lambda().set(TIeInvigilateWarnInfo::getApproveStatus, 1)
+                .eq(TIeInvigilateWarnInfo::getExamRecordId, examRecordId);
+        tIeInvigilateWarnInfoService.update(tIeExamInvigilateNoticeUpdateWrapper);
         return ResultUtil.ok(invigilateListDetailBean);
     }
 
@@ -427,7 +433,6 @@ public class TIeInvigilateController {
                 });
             }
             teExamBreachLogService.saveOrUpdateBatch(teExamBreachLogList);
-            //todo 这里是否需要收卷处理
         }
         return ResultUtil.ok(Collections.singletonMap("success", true));
     }

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

@@ -101,9 +101,12 @@ public class SystemConstant {
     public static final long REDIS_LOCK_MQ_TIME_OUT = 60L;
     public static final long REDIS_LOCK_WEBSOCKET_TIME_OUT = 30L;
     public static final long REDIS_LOCK_REEXAM_TIME_OUT = 30L;
+    public static final long REDIS_LOCK_REEXAM_EXAM_STUDENT_TIME_OUT = 30L;
     public static final long REDIS_CACHE_TIME_OUT = 30L;
     //学生锁
     public static final String REDIS_LOCK_STUDENT_PREFIX = "lock:student:student_id_";
+    //考生锁
+    public static final String REDIS_LOCK_EXAM_STUDENT_PREFIX = "lock:student:student_id_";
     //计算客观分总分锁
     public static final String REDIS_LOCK_TOTAL_OBJECTIVE_SCORE_PREFIX = "lock:total_objective_score:record_id_";
 

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

@@ -82,7 +82,7 @@
 
 	<sql id="invigilatePageHead">
 		select
-		t.exam_id examId,
+		distinct t.exam_id examId,
 		tee.name as examName,
 		t.exam_activity_id examActivityId,
 		teea.code as examActivityCode,
@@ -185,7 +185,7 @@
             and t.paper_download = #{paperDownload}
         </if>
 		<if test="status == null or status == ''">
-			and t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE'
+			and (t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE')
 		</if>
         ) t,
         (SELECT @i := 0) as i
@@ -208,7 +208,7 @@
 			and t.paper_download = #{paperDownload}
 		</if>
 		<if test="status == null or status == ''">
-			and t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE'
+			and (t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE')
 		</if>
 		) t,
 		(SELECT @i := 0) as i
@@ -221,12 +221,12 @@
 		,(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(from_unixtime(IFNULL(teea.max_duration_seconds, tee.max_duration_seconds) - t.duration_seconds),INTERVAL 8 HOUR), '%H:%i:%s') as remainTime
 		<include refid="invigilatePageMiddle" />
+		<where> 1 = 1
 		<if test="examId != null and examId != ''">
 			and t.exam_id = #{examId}
 		</if>
-		<if test="status == null or status == ''">
-			and t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE'
-		</if>
+			and (t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE')
+		</where>
 		ORDER BY RAND() LIMIT #{randomNum}
 	</select>
 
@@ -238,14 +238,15 @@
 		,date_format(date_sub(from_unixtime(IFNULL(teea.max_duration_seconds, tee.max_duration_seconds) - t.duration_seconds),INTERVAL 8 HOUR), '%H:%i:%s') as remainTime
 		<include refid="invigilatePageMiddle" />
 		<include refid="invigilatePageFoot" />
+			<if test="status == null or status == ''">
+				and (t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE')
+			</if>
 		) t
 		<where>
-			<if
-				test="minMultipleFaceCount != null and minMultipleFaceCount != '' or minMultipleFaceCount == 0">
+			<if test="minMultipleFaceCount != null and minMultipleFaceCount != '' or minMultipleFaceCount == 0">
 				and t.multipleFaceCount &lt;= #{minMultipleFaceCount}
 			</if>
-			<if
-				test="maxMultipleFaceCount != null and maxMultipleFaceCount != '' or maxMultipleFaceCount == 0">
+			<if test="maxMultipleFaceCount != null and maxMultipleFaceCount != '' or maxMultipleFaceCount == 0">
 				and t.multipleFaceCount &gt;= #{maxMultipleFaceCount}
 			</if>
 			<if test="minExceptionCount != null and minExceptionCount != '' or minExceptionCount == 0">
@@ -616,7 +617,7 @@
 			and tee.enable = 1
 			and teea.enable = 1
 			and teea.finish_time > unix_timestamp(current_timestamp()) * 1000
-			and t.client_websocket_status = 'OFF_LINE'
+			and (t.status = 'FIRST_PREPARE' or t.status = 'ANSWERING' or t.status = 'BREAK_OFF' or t.status = 'RESUME_PREPARE')
 		</where> ) t
 		group by
 		t.roomCode,