diff --git a/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/controller/admin/monitor/vo/StuMonitorPaperVo.java b/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/controller/admin/monitor/vo/StuMonitorPaperVo.java index c7307f7a..a1c4ccaf 100644 --- a/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/controller/admin/monitor/vo/StuMonitorPaperVo.java +++ b/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/controller/admin/monitor/vo/StuMonitorPaperVo.java @@ -15,4 +15,5 @@ public class StuMonitorPaperVo { private String taskId; + private String temporaryId; } diff --git a/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/controller/admin/paper/vo/ExamPaperVo.java b/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/controller/admin/paper/vo/ExamPaperVo.java index 5909ebac..776d4304 100644 --- a/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/controller/admin/paper/vo/ExamPaperVo.java +++ b/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/controller/admin/paper/vo/ExamPaperVo.java @@ -7,6 +7,8 @@ import pc.exam.pp.module.exam.dal.dataobject.EducationPaperSession; import pc.exam.pp.module.exam.dal.dataobject.ExamQuestion; import java.util.List; + + @Data public class ExamPaperVo { String paperId; @@ -24,19 +26,4 @@ public class ExamPaperVo { this.educationPaperSchemeList = educationPaperSchemeList; } - public List getExamQuestionList() { - return examQuestionList; - } - - public void setExamQuestionList(List examQuestionList) { - this.examQuestionList = examQuestionList; - } - - public List getEducationPaperSchemeList() { - return educationPaperSchemeList; - } - - public void setEducationPaperSchemeList(List educationPaperSchemeList) { - this.educationPaperSchemeList = educationPaperSchemeList; - } } diff --git a/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/dal/dataobject/EducationPaperParam.java b/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/dal/dataobject/EducationPaperParam.java index 6f2d5c16..c1ebfc59 100644 --- a/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/dal/dataobject/EducationPaperParam.java +++ b/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/dal/dataobject/EducationPaperParam.java @@ -38,7 +38,6 @@ public class EducationPaperParam private String isAnswerId; /** 是否使用监考密码验证(0是1否) */ - // @Excel(name = "是否使用监考密码验证", readConverterExp = "0=是1否") private String isExamPassword; /** 监考密码 */ @@ -46,15 +45,12 @@ public class EducationPaperParam private String examPassword; /** 禁止学生使用U盘(0是1否) */ - // @Excel(name = "禁止学生使用U盘", readConverterExp = "0=是1否") private String usb; /** 练习成绩保存0最高成绩1最新成绩 */ - // @Excel(name = "练习成绩保存0最高成绩1最新成绩") private String saveGrades; /** 驱动器为学生文件存放系统盘(C,D) */ - // @Excel(name = "驱动器为学生文件存放系统盘", readConverterExp = "C=,D") private String driver; /** 考试目录名称 */ @@ -62,11 +58,9 @@ public class EducationPaperParam private String directory; /** 考试的模式下定时上传考试目录,每{x}分钟传一次 */ - // @Excel(name = "考试的模式下定时上传考试目录,每{x}分钟传一次") private String uploadTime; /** 是否允许复制题干(0是1否) */ - // @Excel(name = "完成考试后是否删除考试目录", readConverterExp = "0=是1否") private String isCopy; //是否显示重答按钮 diff --git a/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/service/monitor/MonitorServiceImpl.java b/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/service/monitor/MonitorServiceImpl.java index 14464be1..096365a6 100644 --- a/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/service/monitor/MonitorServiceImpl.java +++ b/exam-module-exam/exam-module-exam-biz/src/main/java/pc/exam/pp/module/exam/service/monitor/MonitorServiceImpl.java @@ -260,6 +260,7 @@ public class MonitorServiceImpl implements MonitorService { LocalDateTime nowTime = LocalDateTime.now(); DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); info.setStartTime(nowTime.format(formatter1)); + info.setTemporaryId(stuMonitorPaperVo.getTemporaryId()); info.setIp(stuMonitorPaperVo.getIp()); if (info.getRemainingTime() == null) { diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/AutoToolsController.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/AutoToolsController.java index 9af70b2b..f0c772b2 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/AutoToolsController.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/AutoToolsController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.validation.annotation.Validated; @@ -15,7 +16,10 @@ import pc.exam.pp.framework.common.util.servlet.ServletUtils; import pc.exam.pp.framework.security.config.SecurityProperties; import pc.exam.pp.framework.security.core.LoginUser; import pc.exam.pp.framework.security.core.util.SecurityFrameworkUtils; +import pc.exam.pp.module.exam.controller.admin.paper.vo.ExamPaperVo; import pc.exam.pp.module.exam.dal.dataobject.*; +import pc.exam.pp.module.exam.dal.dataobject.monitor.MonitorDO; +import pc.exam.pp.module.exam.dal.dataobject.student.StuPaperFileDO; import pc.exam.pp.module.exam.dal.dataobject.student.StuPaperScoreDO; import pc.exam.pp.module.exam.dal.mysql.paper.EducationPaperPersonMapper; import pc.exam.pp.module.exam.dal.mysql.paper.EducationPaperQuMapper; @@ -23,16 +27,17 @@ import pc.exam.pp.module.exam.dal.mysql.paper.EducationPaperSessionMapper; import pc.exam.pp.module.exam.dal.mysql.question.ExamQuestionMapper; import pc.exam.pp.module.exam.dal.mysql.student.StuScoreVo; import pc.exam.pp.module.exam.service.paper.IEducationPaperParamService; +import pc.exam.pp.module.exam.service.paper.IEducationPaperQuService; import pc.exam.pp.module.exam.service.stuPaperScore.StuPaperScoreService; -import pc.exam.pp.module.judgement.controller.admin.autoTools.vo.StuInTheExam; -import pc.exam.pp.module.judgement.controller.admin.autoTools.vo.StuPaperReqVo; -import pc.exam.pp.module.judgement.controller.admin.autoTools.vo.StuPaperScoreInfoVo; -import pc.exam.pp.module.judgement.controller.admin.autoTools.vo.StuTheExamInfo; +import pc.exam.pp.module.exam.service.stu_paper_file.StuPaperFileService; +import pc.exam.pp.module.judgement.controller.admin.autoTools.vo.*; import pc.exam.pp.module.judgement.service.TaskManager; import pc.exam.pp.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import java.time.Duration; import java.time.Instant; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.List; import java.util.Map; @@ -67,6 +72,10 @@ public class AutoToolsController { IEducationPaperParamService educationPaperParamService; @Resource StringRedisTemplate stringRedisTemplate; + @Resource + IEducationPaperQuService educationPaperQuService; + @Resource + StuPaperFileService stuPaperFileService; @GetMapping("/getStuScoreInfo") @Operation(summary = "通过学生ID、试卷ID获取") @@ -161,31 +170,120 @@ public class AutoToolsController { stuTheExamInfo.setTime(formatLongDuration(countdown.get())); // 返回数据-上传文件状态 0:上传;1:不上传 stuTheExamInfo.setUpload(1); - // 返回数据-上传文件状态 0:结束;1:不结束 + // 返回数据-结束考试 0:结束;1:不结束 stuTheExamInfo.setEndStatus(1); // 返回数据-网络状态 stuTheExamInfo.setNetwork("强"); // 创建对应的线程池 if (loginUser != null) { - taskManager.startTask(stuInTheExam, stuTheExamInfo, token, countdown, new AtomicInteger(0), String.valueOf(loginUser.getId())); + taskManager.startTask(stuInTheExam, stuTheExamInfo, token, countdown, new AtomicInteger(0), loginUser.getId() + "_" + stuInTheExam.getTaskId() + "_" + stuInTheExam.getPaperId()); } - System.out.println("--------------token------------------" + token); return CommonResult.success(token); } return CommonResult.success("未登录"); } + // 学生端重新登录,判断是否上一次考试没有结束就退出了 + @GetMapping("/reStartExamStatus") + public CommonResult reStartExamStatus() { + HttpServletRequest request = ServletUtils.getRequest(); + // 获取学生ID + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + if (loginUser != null) { + long userId = loginUser.getId(); + String key = taskManager.getTaskById(String.valueOf(userId)); + if (key == null) { + return CommonResult.success("0"); + } + return CommonResult.success(key); + } + return CommonResult.success("0"); + } + + // 学生端考试没有结束对出,继续进行开始(需要返回下载文件地址,任务ID) + @PostMapping("/reStartExam") + public CommonResult reStartExam(@RequestBody StuInTheExam stuInTheExam) { + // 获取学生ID + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + HttpServletRequest request = ServletUtils.getRequest(); + String token = SecurityFrameworkUtils.obtainAuthorization(request, + securityProperties.getTokenHeader(), securityProperties.getTokenParameter()); + ExamRestartPaperVo examRestartPaperVo = new ExamRestartPaperVo(); + // 如果继续考试,需要关闭之前的,重新开始ws + String taskManagerId = loginUser.getId() + "_" + stuInTheExam.getTaskId() + "_" + stuInTheExam.getPaperId(); + taskManager.stopTask(taskManagerId); + if (loginUser != null) { + // 获取试卷详情 + ExamPaperVo examPaperVo = educationPaperQuService.selectPaperQuListByPaperId(stuInTheExam.getPaperId()); + // 获取剩余的时间 + String key = "userCache:" + stuInTheExam.getTaskId() + ":" + loginUser.getId(); + MonitorDO info = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), MonitorDO.class); + if (info != null) { + // 获取随机ID + String temporaryId = info.getTemporaryId(); + // 获取开始时间 + String startTimeExam = info.getStartTime(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime targetTime = LocalDateTime.parse(startTimeExam, formatter); + LocalDateTime currentTime = LocalDateTime.now(); + Duration duration = Duration.between(currentTime, targetTime); + // 两者相差的时间 + long secondsDifference = duration.getSeconds(); + // 获取一共要考试多长时间 + long remainingTime = info.getRemainingTime(); + // 判断剩余时间是否大于等于两者相差的时间 + long times = remainingTime - secondsDifference; + // 开启ws + // 获取上传文件时间 + String time = examPaperVo.getEducationPaperParam().getUploadTime(); + // 将分钟继续转换成秒 + stuInTheExam.setTimes(Integer.parseInt(time) * 60); + // 倒计时 + AtomicInteger countdown = new AtomicInteger((int) times); + // 创建初始返回数据 + StuTheExamInfo stuTheExamInfo = new StuTheExamInfo(); + // 返回数据-剩余时间 + stuTheExamInfo.setTime(formatLongDuration(countdown.get())); + // 返回数据-上传文件状态 0:上传;1:不上传 + stuTheExamInfo.setUpload(1); + // 返回数据-结束考试 0:结束;1:不结束 + stuTheExamInfo.setEndStatus(1); + // 返回数据-网络状态 + stuTheExamInfo.setNetwork("强"); + taskManager.startTask(stuInTheExam, stuTheExamInfo, token, countdown, new AtomicInteger(0), loginUser.getId() + "_" + stuInTheExam.getTaskId() + "_" + stuInTheExam.getPaperId()); + // 将数组的值进行复制 + BeanUtils.copyProperties(examPaperVo, examRestartPaperVo); + examRestartPaperVo.setWsToken(token); + // 查询学生文件下载地址 + examRestartPaperVo.setTemporaryId(temporaryId); + List stuPaperFileS = stuPaperFileService.findByStuIDAndPaperId(loginUser.getId(), stuInTheExam.getPaperId(), temporaryId); + stuPaperFileS.forEach(stuPaperFileDO -> { + if (stuPaperFileDO.getType() == 0) { + // 将文件地址存放,方便前端继续下载处理 + examRestartPaperVo.setFileUrl(stuPaperFileDO.getUrl()); + } + }); + return CommonResult.success(examRestartPaperVo); + } else { + return CommonResult.error(1_0001_001,"没有找到对应的考试信息"); + } + } + return CommonResult.error(1_0001_002,"没有找到对应的学生信息"); + } /** * 停止考试 * * @return true */ @GetMapping("/stopExam") - public CommonResult stopExam() { + public CommonResult stopExam(@RequestParam("taskId") String taskId, @RequestParam("paperId") String paperId) { HttpServletRequest request = ServletUtils.getRequest(); String userId = null; if (request != null) { userId = String.valueOf(SecurityFrameworkUtils.getLoginUserId()); + // 将userId 拼接 taskId 作为key + // 防止不同试卷ID冲突 + userId += "_" + taskId + "_" + paperId; // 删除对应的线程池 taskManager.stopTask(userId); return CommonResult.success(true); @@ -195,10 +293,6 @@ public class AutoToolsController { // 时间转换 public static String formatLongDuration(int totalSeconds) { - int hours = totalSeconds / 3600; - int minutes = (totalSeconds % 3600) / 60; - int seconds = totalSeconds % 60; - - return String.format("%02d:%02d:%02d", hours, minutes, seconds); + return TaskManager.formatLongDuration(totalSeconds); } } diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/vo/ExamRestartPaperVo.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/vo/ExamRestartPaperVo.java new file mode 100644 index 00000000..063f7020 --- /dev/null +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/vo/ExamRestartPaperVo.java @@ -0,0 +1,34 @@ +package pc.exam.pp.module.judgement.controller.admin.autoTools.vo; + +import lombok.Data; +import pc.exam.pp.module.exam.controller.admin.paper.vo.StuInfoPaper; +import pc.exam.pp.module.exam.dal.dataobject.EducationPaperParam; +import pc.exam.pp.module.exam.dal.dataobject.EducationPaperScheme; +import pc.exam.pp.module.exam.dal.dataobject.EducationPaperSession; +import pc.exam.pp.module.exam.dal.dataobject.ExamQuestion; + +import java.util.List; + +@Data +public class ExamRestartPaperVo { + // 试卷iD + String paperId; + // 试卷编号 + String paperNum; + // 试题列表 + List examQuestionList; + // 试卷方案 + List educationPaperSchemeList; + // 试卷参数 + EducationPaperParam educationPaperParam; + // 试卷场次 + EducationPaperSession educationPaperSession; + // 学生信息 + StuInfoPaper stuInfoPaper; + // 试卷文件 + String fileUrl; + // ws token + String wsToken; + // 随机ID + String temporaryId; +} diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/vo/StuInTheExam.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/vo/StuInTheExam.java index ede6f20c..28529e52 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/vo/StuInTheExam.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/controller/admin/autoTools/vo/StuInTheExam.java @@ -15,4 +15,6 @@ public class StuInTheExam { private String taskId; // 延迟时间 单位min private Integer delayTime; + // 试卷ID + private String paperId; } diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/TaskManager.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/TaskManager.java index 0266304f..05318d30 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/TaskManager.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/service/TaskManager.java @@ -32,8 +32,8 @@ public class TaskManager { if (tasks.containsKey(userId)) { log.info("任务 {} 已存在,未重复启动", userId); // TODO 删除,重置倒计时 - tasks.remove(userId); - // return; + // tasks.remove(userId); + return; } tasks.computeIfAbsent(userId, k -> { Runnable task = safe(() -> { @@ -44,6 +44,9 @@ public class TaskManager { if (current == stuInTheExam.getTimes()) { stuTheExamInfo.setUpload(0); counter.set(0); + current = 0; + } else { + stuTheExamInfo.setUpload(1); } if (remaining <= 0) { ScheduledFuture future = tasks.remove(userId); @@ -73,6 +76,14 @@ public class TaskManager { } } + /**通过ID查询*/ + public String getTaskById(String userId) { + return tasks.keySet().stream() + .filter(key -> key.startsWith(userId + "_")) + .findFirst() + .orElse(null); + } + /** 全部停止(可选) */ public void stopAll() { tasks.forEach((k, f) -> f.cancel(false));