【新增】 1、监控页面支持考试中的考试增加考试时间

This commit is contained in:
dlaren
2025-09-16 22:59:29 +08:00
parent fddff098ca
commit 355c7e2b45
8 changed files with 150 additions and 106 deletions

View File

@@ -209,7 +209,7 @@ public class MonitorController {
@PostMapping("/updateMonitorStatus") @PostMapping("/updateMonitorStatus")
@Operation(summary = "改变考生状态") @Operation(summary = "改变考生状态")
public CommonResult<Boolean> updateMonitorStatus(@Valid @RequestBody StuMonitorStatusVo stuMonitorStatusVo) { public CommonResult<MonitorWsVo> updateMonitorStatus(@Valid @RequestBody StuMonitorStatusVo stuMonitorStatusVo) {
return success(monitorService.updateMonitorStatus(stuMonitorStatusVo)); return success(monitorService.updateMonitorStatus(stuMonitorStatusVo));
} }

View File

@@ -3,10 +3,13 @@ package pc.exam.pp.module.exam.controller.admin.monitor.vo;
import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.*; import lombok.*;
import java.util.*; import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import pc.exam.pp.framework.common.pojo.PageParam; import pc.exam.pp.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import static pc.exam.pp.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; import static pc.exam.pp.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@@ -16,42 +19,44 @@ import static pc.exam.pp.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)
public class MonitorPageReqVO extends PageParam { public class MonitorPageReqVO extends PageParam {
private String [] monitorId; private String[] monitorId;
@Schema(description = "用户账号", example = "芋艿") @Schema(description = "用户账号", example = "芋艿")
private String username; private String username;
@Schema(description = "用户姓名", example = "赵六") @Schema(description = "用户姓名", example = "赵六")
private String nickname; private String nickname;
@Schema(description = "班级", example = "芋艿") @Schema(description = "班级", example = "芋艿")
private String className; private String className;
@Schema(description = "考试状态", example = "2") @Schema(description = "考试状态", example = "2")
private String examStatus; private String examStatus;
@Schema(description = "成绩") @Schema(description = "成绩")
private String score; private String score;
@Schema(description = "试卷编号") @Schema(description = "试卷编号")
private String paperNum; private String paperNum;
@Schema(description = "场次", example = "赵六") @Schema(description = "场次", example = "赵六")
private String taskName; private String taskName;
private String taskId; private String taskId;
private String taskType; private String taskType;
@Schema(description = "机器ip") @Schema(description = "机器ip")
private String ip; private String ip;
@Schema(description = "剩余时间") @Schema(description = "剩余时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] remainingTime; private LocalDateTime[] remainingTime;
@Schema(description = "创建时间") @Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime; private LocalDateTime[] createTime;
} }

View File

@@ -48,8 +48,12 @@ public class MonitorRespVO {
@ExcelProperty(value = "剩余时间", converter = SecondsToTimeConverter.class) @ExcelProperty(value = "剩余时间", converter = SecondsToTimeConverter.class)
private String remainingTime; private String remainingTime;
@ExcelProperty("创建时间")
private LocalDateTime createTime; private LocalDateTime createTime;
@ExcelProperty("开始时间")
private String startTime;
@ExcelProperty("结束时间")
private String endTime;
} }

View File

@@ -0,0 +1,16 @@
package pc.exam.pp.module.exam.controller.admin.monitor.vo;
import lombok.Data;
@Data
public class MonitorWsVo {
private String type;
private String stuId;
private String taskId;
private String paperNum;
}

View File

@@ -9,4 +9,5 @@ import java.util.List;
public class StuMonitorStatusVo { public class StuMonitorStatusVo {
private List<String> monitorIds; private List<String> monitorIds;
private String status; private String status;
private String times;
} }

View File

@@ -75,12 +75,16 @@ public class MonitorDO extends BaseDO {
* 临时ID * 临时ID
*/ */
private String temporaryId; private String temporaryId;
/** /**
* 开始时间 * 开始时间
*/ */
private String startTime; private String startTime;
/**
* 结束时间
*/
private String endTime;
/** /**
* 交互时间 * 交互时间
*/ */

View File

@@ -66,5 +66,5 @@ public interface MonitorService {
List<EducationPaperTask> getPaperTaskList(String id); List<EducationPaperTask> getPaperTaskList(String id);
//改变考生状态 //改变考生状态
Boolean updateMonitorStatus(StuMonitorStatusVo stuMonitorStatusVo); MonitorWsVo updateMonitorStatus(StuMonitorStatusVo stuMonitorStatusVo);
} }

View File

