Browse Source

考生端修改

master
luoweijian 2 months ago
parent
commit
e651d2208e
  1. 2
      src/main/java/com/project/ding/domain/service/impl/SearchUserDomainServiceImpl.java
  2. 38
      src/main/java/com/project/exam/domain/job/ShortAnswerScoringJob.java
  3. 17
      src/main/java/com/project/exam/domain/service/impl/SubmitPaperDomainServiceImpl.java
  4. 2
      src/main/java/com/project/exam/domain/service/strategy/ClassicPaperStrategy.java
  5. 3
      src/main/java/com/project/task/domain/enums/CandidateTaskStatusEnum.java
  6. 3
      src/main/java/com/project/task/domain/enums/TaskUserStatusEnum.java
  7. 2
      src/main/java/com/project/task/domain/param/TaskParam.java
  8. 60
      src/main/java/com/project/task/domain/service/impl/CandidateSearchTaskDomainServiceImpl.java
  9. 7
      src/main/java/com/project/task/domain/service/impl/SearchTaskDomainServiceImpl.java
  10. 2
      src/main/resources/application-test.yml

2
src/main/java/com/project/ding/domain/service/impl/SearchUserDomainServiceImpl.java

@ -71,7 +71,7 @@ public class SearchUserDomainServiceImpl implements SearchUserDomainService {
.in(TaskUserEntity::getStatus, List.of(TaskUserStatusEnum.Not_Start.getValue(), TaskUserStatusEnum.Fail.getValue(), TaskUserStatusEnum.Pass.getValue())))).intValue());
dto.setParticipatedExamTaskCount(Long.valueOf(taskUserBaseService.count(new LambdaQueryWrapper<TaskUserEntity>()
.eq(TaskUserEntity::getUserId, dto.getId())
.in(TaskUserEntity::getStatus, List.of(TaskUserStatusEnum.Fail.getValue(), TaskUserStatusEnum.Pass.getValue())))).intValue());
.in(TaskUserEntity::getStatus, List.of(TaskUserStatusEnum.Fail.getValue(), TaskUserStatusEnum.Pass.getValue(), TaskUserStatusEnum.Scoring.getValue())))).intValue());
dto.setPassedExamTaskCount(Long.valueOf(taskUserBaseService.count(new LambdaQueryWrapper<TaskUserEntity>()
.eq(TaskUserEntity::getUserId, dto.getId())
.in(TaskUserEntity::getStatus, List.of(TaskUserStatusEnum.Pass.getValue())))).intValue());

38
src/main/java/com/project/exam/domain/job/ShortAnswerScoringJob.java

@ -311,30 +311,44 @@ public class ShortAnswerScoringJob {
log.warn(">>> [简答题评分任务] 查询及格线失败,使用默认60分", e);
}
boolean oldPass = record.getPass() != null && record.getPass();
boolean newPass = total >= passScore;
record.setPass(newPass);
// 如果及格状态变了,更新相关冗余字段
if (oldPass != newPass && task != null && tu != null) {
try {
// 更新 TaskUser 状态
if (tu != null) {
Integer currentStatus = tu.getStatus();
// 规则1:已经是 Pass → 不降级
if (TaskUserStatusEnum.Pass.getValue().equals(currentStatus)) {
// 不做任何变更
}
// 规则2:评分中(新数据) → 转最终结果
else if (TaskUserStatusEnum.Scoring.getValue().equals(currentStatus)) {
tu.setLastRecordId(record.getId());
tu.setStatus(newPass
? TaskUserStatusEnum.Pass.getValue()
: TaskUserStatusEnum.Fail.getValue());
taskUserMapper.updateById(tu);
if (newPass) {
// 不及格→及格:增加 pass_num,更新用户状态
taskBaseService.update()
.setSql("pass_num = pass_num + 1")
.eq("id", task.getId())
.update();
if (!TaskUserStatusEnum.Pass.getValue().equals(tu.getStatus())) {
}
}
// 规则3:旧数据兼容(之前 Fail,评分完才及格 → 升级 Pass)
else if (TaskUserStatusEnum.Fail.getValue().equals(currentStatus) && newPass) {
tu.setStatus(TaskUserStatusEnum.Pass.getValue());
tu.setLastRecordId(record.getId());
taskUserMapper.updateById(tu);
taskBaseService.update()
.setSql("pass_num = pass_num + 1")
.eq("id", task.getId())
.update();
}
}
// 及格→不及格:理论上不会发生(简答题只加分不减分),暂不处理
} catch (Exception e) {
log.error(">>> [简答题评分任务] 更新及格状态失败, recordId={}", record.getId(), e);
}
// 规则4:其他情况(Fail 且未及格、Not_Start等)→ 不做变更
}
}
}

17
src/main/java/com/project/exam/domain/service/impl/SubmitPaperDomainServiceImpl.java

@ -138,7 +138,7 @@ public class SubmitPaperDomainServiceImpl implements SubmitPaperDomainService {
}
// 更新 TaskUser 冗余字段
updateTaskUserStatus(taskUser , isPassed , recordId);
updateTaskUserStatus(taskUser , isPassed , recordId , hasShortAnswer);
// 异步收集易错统计
statisticsApplicationService.collectErrorProneStatistics(
@ -170,12 +170,23 @@ public class SubmitPaperDomainServiceImpl implements SubmitPaperDomainService {
return 0.0;
}
private void updateTaskUserStatus(TaskUserEntity taskUser, boolean isPassed, Long recordId) {
private void updateTaskUserStatus(TaskUserEntity taskUser, boolean isPassed, Long recordId, boolean hasShortAnswer) {
taskUser.setAttemptNum((taskUser.getAttemptNum() == null ? 0 : taskUser.getAttemptNum()) + 1);
if (!TaskUserStatusEnum.Pass.getValue().equals(taskUser.getStatus())) {
// 如果已经通过,不降级
if (TaskUserStatusEnum.Pass.getValue().equals(taskUser.getStatus())) {
taskUserMapper.updateById(taskUser);
return;
}
taskUser.setLastRecordId(recordId);
if (hasShortAnswer) {
// 有简答题 → 先设为评分中,等异步评分完成再定最终结果
taskUser.setStatus(TaskUserStatusEnum.Scoring.getValue());
} else {
// 纯客观题 → 直接出最终结果
taskUser.setStatus(isPassed ? TaskUserStatusEnum.Pass.getValue() : TaskUserStatusEnum.Fail.getValue());
}

2
src/main/java/com/project/exam/domain/service/strategy/ClassicPaperStrategy.java

@ -97,7 +97,7 @@ public class ClassicPaperStrategy implements PaperAssemblyStrategy {
// 6. 过滤出该版本的快照,按 sortOrder 排序
List<TaskPaperSnapshotEntity> selectedSnapshots = allSnapshots.stream()
.filter(s -> selectedSetIndex.equals(s.getSetIndex()))
.sorted(Comparator.comparing(TaskPaperSnapshotEntity::getSortOrder))
.sorted(Comparator.comparing(TaskPaperSnapshotEntity::getQuestionType))
.collect(Collectors.toList());
// 7. 构建 QuestionSnapshot 列表

3
src/main/java/com/project/task/domain/enums/CandidateTaskStatusEnum.java

@ -11,7 +11,8 @@ public enum CandidateTaskStatusEnum implements HasValueEnum<String> {
Pending_Exam("待开考") ,
Not_Exam("未考试") ,
Has_Exam("已考试") ,
End("已截止")
End("已截止") ,
Scoring("评分中")
;
private final String value;
}

3
src/main/java/com/project/task/domain/enums/TaskUserStatusEnum.java

@ -9,7 +9,8 @@ import lombok.RequiredArgsConstructor;
public enum TaskUserStatusEnum implements HasValueEnum<Integer> {
Not_Start(0 , "未参加") ,
Fail(1 , "未通过") ,
Pass(2 ,"已通过");
Pass(2 ,"已通过") ,
Scoring(3 , "评分中");
private final Integer value;

2
src/main/java/com/project/task/domain/param/TaskParam.java

@ -23,4 +23,6 @@ public class TaskParam extends BaseParam {
private String taskStatus;
private Boolean excludeEnd = Boolean.TRUE;
}

60
src/main/java/com/project/task/domain/service/impl/CandidateSearchTaskDomainServiceImpl.java

@ -2,6 +2,8 @@ package com.project.task.domain.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -9,19 +11,27 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.project.base.domain.result.PageResult;
import com.project.base.domain.result.Result;
import com.project.base.domain.utils.PageConverter;
import com.project.classicpaper.domain.entity.ClassicCategoryEntity;
import com.project.classicpaper.domain.entity.ClassicPaperSetEntity;
import com.project.classicpaper.domain.service.ClassicCategoryBaseService;
import com.project.classicpaper.domain.service.ClassicPaperSetBaseService;
import com.project.ding.utils.SecurityUtils;
import com.project.exam.domain.entity.ExamRecordEntity;
import com.project.exam.mapper.ExamRecordMapper;
import com.project.information.domain.entity.ProductLineEntity;
import com.project.information.domain.service.ProductLineBaseService;
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.CandidateExamResultEnum;
import com.project.task.domain.enums.CandidateTaskStatusEnum;
import com.project.task.domain.enums.ExamModeEnum;
import com.project.task.domain.enums.TaskUserStatusEnum;
import com.project.task.domain.param.TaskParam;
import com.project.task.domain.service.CandidateSearchTaskDomainService;
import com.project.task.mapper.TaskMapper;
import com.project.task.mapper.TaskUserMapper;
import io.vavr.control.Try;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -44,6 +54,15 @@ public class CandidateSearchTaskDomainServiceImpl implements CandidateSearchTask
@Autowired
private ExamRecordMapper examRecordMapper;
@Autowired
private ProductLineBaseService productLineBaseService;
@Autowired
private ClassicPaperSetBaseService classicPaperSetBaseService;
@Autowired
private ClassicCategoryBaseService classicCategoryBaseService;
@Override
public Result<PageResult<TaskDTO>> candidateSearch(TaskParam param) throws Exception {
@ -74,6 +93,11 @@ public class CandidateSearchTaskDomainServiceImpl implements CandidateSearchTask
if (StrUtil.equals(param.getCandidateTaskStatus() , CandidateTaskStatusEnum.End.name())) {
queryWrapper.lt(TaskEntity::getEndTime , beginOfToday);
}
if (BooleanUtil.isTrue(param.getExcludeEnd())) {
// 强制要求:结束时间必须 >= 今天 00:00:00
// 这样,截止时间是今天的任务会被【保留】,只有昨天及以前截止的任务会被【排除】
queryWrapper.ge(TaskEntity::getEndTime, beginOfToday);
}
// 未考试:在有效期内,且用户状态为未参加考试
if (StrUtil.equals(param.getCandidateTaskStatus() , CandidateTaskStatusEnum.Not_Exam.name())) {
queryWrapper.le(TaskEntity::getStartTime, endOfToday);
@ -81,7 +105,7 @@ public class CandidateSearchTaskDomainServiceImpl implements CandidateSearchTask
queryWrapper.inSql(TaskEntity::getId,
String.format("SELECT task_id FROM evaluator_task_user WHERE user_id = '%s' AND status = %s and deleted = 0 ", SecurityUtils.getUserId() , TaskUserStatusEnum.Not_Start.getValue()));
}
// 已考试:在有效期内,用户状态为已通过或未通过
// 已考试:在有效期内,用户状态为已通过或未通过(不含评分中)
if (StrUtil.equals(param.getCandidateTaskStatus() , CandidateTaskStatusEnum.Has_Exam.name())) {
queryWrapper.le(TaskEntity::getStartTime, endOfToday);
queryWrapper.ge(TaskEntity::getEndTime, beginOfToday);
@ -90,6 +114,14 @@ public class CandidateSearchTaskDomainServiceImpl implements CandidateSearchTask
SecurityUtils.getUserId() , CollUtil.join(List.of(TaskUserStatusEnum.Fail.getValue() , TaskUserStatusEnum.Pass.getValue())
, ",")));
}
// 评分中:在有效期内,用户状态为评分中
if (StrUtil.equals(param.getCandidateTaskStatus() , CandidateTaskStatusEnum.Scoring.name())) {
queryWrapper.le(TaskEntity::getStartTime, endOfToday);
queryWrapper.ge(TaskEntity::getEndTime, beginOfToday);
queryWrapper.inSql(TaskEntity::getId,
String.format("SELECT task_id FROM evaluator_task_user WHERE user_id = '%s' AND status = %s and deleted = 0 ",
SecurityUtils.getUserId() , TaskUserStatusEnum.Scoring.getValue()));
}
// 排序
if (Objects.nonNull(param.getSortType())) {
switch (param.getSortType()) {
@ -149,6 +181,11 @@ public class CandidateSearchTaskDomainServiceImpl implements CandidateSearchTask
dto.setCandidateTaskStatus(CandidateTaskStatusEnum.Has_Exam.name());
dto.setCandidateTaskStatusText(CandidateTaskStatusEnum.Has_Exam.getValue());
}
if (TaskUserStatusEnum.Scoring.getValue().equals(taskUserEntity.getStatus())) {
dto.setCandidateTaskStatus(CandidateTaskStatusEnum.Scoring.name());
dto.setCandidateTaskStatusText(CandidateTaskStatusEnum.Scoring.getValue());
}
}
if (TaskUserStatusEnum.Pass.getValue().equals(taskUserEntity.getStatus())) {
dto.setExamResult(CandidateExamResultEnum.Pass.name());
@ -158,6 +195,10 @@ public class CandidateSearchTaskDomainServiceImpl implements CandidateSearchTask
dto.setExamResult(CandidateExamResultEnum.Fail.name());
dto.setExamResultText(CandidateExamResultEnum.Fail.getValue());
}
if (TaskUserStatusEnum.Scoring.getValue().equals(taskUserEntity.getStatus())) {
dto.setExamResult("Scoring");
dto.setExamResultText("评分中");
}
dto.setTaskUserStatus(TaskUserStatusEnum.getNameByValue(taskUserEntity.getStatus()));
dto.setLastRecordId(taskUserEntity.getLastRecordId());
if (Objects.nonNull(taskUserEntity.getLastRecordId())) {
@ -168,6 +209,23 @@ public class CandidateSearchTaskDomainServiceImpl implements CandidateSearchTask
dto.setLastRecordScoreStr(lastRecordScoreStr);
}
dto.setTotalScore((int) Math.floor(entity.getTotalScore()));
// 题目类型
dto.setExamModeTag(Try.of(() -> EnumUtil.getBy(ExamModeEnum::getValue, dto.getExamMode()))
.getOrElse(ExamModeEnum.GENERATIVE)
.getDesc());
if (ExamModeEnum.GENERATIVE.getValue().equals(dto.getExamMode())) {
// 生成式
ProductLineEntity byId = productLineBaseService.getById(dto.getSubLineId());
dto.setClassificationTag(String.format("%s - %s" , byId.getParentName() , byId.getName()));
} else {
// 经典
ClassicPaperSetEntity byId = classicPaperSetBaseService.getById(dto.getClassicPaperSetId());
ClassicCategoryEntity classicCategoryBaseServiceById = classicCategoryBaseService.getById(byId.getClassicCategoryId());
ClassicCategoryEntity classicCategoryBaseServiceByParentId = classicCategoryBaseService.getById(classicCategoryBaseServiceById.getParentId());
dto.setClassificationTag(String.format("%s - %s" , classicCategoryBaseServiceByParentId.getName() , byId.getName()));
}
return dto;
}
}

7
src/main/java/com/project/task/domain/service/impl/SearchTaskDomainServiceImpl.java

@ -2,6 +2,7 @@ package com.project.task.domain.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -98,6 +99,11 @@ public class SearchTaskDomainServiceImpl implements SearchTaskDomainService {
queryWrapper.le(TaskEntity::getStartTime, endOfToday);
queryWrapper.ge(TaskEntity::getEndTime, beginOfToday);
}
if (BooleanUtil.isTrue(param.getExcludeEnd())) {
// 强制要求:结束时间必须 >= 今天 00:00:00
// 这样,截止时间是今天的任务会被【保留】,只有昨天及以前截止的任务会被【排除】
queryWrapper.ge(TaskEntity::getEndTime, beginOfToday);
}
queryWrapper.orderByDesc(TaskEntity::getId);
IPage<TaskEntity> taskEntityPage = taskMapper.selectPage(
PageConverter.toMpPage(param),
@ -137,6 +143,7 @@ public class SearchTaskDomainServiceImpl implements SearchTaskDomainService {
case 0 -> notParticipatedNum.getAndIncrement();
case 1 -> notPassedNum.getAndIncrement();
case 2 -> passedNum.getAndIncrement();
case 3 -> notPassedNum.getAndIncrement();
}
return userDTO;
}).toList();

2
src/main/resources/application-test.yml

@ -114,4 +114,4 @@ scoring:
# 每批最多处理多少道简答题
batch-size: 5
# 执行间隔(毫秒),每60秒扫描一次
interval-ms: 60000
interval-ms: 600000
Loading…
Cancel
Save