9 changed files with 181 additions and 5 deletions
@ -0,0 +1,7 @@ |
|||||
|
package com.project.exam.domain.service; |
||||
|
|
||||
|
import com.project.exam.domain.dto.ExamRecordDTO; |
||||
|
|
||||
|
public interface SubmitPaperDomainService { |
||||
|
ExamRecordDTO submitPaper(Long recordId) throws Exception; |
||||
|
} |
||||
@ -1,4 +0,0 @@ |
|||||
package com.project.exam.domain.service; |
|
||||
|
|
||||
public interface SummitPaperDomainService { |
|
||||
} |
|
||||
@ -0,0 +1,127 @@ |
|||||
|
package com.project.exam.domain.service.impl; |
||||
|
|
||||
|
import cn.hutool.core.util.StrUtil; |
||||
|
import com.project.base.domain.exception.BusinessErrorException; |
||||
|
import com.project.exam.domain.dto.ExamRecordDTO; |
||||
|
import com.project.exam.domain.entity.ExamRecordEntity; |
||||
|
import com.project.exam.domain.service.BuildExamRecordDomainService; |
||||
|
import com.project.exam.domain.service.SubmitPaperDomainService; |
||||
|
import com.project.exam.mapper.ExamRecordMapper; |
||||
|
import com.project.task.domain.dto.TaskDTO; |
||||
|
import com.project.task.domain.entity.TaskEntity; |
||||
|
import com.project.task.domain.entity.TaskUserEntity; |
||||
|
import com.project.task.domain.enums.QuestionTypeEnum; |
||||
|
import com.project.task.domain.enums.TaskUserStatusEnum; |
||||
|
import com.project.task.domain.service.TaskBaseService; |
||||
|
import com.project.task.mapper.TaskMapper; |
||||
|
import com.project.task.mapper.TaskUserMapper; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.math.RoundingMode; |
||||
|
import java.util.Arrays; |
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@Service |
||||
|
public class SubmitPaperDomainServiceImpl implements SubmitPaperDomainService { |
||||
|
@Autowired |
||||
|
private ExamRecordMapper examRecordMapper; |
||||
|
@Autowired |
||||
|
private TaskUserMapper taskUserMapper; |
||||
|
@Autowired |
||||
|
private TaskMapper taskMapper; |
||||
|
@Autowired |
||||
|
private TaskBaseService taskBaseService; |
||||
|
|
||||
|
@Autowired |
||||
|
private BuildExamRecordDomainService buildExamRecordDomainService; |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public ExamRecordDTO submitPaper(Long recordId) throws Exception { |
||||
|
ExamRecordEntity record = examRecordMapper.selectById(recordId); |
||||
|
if (record == null || record.getSubmitTime() != null) { |
||||
|
throw new BusinessErrorException("试卷已提交或记录不存在"); |
||||
|
} |
||||
|
// 获取任务配置与用户进度记录
|
||||
|
TaskUserEntity taskUser = taskUserMapper.selectById(record.getTaskUserId()); |
||||
|
TaskEntity task = taskMapper.selectById(taskUser.getTaskId()); |
||||
|
|
||||
|
// 判分
|
||||
|
double finalScore = 0.0; |
||||
|
List<ExamRecordEntity.QuestionSnapshot> snapshotList = record.getAnswerSnapshot(); |
||||
|
for (ExamRecordEntity.QuestionSnapshot snapshot : snapshotList) { |
||||
|
// 比对答案
|
||||
|
if (StrUtil.equals(formatAnswer(snapshot.getUserAnswer()) , formatAnswer(snapshot.getRightAnswer()))) { |
||||
|
snapshot.setIsRight(true); |
||||
|
// 根据题型获取任务创建时算好的单题分值
|
||||
|
finalScore += getQuestionWeight(snapshot.getType(), task); |
||||
|
} else { |
||||
|
snapshot.setIsRight(false); |
||||
|
} |
||||
|
} |
||||
|
// 四舍五入处理
|
||||
|
finalScore = new BigDecimal(finalScore).setScale(2, RoundingMode.HALF_UP).doubleValue(); |
||||
|
boolean isPassed = finalScore >= task.getPassScore(); |
||||
|
record.setScore(finalScore); |
||||
|
record.setPass(isPassed); |
||||
|
record.setSubmitTime(new Date()); |
||||
|
record.setAnswerSnapshot(snapshotList); |
||||
|
examRecordMapper.updateById(record); |
||||
|
|
||||
|
// 更新 TaskEntity 冗余字段
|
||||
|
if (isPassed) { |
||||
|
taskBaseService.update() |
||||
|
.setSql("pass_num = pass_num + 1") |
||||
|
.eq("id", task.getId()) |
||||
|
.update(); |
||||
|
} |
||||
|
|
||||
|
// 更新 TaskUser 冗余字段
|
||||
|
updateTaskUserStatus(taskUser , isPassed , recordId); |
||||
|
// 构建dto
|
||||
|
ExamRecordDTO dto = record.toDTO(ExamRecordDTO::new); |
||||
|
dto.setTaskDTO(task.toDTO(TaskDTO::new)); |
||||
|
return buildExamRecordDomainService.buildDTO(dto); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据题型映射任务表中的动态分值 |
||||
|
*/ |
||||
|
private double getQuestionWeight(Integer type, TaskEntity task) { |
||||
|
if (QuestionTypeEnum.SINGLE_CHOICE.getValue().equals(type)) { |
||||
|
return task.getSingleChoiceScore(); |
||||
|
} else if (QuestionTypeEnum.MULTIPLE_CHOICE.getValue().equals(type)) { |
||||
|
return task.getMultipleChoiceScore(); |
||||
|
} |
||||
|
else if (QuestionTypeEnum.TRUE_FALSE.getValue().equals(type)) { |
||||
|
return task.getTrueFalseScore(); |
||||
|
} |
||||
|
return 0.0; |
||||
|
} |
||||
|
|
||||
|
private void updateTaskUserStatus(TaskUserEntity taskUser, boolean isPassed, Long recordId) { |
||||
|
taskUser.setLastRecordId(recordId); |
||||
|
taskUser.setAttemptNum((taskUser.getAttemptNum() == null ? 0 : taskUser.getAttemptNum()) + 1); |
||||
|
|
||||
|
if (!TaskUserStatusEnum.Pass.getValue().equals(taskUser.getStatus())) { |
||||
|
taskUser.setStatus(isPassed ? TaskUserStatusEnum.Pass.getValue() : TaskUserStatusEnum.Fail.getValue()); |
||||
|
} |
||||
|
|
||||
|
taskUserMapper.updateById(taskUser); |
||||
|
} |
||||
|
|
||||
|
private String formatAnswer(String ans) { |
||||
|
if (StrUtil.isBlank(ans)) return ""; |
||||
|
// 去空格 -> 转大写 -> 排序(解决 B,A vs A,B 的问题)
|
||||
|
return Arrays.stream(ans.split(",")) |
||||
|
.map(String::trim) |
||||
|
.map(String::toUpperCase) |
||||
|
.sorted() |
||||
|
.collect(Collectors.joining(",")); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue