merge
This commit is contained in:
GoCo 2025-08-28 06:02:07 +08:00
commit 5861ce2655

View File

@ -1,14 +1,18 @@
package org.jeecg.modules.biz.controller; package org.jeecg.modules.biz.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.gen.exam.entity.Exam; import org.jeecg.modules.gen.exam.entity.Exam;
import org.jeecg.modules.gen.exam.service.IExamService; import org.jeecg.modules.gen.exam.service.IExamService;
import org.jeecg.modules.gen.examanswer.entity.ExamAnswer;
import org.jeecg.modules.gen.examanswer.service.IExamAnswerService; import org.jeecg.modules.gen.examanswer.service.IExamAnswerService;
import org.jeecg.modules.gen.examrecord.entity.ExamRecord;
import org.jeecg.modules.gen.examrecord.service.IExamRecordService; import org.jeecg.modules.gen.examrecord.service.IExamRecordService;
import org.jeecg.modules.gen.paper.entity.Paper; import org.jeecg.modules.gen.paper.entity.Paper;
import org.jeecg.modules.gen.paper.service.IPaperService; import org.jeecg.modules.gen.paper.service.IPaperService;
@ -19,15 +23,10 @@ import org.jeecg.modules.gen.question.service.IQuestionService;
import org.jeecg.modules.gen.questionrepo.entity.QuestionRepo; import org.jeecg.modules.gen.questionrepo.entity.QuestionRepo;
import org.jeecg.modules.gen.questionrepo.service.IQuestionRepoService; import org.jeecg.modules.gen.questionrepo.service.IQuestionRepoService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList; import javax.servlet.http.HttpServletRequest;
import java.util.Comparator; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RestController @RestController
@ -101,9 +100,179 @@ public class ExamBizController {
.map(paperQuestion -> questionMap.get(paperQuestion.getQuestionId())) .map(paperQuestion -> questionMap.get(paperQuestion.getQuestionId()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
// 返回排序后的试题列表 //获取复选题id
return Result.OK(sortedQuestions); List<String> type5Ids = sortedQuestions.stream()
.filter(question -> question.getType() == 5)
.map(Question::getId)
.collect(Collectors.toList());
//获取复选题所包含的题目
List<Question> type5Questions = new ArrayList<>();
if (!type5Ids.isEmpty()) {
type5Questions = questionService.list(
new LambdaQueryWrapper<Question>()
.in(Question::getParentId, type5Ids)
);
}
// 创建一个映射用于快速查找父ID对应的子题目
Map<String, List<Question>> parentToChildrenMap = type5Questions.stream()
.collect(Collectors.groupingBy(Question::getParentId));
// 将子题目添加到原始列表中保持原有顺序
List<Question> resultQuestions = new ArrayList<>();
for (Question question : questions) {
resultQuestions.add(question);
if (question.getType() == 5) {
List<Question> children = parentToChildrenMap.getOrDefault(question.getId(), Collections.emptyList());
resultQuestions.addAll(children);
}
}
//创建考试答题初始化记录
List<ExamAnswer> examAnswerList = new ArrayList<>();
for (Question resultQuestion : resultQuestions) {
ExamAnswer examAnswer = new ExamAnswer();
examAnswer.setExamId(examId);
examAnswer.setUserId(studentId);
if (resultQuestion != null && StringUtils.isNotEmpty(resultQuestion.getParentId())) {
examAnswer.setParentQuestionId(resultQuestion.getParentId());
}
examAnswer.setQuestionId(resultQuestion.getId());
examAnswerList.add(examAnswer);
}
examAnswerService.saveBatch(examAnswerList);
//创建考试记录
ExamRecord examRecord = new ExamRecord();
examRecord.setExamId(examId);
examRecord.setUserId(studentId);
examRecord.setStatus(0);
examRecordService.save(examRecord);
// 返回排序后的试题总列表
return Result.OK(resultQuestions);
}
@PostMapping("/submitAnswer")
@Operation(summary = "提交答案")
public Result<?> submitAnswer(@RequestBody ExamAnswer examAnswer) {
// 创建查询条件
LambdaUpdateWrapper<ExamAnswer> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(ExamAnswer::getExamId, examAnswer.getExamId())
.eq(ExamAnswer::getUserId, examAnswer.getUserId())
.eq(ExamAnswer::getQuestionId, examAnswer.getQuestionId());
// 更新答案
if (examAnswer.getAnswer() != null) {
updateWrapper.set(ExamAnswer::getAnswer, examAnswer.getAnswer());
}
// 执行更新
return examAnswerService.update(updateWrapper) ? Result.OK() : Result.error("提交答案失败");
}
@PostMapping("/submitExam")
@Operation(summary = "提交考试")
public Result<?> submitExam(@RequestBody ExamRecord examRecord,
HttpServletRequest req) {
examRecord.setIpAddress(getClientIp(req));
examRecord.setDeviceInfo(getDeviceInfo(req));
//修改状态
examRecord.setStatus(1);
// 创建更新条件
LambdaUpdateWrapper<ExamRecord> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(ExamRecord::getExamId, examRecord.getExamId())
.eq(ExamRecord::getUserId, examRecord.getUserId());
// 更新ip
if (examRecord.getIpAddress() != null) {
updateWrapper.set(ExamRecord::getIpAddress, examRecord.getIpAddress());
}
// 更新设备信息
if (examRecord.getDeviceInfo() != null) {
updateWrapper.set(ExamRecord::getDeviceInfo, examRecord.getDeviceInfo());
}
// 更新考试状态提交时间
updateWrapper.
set(ExamRecord::getStatus,1).
set(ExamRecord::getSubmittedAt, new Date());
// 更新
return examRecordService.update(updateWrapper) ? Result.OK() : Result.error("提交考试失败");
}
public String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 对于通过多个代理的情况第一个IP为客户端真实IP,多个IP按照','分割
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}
public String getDeviceInfo(HttpServletRequest request) {
// 获取User-Agent
String userAgent = request.getHeader("User-Agent");
// 解析设备信息
String deviceInfo = parseDeviceInfo(userAgent);
return deviceInfo;
}
private String parseDeviceInfo(String userAgent) {
if (userAgent == null) {
return "Unknown";
}
StringBuilder deviceInfo = new StringBuilder();
// 判断操作系统
if (userAgent.indexOf("Windows") > -1) {
deviceInfo.append("Windows");
} else if (userAgent.indexOf("Mac") > -1) {
deviceInfo.append("Mac");
} else if (userAgent.indexOf("X11") > -1) {
deviceInfo.append("Unix");
} else if (userAgent.indexOf("Android") > -1) {
deviceInfo.append("Android");
} else if (userAgent.indexOf("iPhone") > -1 || userAgent.indexOf("iPad") > -1) {
deviceInfo.append("iOS");
} else {
deviceInfo.append("Unknown OS");
}
deviceInfo.append(" | ");
// 判断浏览器
if (userAgent.indexOf("MSIE") > -1) {
deviceInfo.append("MSIE");
} else if (userAgent.indexOf("Firefox") > -1) {
deviceInfo.append("Firefox");
} else if (userAgent.indexOf("Chrome") > -1) {
deviceInfo.append("Chrome");
} else if (userAgent.indexOf("Safari") > -1) {
deviceInfo.append("Safari");
} else if (userAgent.indexOf("Opera") > -1) {
deviceInfo.append("Opera");
} else {
deviceInfo.append("Unknown Browser");
}
// 可以添加更多设备信息的判断
// 判断是否是移动设备
boolean isMobile = userAgent.indexOf("Mobile") > -1 ||
userAgent.indexOf("Android") > -1 ||
userAgent.indexOf("iPhone") > -1;
deviceInfo.append(" | ").append(isMobile ? "Mobile" : "PC");
return deviceInfo.toString();
} }
} }