【新增】 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")
@Operation(summary = "改变考生状态")
public CommonResult<Boolean> updateMonitorStatus(@Valid @RequestBody StuMonitorStatusVo stuMonitorStatusVo) {
public CommonResult<MonitorWsVo> updateMonitorStatus(@Valid @RequestBody StuMonitorStatusVo 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 lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import pc.exam.pp.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
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)
@ToString(callSuper = true)
public class MonitorPageReqVO extends PageParam {
private String [] monitorId;
private String[] monitorId;
@Schema(description = "用户账号", example = "芋艿")
private String username;
@Schema(description = "用户账号", example = "芋艿")
private String username;
@Schema(description = "用户姓名", example = "赵六")
private String nickname;
@Schema(description = "用户姓名", example = "赵六")
private String nickname;
@Schema(description = "班级", example = "芋艿")
private String className;
@Schema(description = "班级", example = "芋艿")
private String className;
@Schema(description = "考试状态", example = "2")
private String examStatus;
@Schema(description = "考试状态", example = "2")
private String examStatus;
@Schema(description = "成绩")
private String score;
@Schema(description = "成绩")
private String score;
@Schema(description = "试卷编号")
private String paperNum;
@Schema(description = "试卷编号")
private String paperNum;
@Schema(description = "场次", example = "赵六")
private String taskName;
@Schema(description = "场次", example = "赵六")
private String taskName;
private String taskId;
private String taskId;
private String taskType;
private String taskType;
@Schema(description = "机器ip")
private String ip;
@Schema(description = "机器ip")
private String ip;
@Schema(description = "剩余时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] remainingTime;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "剩余时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] remainingTime;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -48,8 +48,12 @@ public class MonitorRespVO {
@ExcelProperty(value = "剩余时间", converter = SecondsToTimeConverter.class)
private String remainingTime;
@ExcelProperty("创建时间")
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 {
private List<String> monitorIds;
private String status;
private String times;
}

View File

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

View File

@@ -66,5 +66,5 @@ public interface MonitorService {
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
@Validated
public class MonitorServiceImpl implements MonitorService {
@Autowired
@Resource
private RedisTemplate redisTemplate;
@Resource
private MonitorMapper monitorMapper;
@@ -309,6 +309,9 @@ public class MonitorServiceImpl implements MonitorService {
long finalRemaining = Math.min(remainingSeconds, examDurationSeconds);
// 4. 设置和返回
info.setRemainingTime(finalRemaining);
// 5. 通过计算获取endTime考试结束时间
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
info.setEndTime(end.format(fmt));
// 判分后更新记录
monitorMapper.updateById(info);
return finalRemaining;
@@ -319,6 +322,12 @@ public class MonitorServiceImpl implements MonitorService {
//开启测评时长限制 没开启场次 -直接返回测评时长
if ("1".equals(educationPaperParam.getIsSession()) && "0".equals(educationPaperParam.getIsTime())) {
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));
monitorMapper.updateById(info);
return (long) examTime.toLocalTime().toSecondOfDay();
@@ -367,8 +376,9 @@ public class MonitorServiceImpl implements MonitorService {
}
// 重置开始时间&交互时间
if (info != null) {
info.setStartTime(null);
info.setInteractiveTime(null);
info.setStartTime("");
info.setInteractiveTime("");
info.setEndTime("");
}
MonitorDO monitorDOs = null;
if (info != null) {
@@ -438,87 +448,71 @@ public class MonitorServiceImpl implements MonitorService {
}
@Override
public Boolean updateMonitorStatus(StuMonitorStatusVo stuMonitorStatusVo) {
public MonitorWsVo updateMonitorStatus(StuMonitorStatusVo stuMonitorStatusVo) {
MonitorWsVo monitorWsVo = new MonitorWsVo();
String status = stuMonitorStatusVo.getStatus();
String times = stuMonitorStatusVo.getTimes();
List<String> monitorIds = stuMonitorStatusVo.getMonitorIds();
if ("1".equals(status) || "0".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.setExamStatus(status);
monitorMapper.updateById(monitorDO);
MonitorDO info = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), MonitorDO.class);
EducationPaperParam educationPaperParam = educationPaperParamMapper.selectEducationPaperParamByTaskId(taskId);
Time examTime = educationPaperParam.getExamTime();
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("");
for (String monitorId : monitorIds) {
MonitorDO monitorDO = monitorMapper.selectById(monitorId);
// 任务ID
String taskId = monitorDO.getTaskId();
// 学号
String stuId = monitorDO.getStuId();
// redis_key
String key = "userCache:" + taskId + ":" + stuId;
// 获取缓存数据
MonitorDO info = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), MonitorDO.class);
// 如果考试状态存在,更新考试状态
if (status != null) {
if (info != null) {
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 true;
return monitorWsVo;
}
public List<TentSpecialy> filterSpecialtyList(List<TentSpecialy> inputList) {
if (inputList == null || inputList.isEmpty()) {
return Collections.emptyList();
@@ -544,5 +538,25 @@ public class MonitorServiceImpl implements MonitorService {
}).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;
}
}