@@ -55,7 +55,7 @@ import static pc.exam.pp.module.system.enums.ErrorCodeConstants.MONITOR_NOT_EXIS
@Service @Service
@Validated @Validated
public class MonitorServiceImpl implements MonitorService { public class MonitorServiceImpl implements MonitorService {
@Autowired @Resource
private RedisTemplate redisTemplate; private RedisTemplate redisTemplate;
@Resource @Resource
private MonitorMapper monitorMapper; private MonitorMapper monitorMapper;
@@ -309,6 +309,9 @@ public class MonitorServiceImpl implements MonitorService {
long finalRemaining = Math.min(remainingSeconds, examDurationSeconds); long finalRemaining = Math.min(remainingSeconds, examDurationSeconds);
// 4. 设置和返回 // 4. 设置和返回
info.setRemainingTime(finalRemaining); info.setRemainingTime(finalRemaining);
// 5. 通过计算获取endTime考试结束时间
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
info.setEndTime(end.format(fmt));
// 判分后更新记录 // 判分后更新记录
monitorMapper.updateById(info); monitorMapper.updateById(info);
return finalRemaining; return finalRemaining;
@@ -319,6 +322,12 @@ public class MonitorServiceImpl implements MonitorService {
//开启测评时长限制 没开启场次 -直接返回测评时长 //开启测评时长限制 没开启场次 -直接返回测评时长
if ("1".equals(educationPaperParam.getIsSession()) && "0".equals(educationPaperParam.getIsTime())) { if ("1".equals(educationPaperParam.getIsSession()) && "0".equals(educationPaperParam.getIsTime())) {
info.setRemainingTime((long) examTime.toLocalTime().toSecondOfDay()); info.setRemainingTime((long) examTime.toLocalTime().toSecondOfDay());
// 通过计算获取endTime考试结束时间
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now(); // 本地日期时间
LocalDateTime target = now.plusSeconds((long) examTime.toLocalTime().toSecondOfDay());
// 没有考场更新结束时间
info.setEndTime(target.format(fmt));
stringRedisTemplate.opsForValue().set("userCache:" + stuMonitorPaperVo.getTaskId() + ":" + stuMonitorPaperVo.getStuId(), JsonUtils.toJsonString(info)); stringRedisTemplate.opsForValue().set("userCache:" + stuMonitorPaperVo.getTaskId() + ":" + stuMonitorPaperVo.getStuId(), JsonUtils.toJsonString(info));
monitorMapper.updateById(info); monitorMapper.updateById(info);
return (long) examTime.toLocalTime().toSecondOfDay(); return (long) examTime.toLocalTime().toSecondOfDay();
@@ -367,8 +376,9 @@ public class MonitorServiceImpl implements MonitorService {
} }
// 重置开始时间&交互时间 // 重置开始时间&交互时间
if (info != null) { if (info != null) {
info.setStartTime(null); info.setStartTime("");
info.setInteractiveTime(null); info.setInteractiveTime("");
info.setEndTime("");
} }
MonitorDO monitorDOs = null; MonitorDO monitorDOs = null;
if (info != null) { if (info != null) {
@@ -438,87 +448,71 @@ public class MonitorServiceImpl implements MonitorService {
} }
@Override @Override
public Boolean updateMonitorStatus(StuMonitorStatusVo stuMonitorStatusVo) { public MonitorWsVo updateMonitorStatus(StuMonitorStatusVo stuMonitorStatusVo) {
MonitorWsVo monitorWsVo = new MonitorWsVo();
String status = stuMonitorStatusVo.getStatus(); String status = stuMonitorStatusVo.getStatus();
String times = stuMonitorStatusVo.getTimes();
List<String> monitorIds = stuMonitorStatusVo.getMonitorIds(); List<String> monitorIds = stuMonitorStatusVo.getMonitorIds();
if ("1".equals(status) || "0".equals(status)) { for (String monitorId : monitorIds) {
//新增或更新 MonitorDO monitorDO = monitorMapper.selectById(monitorId);
for (String monitorId : monitorIds) { // 任务ID
MonitorDO monitorDO = monitorMapper.selectById(monitorId); String taskId = monitorDO.getTaskId();
String taskId = monitorDO.getTaskId(); // 学号
String stuId = monitorDO.getStuId(); String stuId = monitorDO.getStuId();
String key = "userCache:" + taskId + ":" + stuId; // redis_key
monitorDO.setExamStatus(status); String key = "userCache:" + taskId + ":" + stuId;
monitorMapper.updateById(monitorDO); // 获取缓存数据
MonitorDO info = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), MonitorDO.class); MonitorDO info = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), MonitorDO.class);
EducationPaperParam educationPaperParam = educationPaperParamMapper.selectEducationPaperParamByTaskId(taskId); // 如果考试状态存在,更新考试状态
Time examTime = educationPaperParam.getExamTime(); if (status != null) {
if (info != null) {
if (info == null) {
MonitorDO monitorDO1 = monitorMapper.selectOne(new QueryWrapper<MonitorDO>().eq("stu_id", stuId).eq("task_id", taskId));
PersonRepDto personRepDto = educationPaperPersonMapper.selectUserById(stuId);
String name = educationPaperTaskMapper.selectEducationPaperTaskNameByid(taskId);
EducationPaperTask educationPaperTask = educationPaperTaskMapper.selectEducationPaperTaskByTaskId(taskId);
monitorDO1.setScore("0");
monitorDO1.setTaskId(taskId);
monitorDO1.setTaskType(educationPaperTask.getTaskType());
monitorDO1.setExamStatus(status);
monitorDO1.setPaperNum("");
monitorDO1.setIp("");
monitorDO1.setStuId(stuId);
monitorDO1.setUsername(personRepDto.getUsername());
monitorDO1.setNickname(personRepDto.getNickname());
//如果开启了 时长限制 或者考场
if ("0".equals(educationPaperParam.getIsTime()) || "0".equals(educationPaperParam.getIsSession())) {
monitorDO1.setRemainingTime((long) examTime.toLocalTime().toSecondOfDay());
}
stringRedisTemplate.opsForValue().set(key, JsonUtils.toJsonString(monitorDO1));
monitorMapper.updateById(monitorDO1);
} else {
//如果开启了 时长限制 或者考场
if ("0".equals(educationPaperParam.getIsTime()) || "0".equals(educationPaperParam.getIsSession())) {
info.setRemainingTime((long) examTime.toLocalTime().toSecondOfDay());
}
info.setScore("0");
info.setPaperNum("");
info.setIp("");
info.setExamStatus(status); info.setExamStatus(status);
stringRedisTemplate.opsForValue().set(key, JsonUtils.toJsonString(info)); // 如果状态是0和2清除剩余时间
if ("0".equals(status) || "2".equals(status)) {
info.setRemainingTime(0L);
info.setPaperNum("");
info.setIp("");
info.setStartTime("");
info.setEndTime("");
info.setInteractiveTime("");
// 更新
stringRedisTemplate.opsForValue().set(key, JsonUtils.toJsonString(info));
monitorMapper.updateById(info);
monitorWsVo.setStuId(stuId);
monitorWsVo.setType("STOP");
monitorWsVo.setTaskId(taskId);
monitorWsVo.setPaperNum(info.getPaperNum());
return monitorWsVo;
}
// 如果是考试状态1更新剩余时间
if ("1".equals(status)) {
long time = parseTimeToSeconds(times);
// 当考试中的状态的时候才获取times字段
long nowTimes = info.getRemainingTime();
info.setRemainingTime(nowTimes + time);
// 更新结束时间
String endTime = info.getEndTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime targetTime = LocalDateTime.parse(endTime, formatter);
LocalDateTime newTime = targetTime.plusSeconds(time);
String newEndTimeStr = newTime.format(formatter);
info.setEndTime(newEndTimeStr);
// 更新
stringRedisTemplate.opsForValue().set(key, JsonUtils.toJsonString(info));
monitorMapper.updateById(info);
monitorWsVo.setStuId(stuId);
monitorWsVo.setType("RESTART");
monitorWsVo.setTaskId(taskId);
monitorWsVo.setPaperNum(info.getPaperNum());
return monitorWsVo;
}
} }
}
}
if ("2".equals(status)) {
//删除
for (String monitorId : monitorIds) {
MonitorDO monitorDO = monitorMapper.selectById(monitorId);
String taskId = monitorDO.getTaskId();
String stuId = monitorDO.getStuId();
String key = "userCache:" + taskId + ":" + stuId;
monitorDO.setRemainingTime(0L);
if ("0".equals(monitorDO.getTaskType())) {
monitorDO.setExamStatus("0");
stringRedisTemplate.opsForValue().set(key, JsonUtils.toJsonString(monitorDO));
} else {
monitorDO.setExamStatus(status);
redisTemplate.delete(key);
}
monitorMapper.updateById(monitorDO);
} }
} }
return monitorWsVo;
return true;
} }
public List<TentSpecialy> filterSpecialtyList(List<TentSpecialy> inputList) { public List<TentSpecialy> filterSpecialtyList(List<TentSpecialy> inputList) {
if (inputList == null || inputList.isEmpty()) { if (inputList == null || inputList.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
@@ -544,5 +538,25 @@ public class MonitorServiceImpl implements MonitorService {
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }
public static long parseTimeToSeconds(String time) {
if (time == null) throw new IllegalArgumentException("time is null");
String t = time.trim();
if (t.isEmpty()) throw new IllegalArgumentException("time is empty");
String[] parts = t.split(":");
if (parts.length < 1 || parts.length > 3) {
throw new IllegalArgumentException("Unsupported time format: " + time);
}
long total = 0;
for (String p : parts) {
if (!p.matches("\\d+")) {
throw new IllegalArgumentException("Invalid numeric part in time: " + p);
}
int value = Integer.parseInt(p);
if (value < 0) throw new IllegalArgumentException("Negative value not allowed: " + p);
total = total * 60 + value;
}
return total;
}
} }