diff --git a/src/main/java/com/project/classicpaper/application/impl/ClassicCategoryApplicationServiceImpl.java b/src/main/java/com/project/classicpaper/application/impl/ClassicCategoryApplicationServiceImpl.java index 29881ca..a063236 100644 --- a/src/main/java/com/project/classicpaper/application/impl/ClassicCategoryApplicationServiceImpl.java +++ b/src/main/java/com/project/classicpaper/application/impl/ClassicCategoryApplicationServiceImpl.java @@ -43,7 +43,7 @@ public class ClassicCategoryApplicationServiceImpl implements ClassicCategoryApp // 3. 查询套题组,统计数量和分组 List allPaperSets = classicPaperSetBaseService.lambdaQuery() - .select(ClassicPaperSetEntity::getClassicCategoryId, ClassicPaperSetEntity::getId, ClassicPaperSetEntity::getName) + .select(ClassicPaperSetEntity::getClassicCategoryId, ClassicPaperSetEntity::getId, ClassicPaperSetEntity::getName, ClassicPaperSetEntity::getStatus) .orderByDesc(ClassicPaperSetEntity::getId).list(); Map countMap = new HashMap<>(); Map> paperSetMap = Boolean.TRUE.equals(withPaperSet) ? new HashMap<>() : null; diff --git a/src/main/java/com/project/task/domain/service/strategy/ClassicTaskConfigStrategy.java b/src/main/java/com/project/task/domain/service/strategy/ClassicTaskConfigStrategy.java index b90d46d..be34efd 100644 --- a/src/main/java/com/project/task/domain/service/strategy/ClassicTaskConfigStrategy.java +++ b/src/main/java/com/project/task/domain/service/strategy/ClassicTaskConfigStrategy.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.project.base.domain.exception.BusinessErrorException; import com.project.classicpaper.domain.entity.ClassicPaperSetEntity; import com.project.classicpaper.domain.service.ClassicPaperSetBaseService; +import com.project.task.config.ExamScoreRatioConfig; import com.project.task.domain.dto.TaskDTO; import com.project.task.domain.entity.TaskEntity; import com.project.task.domain.service.TaskBaseService; @@ -35,6 +36,9 @@ public class ClassicTaskConfigStrategy implements TaskConfigStrategy { @Autowired private ClassicPaperSetBaseService classicPaperSetBaseService; + @Autowired + private ExamScoreRatioConfig examScoreRatioConfig; + private final ObjectMapper objectMapper = new ObjectMapper(); @Override @@ -97,25 +101,35 @@ public class ClassicTaskConfigStrategy implements TaskConfigStrategy { } /** - * 经典模式下题目数量和分数来自套卷,DTO 中可能为 null,赋默认值避免 NPE + * 经典模式下题目数量和分数来自套卷,DTO 中可能为 null,从纸套组补全以免写死 0 */ private void fillDefaults(TaskDTO dto) { + // 1. 从纸套组读取实际题量(如果 DTO 未传) + ClassicPaperSetEntity paperSet = null; + if (dto.getClassicPaperSetId() != null) { + paperSet = classicPaperSetBaseService.getById(dto.getClassicPaperSetId()); + } + + // 2. 补全题量:DTO 没传就从纸套取,纸套也没有就给 0 if (dto.getSingleChoiceNum() == null) { - dto.setSingleChoiceNum(0); + dto.setSingleChoiceNum(paperSet != null && paperSet.getSingleChoiceNum() != null ? paperSet.getSingleChoiceNum() : 0); } if (dto.getMultipleChoiceNum() == null) { - dto.setMultipleChoiceNum(0); + dto.setMultipleChoiceNum(paperSet != null && paperSet.getMultipleChoiceNum() != null ? paperSet.getMultipleChoiceNum() : 0); } if (dto.getTrueFalseNum() == null) { - dto.setTrueFalseNum(0); + dto.setTrueFalseNum(paperSet != null && paperSet.getTrueFalseNum() != null ? paperSet.getTrueFalseNum() : 0); } if (dto.getShortAnswerNum() == null) { - dto.setShortAnswerNum(0); + dto.setShortAnswerNum(paperSet != null && paperSet.getShortAnswerNum() != null ? paperSet.getShortAnswerNum() : 0); } - // 从套题组的分值比例计算每题分值(保留2位小数) - calculateScoresFromRatio(dto); + // 3. 从纸套比例算分(传入 paperSet 避免重复查询) + if (paperSet != null) { + calculateScoresFromRatio(dto, paperSet); + } + // 4. 补全分数:算分后仍为 null 才给 0 if (dto.getSingleChoiceScore() == null) { dto.setSingleChoiceScore(0.0); } @@ -142,39 +156,72 @@ public class ClassicTaskConfigStrategy implements TaskConfigStrategy { /** * 从 ClassicPaperSet.scoreRatio 解析比例,计算每题分值 * 公式:每题分值 = 100 × 题型比例 / 总比例 / 该题型数量 + * 条件判断用 DTO 的题量(已在 fillDefaults 中从纸套补全),确保与任务实际题量一致 */ - private void calculateScoresFromRatio(TaskDTO dto) { - if (dto.getClassicPaperSetId() == null) { - return; - } - ClassicPaperSetEntity paperSet = classicPaperSetBaseService.getById(dto.getClassicPaperSetId()); - if (paperSet == null || StrUtil.isBlank(paperSet.getScoreRatio())) { + private void calculateScoresFromRatio(TaskDTO dto, ClassicPaperSetEntity paperSet) { + if (StrUtil.isBlank(paperSet.getScoreRatio())) { + // 纸套没有分值比例时,用配置默认权重计算(同生成式模式逻辑) + calculateScoresFromDefaultWeights(dto); return; } try { - Map ratioMap = objectMapper.readValue(paperSet.getScoreRatio(), Map.class); + // JacksonTypeHandler 对 String 字段存 JSON 时会产生二次编码(存为 JSON 字符串),需要反解一次 + String scoreRatioStr = paperSet.getScoreRatio(); + if (scoreRatioStr.startsWith("\"") && scoreRatioStr.endsWith("\"")) { + scoreRatioStr = objectMapper.readValue(scoreRatioStr, String.class); + } + Map ratioMap = objectMapper.readValue(scoreRatioStr, Map.class); int totalRatio = ratioMap.values().stream().mapToInt(Integer::intValue).sum(); if (totalRatio <= 0) { + calculateScoresFromDefaultWeights(dto); return; } - if (paperSet.getSingleChoiceNum() != null && paperSet.getSingleChoiceNum() > 0) { - double perScore = 100.0 * ratioMap.getOrDefault("single", 0) / totalRatio / paperSet.getSingleChoiceNum(); + if (dto.getSingleChoiceNum() != null && dto.getSingleChoiceNum() > 0) { + double perScore = 100.0 * ratioMap.getOrDefault("single", 0) / totalRatio / dto.getSingleChoiceNum(); dto.setSingleChoiceScore(BigDecimal.valueOf(perScore).setScale(2, RoundingMode.HALF_UP).doubleValue()); } - if (paperSet.getMultipleChoiceNum() != null && paperSet.getMultipleChoiceNum() > 0) { - double perScore = 100.0 * ratioMap.getOrDefault("multiple", 0) / totalRatio / paperSet.getMultipleChoiceNum(); + if (dto.getMultipleChoiceNum() != null && dto.getMultipleChoiceNum() > 0) { + double perScore = 100.0 * ratioMap.getOrDefault("multiple", 0) / totalRatio / dto.getMultipleChoiceNum(); dto.setMultipleChoiceScore(BigDecimal.valueOf(perScore).setScale(2, RoundingMode.HALF_UP).doubleValue()); } - if (paperSet.getTrueFalseNum() != null && paperSet.getTrueFalseNum() > 0) { - double perScore = 100.0 * ratioMap.getOrDefault("trueFalse", 0) / totalRatio / paperSet.getTrueFalseNum(); + if (dto.getTrueFalseNum() != null && dto.getTrueFalseNum() > 0) { + double perScore = 100.0 * ratioMap.getOrDefault("trueFalse", 0) / totalRatio / dto.getTrueFalseNum(); dto.setTrueFalseScore(BigDecimal.valueOf(perScore).setScale(2, RoundingMode.HALF_UP).doubleValue()); } - if (paperSet.getShortAnswerNum() != null && paperSet.getShortAnswerNum() > 0) { - double perScore = 100.0 * ratioMap.getOrDefault("shortAnswer", 0) / totalRatio / paperSet.getShortAnswerNum(); + if (dto.getShortAnswerNum() != null && dto.getShortAnswerNum() > 0) { + double perScore = 100.0 * ratioMap.getOrDefault("shortAnswer", 0) / totalRatio / dto.getShortAnswerNum(); dto.setShortAnswerScore(BigDecimal.valueOf(perScore).setScale(2, RoundingMode.HALF_UP).doubleValue()); } } catch (Exception e) { log.warn(">>> [经典模式] scoreRatio 解析失败, paperSetId={}", dto.getClassicPaperSetId(), e); + calculateScoresFromDefaultWeights(dto); } } + + /** + * 用配置默认权重计算每题分值(降级方案,同生成式模式逻辑) + * 公式:base = 总分 / 总权重,每题分值 = base × 题型权重 + */ + private void calculateScoresFromDefaultWeights(TaskDTO dto) { + int shortAnswerNum = dto.getShortAnswerNum() != null ? dto.getShortAnswerNum() : 0; + + int totalUnit = dto.getSingleChoiceNum() * examScoreRatioConfig.getSingle() + + dto.getMultipleChoiceNum() * examScoreRatioConfig.getMultiple() + + dto.getTrueFalseNum() * examScoreRatioConfig.getTrueFalse() + + shortAnswerNum * examScoreRatioConfig.getShortAnswer(); + if (totalUnit <= 0) { + return; + } + + double base = examScoreRatioConfig.getTotalScore() * 1.0 / totalUnit; + + dto.setSingleChoiceScore(dto.getSingleChoiceNum() > 0 + ? Math.round(base * examScoreRatioConfig.getSingle() * 100) / 100.0 : 0.0); + dto.setMultipleChoiceScore(dto.getMultipleChoiceNum() > 0 + ? Math.round(base * examScoreRatioConfig.getMultiple() * 100) / 100.0 : 0.0); + dto.setTrueFalseScore(dto.getTrueFalseNum() > 0 + ? Math.round(base * examScoreRatioConfig.getTrueFalse() * 100) / 100.0 : 0.0); + dto.setShortAnswerScore(shortAnswerNum > 0 + ? Math.round(base * examScoreRatioConfig.getShortAnswer() * 100) / 100.0 : 0.0); + } } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 2755fd1..0d08fa1 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -76,6 +76,8 @@ ding: agentId: 4283077101 corpId: ding13d71da66ad91ff0f5bf40eda33b7ba0 noticeUrlPrefix: https://107pm707566hq.vicp.fun/ai-evaluator +# appKey: ding4eootvq4jzas96lr #保伦架构 +# appSecret: UI6XcD8GFPE_W_yo2eQkMuoSsTEf1whpZYEXrsDA7CV7bkJp40B3VNcETWS1aGgg algo: clusterUrl: /semantic-cluster baseUrl: http://172.16.204.50:8002