From d6be0d0044eccdb4b6b5f542e0312494af7b7610 Mon Sep 17 00:00:00 2001 From: luoweijian <1329394916@qq.com> Date: Tue, 30 Jun 2026 19:50:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E4=BD=93=E7=B1=BB=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ClassicCategoryApplicationServiceImpl.java | 51 ++++++++++++++- ...ClassicPaperSetApplicationServiceImpl.java | 18 ++++- .../domain/dto/ClassicCategoryDTO.java | 3 + .../domain/entity/ClassicPaperEntity.java | 3 +- .../domain/entity/ClassicPaperSetEntity.java | 11 ++-- .../service/PaperGenerationTracker.java | 58 ----------------- ...assicPaperQuestionCallbackServiceImpl.java | 8 +-- ...GenerateClassicPaperDomainServiceImpl.java | 33 +++------- .../ding/domain/entity/DepartmentEntity.java | 4 +- .../ding/domain/entity/UserEntity.java | 3 +- .../domain/entity/AiGradingLogEntity.java | 4 +- .../DraftReviewApplicationServiceImpl.java | 65 ++++++++++++------- .../domain/entity/KnowledgePointEntity.java | 4 +- .../domain/entity/QuestionEntity.java | 6 +- .../entity/ErrorProneStatisticsEntity.java | 7 +- .../task/domain/entity/TaskEntity.java | 4 +- .../entity/TaskPaperSnapshotEntity.java | 3 +- 17 files changed, 155 insertions(+), 130 deletions(-) delete mode 100644 src/main/java/com/project/classicpaper/domain/service/PaperGenerationTracker.java 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 303550c..159a64a 100644 --- a/src/main/java/com/project/classicpaper/application/impl/ClassicCategoryApplicationServiceImpl.java +++ b/src/main/java/com/project/classicpaper/application/impl/ClassicCategoryApplicationServiceImpl.java @@ -8,11 +8,15 @@ import com.project.base.domain.utils.TreeUtils; import com.project.classicpaper.application.ClassicCategoryApplicationService; import com.project.classicpaper.domain.dto.ClassicCategoryDTO; 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 org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -22,16 +26,59 @@ public class ClassicCategoryApplicationServiceImpl implements ClassicCategoryApp @Autowired private ClassicCategoryBaseService classicCategoryBaseService; + @Autowired + private ClassicPaperSetBaseService classicPaperSetBaseService; + @Override public Result> treeList() { + // 1. 查所有分类 → DTO List list = classicCategoryBaseService.list( new LambdaQueryWrapper().orderByAsc(ClassicCategoryEntity::getSort) ).stream().map(entity -> entity.toDTO(ClassicCategoryDTO::new)) .collect(Collectors.toList()); - return Result.success(TreeUtils.buildLongTree(list, + + // 2. 构建树 + List tree = TreeUtils.buildLongTree(list, ClassicCategoryDTO::getId, ClassicCategoryDTO::getParentId, - ClassicCategoryDTO::setChildrenList)); + ClassicCategoryDTO::setChildrenList); + + // 3. 统计各分类下的套题组数量 + List allSets = classicPaperSetBaseService.lambdaQuery() + .select(ClassicPaperSetEntity::getClassicCategoryId) + .list(); + Map countMap = new HashMap<>(); + for (ClassicPaperSetEntity set : allSets) { + Long catId = set.getClassicCategoryId(); + if (catId != null) { + countMap.merge(catId, 1, Integer::sum); + } + } + + // 4. 注入 paperSetCount 到树节点 + injectPaperSetCount(tree, countMap); + + return Result.success(tree); + } + + /** + * 递归注入 paperSetCount: + * 二级节点取直接统计值,一级节点累加子节点 + */ + private void injectPaperSetCount(List nodes, Map countMap) { + for (ClassicCategoryDTO node : nodes) { + if (node.getChildrenList() != null && !node.getChildrenList().isEmpty()) { + // 一级分类:先递归处理子节点,再累加 + injectPaperSetCount(node.getChildrenList(), countMap); + int sum = node.getChildrenList().stream() + .mapToInt(c -> c.getPaperSetCount() != null ? c.getPaperSetCount() : 0) + .sum(); + node.setPaperSetCount(sum); + } else { + // 二级分类:直接取统计值 + node.setPaperSetCount(countMap.getOrDefault(node.getId(), 0)); + } + } } @Override diff --git a/src/main/java/com/project/classicpaper/application/impl/ClassicPaperSetApplicationServiceImpl.java b/src/main/java/com/project/classicpaper/application/impl/ClassicPaperSetApplicationServiceImpl.java index a968993..d1e17d6 100644 --- a/src/main/java/com/project/classicpaper/application/impl/ClassicPaperSetApplicationServiceImpl.java +++ b/src/main/java/com/project/classicpaper/application/impl/ClassicPaperSetApplicationServiceImpl.java @@ -18,6 +18,7 @@ import com.project.classicpaper.domain.entity.ClassicPaperSetEntity; import com.project.classicpaper.domain.entity.RegenerateQuestionTaskEntity; import com.project.classicpaper.domain.enums.ClassicPaperStatusEnum; import com.project.classicpaper.domain.param.ClassicPaperSetParam; +import com.project.classicpaper.domain.entity.ClassicCategoryEntity; import com.project.classicpaper.domain.service.*; import com.project.question.domain.entity.QuestionEntity; import com.project.question.domain.service.QuestionBaseService; @@ -58,6 +59,9 @@ public class ClassicPaperSetApplicationServiceImpl implements ClassicPaperSetApp @Autowired private ImportClassicPaperDomainService importClassicPaperDomainService; + @Autowired + private ClassicCategoryBaseService classicCategoryBaseService; + @Autowired private com.project.task.config.ExamScoreRatioConfig examScoreRatioConfig; @@ -77,7 +81,19 @@ public class ClassicPaperSetApplicationServiceImpl implements ClassicPaperSetApp wrapper.eq(ClassicPaperSetEntity::getSubLineId, param.getSubLineId()); } if (param.getClassicCategoryId() != null) { - wrapper.eq(ClassicPaperSetEntity::getClassicCategoryId, param.getClassicCategoryId()); + Set catIds = new HashSet<>(); + catIds.add(param.getClassicCategoryId()); + // 如果是一级分类,查找所有二级子分类 + ClassicCategoryEntity cat = classicCategoryBaseService.getById(param.getClassicCategoryId()); + if (cat != null && cat.getLevel() != null && cat.getLevel() == 1) { + List children = classicCategoryBaseService.lambdaQuery() + .eq(ClassicCategoryEntity::getParentId, param.getClassicCategoryId()) + .list(); + for (ClassicCategoryEntity child : children) { + catIds.add(child.getId()); + } + } + wrapper.in(ClassicPaperSetEntity::getClassicCategoryId, catIds); } if (param.getStatus() != null) { wrapper.eq(ClassicPaperSetEntity::getStatus, param.getStatus()); diff --git a/src/main/java/com/project/classicpaper/domain/dto/ClassicCategoryDTO.java b/src/main/java/com/project/classicpaper/domain/dto/ClassicCategoryDTO.java index 24b1385..94a9b59 100644 --- a/src/main/java/com/project/classicpaper/domain/dto/ClassicCategoryDTO.java +++ b/src/main/java/com/project/classicpaper/domain/dto/ClassicCategoryDTO.java @@ -18,5 +18,8 @@ public class ClassicCategoryDTO extends BaseDTO { private Integer sort = 0; + /** 该分类下的套题组数量(一级=下属二级总和,二级=直接数量) */ + private Integer paperSetCount = 0; + private List childrenList = new ArrayList<>(); } diff --git a/src/main/java/com/project/classicpaper/domain/entity/ClassicPaperEntity.java b/src/main/java/com/project/classicpaper/domain/entity/ClassicPaperEntity.java index 364a0e2..827f414 100644 --- a/src/main/java/com/project/classicpaper/domain/entity/ClassicPaperEntity.java +++ b/src/main/java/com/project/classicpaper/domain/entity/ClassicPaperEntity.java @@ -40,8 +40,9 @@ public class ClassicPaperEntity extends BaseEntity { @Comment("来源子产品线ID") private Long subLineId; - @Column(name = "information_ids", columnDefinition = "json comment '关联资料ID列表'") + @Column(name = "information_ids") @TableField("information_ids") + @Comment("关联资料ID列表") private String informationIds; @Column(name = "status") diff --git a/src/main/java/com/project/classicpaper/domain/entity/ClassicPaperSetEntity.java b/src/main/java/com/project/classicpaper/domain/entity/ClassicPaperSetEntity.java index e287b7e..47cab46 100644 --- a/src/main/java/com/project/classicpaper/domain/entity/ClassicPaperSetEntity.java +++ b/src/main/java/com/project/classicpaper/domain/entity/ClassicPaperSetEntity.java @@ -4,11 +4,13 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import com.project.base.domain.entity.BaseEntity; import jakarta.persistence.*; import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Comment; +import org.hibernate.annotations.JdbcTypeCode; @Data @Table(name = "evaluator_classic_paper_set", @@ -76,14 +78,15 @@ public class ClassicPaperSetEntity extends BaseEntity { @Comment("简答题数量") private Integer shortAnswerNum; - @Column(name = "score_ratio", columnDefinition = "json comment '分值比例配置'") - @TableField("score_ratio") + @Column(name = "score_ratio") // 移除 columnDefinition + @Comment("分值比例配置") // 使用专门的注解来定义注释 + @JdbcTypeCode(org.hibernate.type.SqlTypes.JSON) // 明确告知 Hibernate 这是 JSON 类型 + @TableField(value = "score_ratio", typeHandler = JacksonTypeHandler.class) // MyBatis-Plus 配置 private String scoreRatio; @Column(name = "status") @TableField("status") - @Comment("状态:0-生成中,1-草稿,2-已确认,3-已废弃") - private Integer status; + @Comment("状态:0-生成中,1-草稿,2-已确认,3-已废弃") private Integer status; @Column(name = "source_file_name", columnDefinition = "varchar(500) comment '导入原始文件MinIO路径(Word导入时记录)'") @TableField("source_file_name") diff --git a/src/main/java/com/project/classicpaper/domain/service/PaperGenerationTracker.java b/src/main/java/com/project/classicpaper/domain/service/PaperGenerationTracker.java deleted file mode 100644 index 71f0c66..0000000 --- a/src/main/java/com/project/classicpaper/domain/service/PaperGenerationTracker.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.project.classicpaper.domain.service; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; - -/** - * 经典套卷生题等待跟踪器 - * generate() 通过它等待所有异步回调完成后才返回 - */ -@Component -@Slf4j -public class PaperGenerationTracker { - - private final ConcurrentHashMap latches = new ConcurrentHashMap<>(); - - /** - * 开始跟踪某个 paper 的生成进度 - * @param paperId 套卷ID - * @param totalCount 需要生成的题目总数 - */ - public void track(Long paperId, int totalCount) { - latches.put(paperId, new CountDownLatch(totalCount)); - log.info(">>> [生题跟踪] 开始跟踪 paperId={}, 总题数={}", paperId, totalCount); - } - - /** - * 某道题回调完成,countDown - */ - public void onQuestionGenerated(Long paperId) { - CountDownLatch latch = latches.get(paperId); - if (latch != null) { - latch.countDown(); - log.debug(">>> [生题跟踪] paperId={}, 剩余={}", paperId, latch.getCount()); - } - } - - /** - * 等待所有题目生成完成(一直等待,无超时) - */ - public void waitForCompletion(Long paperId) { - CountDownLatch latch = latches.get(paperId); - if (latch == null) { - return; - } - try { - latch.await(); - log.info(">>> [生题跟踪] paperId={} 所有题目生成完成", paperId); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - log.warn(">>> [生题跟踪] paperId={} 等待被中断", paperId); - } finally { - latches.remove(paperId); - } - } -} diff --git a/src/main/java/com/project/classicpaper/domain/service/impl/ClassicPaperQuestionCallbackServiceImpl.java b/src/main/java/com/project/classicpaper/domain/service/impl/ClassicPaperQuestionCallbackServiceImpl.java index b5b6f88..ad5761b 100644 --- a/src/main/java/com/project/classicpaper/domain/service/impl/ClassicPaperQuestionCallbackServiceImpl.java +++ b/src/main/java/com/project/classicpaper/domain/service/impl/ClassicPaperQuestionCallbackServiceImpl.java @@ -40,9 +40,6 @@ public class ClassicPaperQuestionCallbackServiceImpl implements ClassicPaperQues @Autowired private ClassicPaperSetBaseService classicPaperSetBaseService; - @Autowired - private PaperGenerationTracker paperGenerationTracker; - @Override @Transactional(rollbackFor = Exception.class) public void handleCallback(QuestionCallBackDTO callback) { @@ -105,10 +102,7 @@ public class ClassicPaperQuestionCallbackServiceImpl implements ClassicPaperQues log.info(">>> [经典套题-回调] 处理完成, paperQuestionId={}, promotedQuestionId={}", paperQuestionId, promoted.getId()); - // 5. 通知跟踪器(释放 generate() 的等待) - paperGenerationTracker.onQuestionGenerated(paperId); - - // 6. 检查当前 paper 的所有题目是否都已生成完成 + // 检查当前 paper 的所有题目是否都已生成完成 boolean paperAllDone = classicPaperQuestionBaseService.count( new LambdaQueryWrapper() .eq(ClassicPaperQuestionEntity::getPaperId, paperId) diff --git a/src/main/java/com/project/classicpaper/domain/service/impl/GenerateClassicPaperDomainServiceImpl.java b/src/main/java/com/project/classicpaper/domain/service/impl/GenerateClassicPaperDomainServiceImpl.java index 0bb673e..a63484a 100644 --- a/src/main/java/com/project/classicpaper/domain/service/impl/GenerateClassicPaperDomainServiceImpl.java +++ b/src/main/java/com/project/classicpaper/domain/service/impl/GenerateClassicPaperDomainServiceImpl.java @@ -72,9 +72,6 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap @Autowired private com.project.task.config.ExamScoreRatioConfig examScoreRatioConfig; - @Autowired - private PaperGenerationTracker paperGenerationTracker; - @Value("${classicpaper.spare.per-question:2}") private int sparePerQuestion; @@ -184,20 +181,16 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap paperDTOs.add(paperDTO); } - // 8. 所有子套题生成完成,将状态从"生成中"改为"草稿" - classicPaperBaseService.lambdaUpdate() - .eq(ClassicPaperEntity::getSetId, paperSet.getId()) - .set(ClassicPaperEntity::getStatus, ClassicPaperStatusEnum.DRAFT.getValue()) - .update(); - paperSet.setStatus(ClassicPaperStatusEnum.DRAFT.getValue()); - classicPaperSetBaseService.updateById(paperSet); + // 注意:生题为异步流程,此处不等待完成 + // paper 状态会在回调中逐步更新为 DRAFT + // paperSet 状态会在所有 paper 都完成后更新为 DRAFT - log.info(">>> [经典套题] 批量生成完成, setId={}, 版本数={}, 每套题数={}", + log.info(">>> [经典套题] 生成任务已提交, setId={}, 版本数={}, 每套题数={}", paperSet.getId(), setCount, totalPerSet); - // 10. 构建返回 DTO + // 8. 构建返回 DTO(套题组状态为 GENERATING,等待异步完成) ClassicPaperSetDTO setDTO = paperSet.toDTO(ClassicPaperSetDTO::new); - setDTO.setStatusText(ClassicPaperStatusEnum.DRAFT.getDesc()); + setDTO.setStatusText(ClassicPaperStatusEnum.GENERATING.getDesc()); setDTO.setPaperList(paperDTOs); return Result.success(setDTO); } @@ -363,9 +356,6 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap // ============ Phase 2: 提交异步生题任务 ============ - // 注册等待跟踪 - paperGenerationTracker.track(paper.getId(), totalQuestions); - // 逐个提交异步任务(使用 Phase 1 采样好的 KPs) for (PaperQuestionTask task : paperQuestionTasks) { classicPaperQuestionGenerator.generateAsync( @@ -373,15 +363,12 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap 1 + sparePerQuestion); } - // ============ Phase 3: 等待所有回调完成 ============ - - paperGenerationTracker.waitForCompletion(paper.getId()); - - // ============ Phase 4: 构建返回 DTO ============ + // ============ Phase 3: 立即返回 ============ + // 生题为异步流程,回调会逐步填充 questionId 并更新状态 + // 此处不阻塞等待,立即返回 - // 回调已填充 questionId,paper 状态已在回调中更新为 DRAFT ClassicPaperDTO dto = paper.toDTO(ClassicPaperDTO::new); - dto.setStatusText(ClassicPaperStatusEnum.DRAFT.getDesc()); + dto.setStatusText(ClassicPaperStatusEnum.GENERATING.getDesc()); return dto; } diff --git a/src/main/java/com/project/ding/domain/entity/DepartmentEntity.java b/src/main/java/com/project/ding/domain/entity/DepartmentEntity.java index 121a561..9c3ae12 100644 --- a/src/main/java/com/project/ding/domain/entity/DepartmentEntity.java +++ b/src/main/java/com/project/ding/domain/entity/DepartmentEntity.java @@ -9,6 +9,7 @@ import com.project.base.domain.entity.BaseEntity; import jakarta.persistence.*; import lombok.Data; import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Comment; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.type.SqlTypes; @@ -35,7 +36,8 @@ public class DepartmentEntity extends BaseEntity { @TableField(value = "dept_id_path" , typeHandler = JacksonTypeHandler.class) - @Column(name = "dept_id_path", columnDefinition = "json comment '部门ID全路径'") + @Column(name = "dept_id_path") @JdbcTypeCode(SqlTypes.JSON) + @Comment("部门ID全路径") private List deptIdPath; } diff --git a/src/main/java/com/project/ding/domain/entity/UserEntity.java b/src/main/java/com/project/ding/domain/entity/UserEntity.java index 08c78a6..eca8f15 100644 --- a/src/main/java/com/project/ding/domain/entity/UserEntity.java +++ b/src/main/java/com/project/ding/domain/entity/UserEntity.java @@ -61,8 +61,9 @@ public class UserEntity extends BaseEntity { * 存储为 JSON 数组: [1, 10, 101] */ @TableField(value = "dept_id_list" , typeHandler = JacksonTypeHandler.class) - @Column(name = "dept_id_list", columnDefinition = "json comment '部门ID列表'") + @Column(name = "dept_id_list") @JdbcTypeCode(SqlTypes.JSON) + @Comment("部门ID列表") private List deptIdList; @Column(name = "dept_path_name_str" , columnDefinition="varchar(1000) comment '部门全路径集合'") diff --git a/src/main/java/com/project/exam/domain/entity/AiGradingLogEntity.java b/src/main/java/com/project/exam/domain/entity/AiGradingLogEntity.java index 1c6dcde..8bec474 100644 --- a/src/main/java/com/project/exam/domain/entity/AiGradingLogEntity.java +++ b/src/main/java/com/project/exam/domain/entity/AiGradingLogEntity.java @@ -62,7 +62,9 @@ public class AiGradingLogEntity extends BaseEntity { /** 命中的得分点index列表 */ @TableField(value = "hit_points", typeHandler = JacksonTypeHandler.class) @JdbcTypeCode(SqlTypes.JSON) - @Column(name = "hit_points", columnDefinition = "json comment '命中得分点列表'") + @Column(name = "hit_points") + @Comment("命中得分点列表") + private List hitPoints; /** 总得分点数 */ diff --git a/src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java b/src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java index 77c74c7..432298d 100644 --- a/src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java +++ b/src/main/java/com/project/information/application/impl/DraftReviewApplicationServiceImpl.java @@ -24,7 +24,11 @@ import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -154,23 +158,25 @@ public class DraftReviewApplicationServiceImpl implements DraftReviewApplication throw new BusinessErrorException("该资料不在待审核状态"); } - // 2. 获取该资料下所有待审核草稿 - List existingDrafts = knowledgePointDraftBaseService.list( - new LambdaQueryWrapper() - .eq(KnowledgePointDraftEntity::getInformationId, informationId) - .eq(KnowledgePointDraftEntity::getAuditStatus, AuditStatusEnum.PENDING.getValue())); - List existingIds = existingDrafts.stream() - .map(KnowledgePointDraftEntity::getId).toList(); + // 2. 获取该资料下所有待审核草稿ID(仅查ID,减少数据传输) + List existingIds = knowledgePointDraftBaseService.lambdaQuery() + .select(KnowledgePointDraftEntity::getId) + .eq(KnowledgePointDraftEntity::getInformationId, informationId) + .eq(KnowledgePointDraftEntity::getAuditStatus, AuditStatusEnum.PENDING.getValue()) + .list() + .stream() + .map(KnowledgePointDraftEntity::getId) + .toList(); - // 3. 用户传来的草稿ID集合 - List incomingIds = draftList.stream() + // 3. 用户传来的草稿ID集合(用Set,O(1)查找) + Set incomingIdSet = draftList.stream() .map(DraftSaveDTO::getId) .filter(Objects::nonNull) - .toList(); + .collect(Collectors.toSet()); // 4. 计算用户删除的草稿ID List deletedIds = existingIds.stream() - .filter(id -> !incomingIds.contains(id)) + .filter(id -> !incomingIdSet.contains(id)) .toList(); // 5. 逻辑删除(deleted=1),保留审计记录 @@ -181,21 +187,32 @@ public class DraftReviewApplicationServiceImpl implements DraftReviewApplication .update(); } - // 6. 更新/编辑草稿 + // 6. 批量查现存草稿,批量更新确认(替代逐个 getById + updateById) + List toConfirmIds = incomingIdSet.stream() + .filter(existingIds::contains) + .toList(); List confirmedDrafts = new ArrayList<>(); - for (DraftSaveDTO dto : draftList) { - if (dto.getId() != null) { - // 编辑现有草稿 - KnowledgePointDraftEntity oldDraft = knowledgePointDraftBaseService.getById(dto.getId()); - if (oldDraft != null && AuditStatusEnum.PENDING.getValue().equals(oldDraft.getAuditStatus())) { - oldDraft.setContent(dto.getContent()); - oldDraft.setKnowledgeType(dto.getKnowledgeType() != null ? dto.getKnowledgeType() : oldDraft.getKnowledgeType()); - // aiContent 保留不动(AI原始返回用于审计对比) - oldDraft.setAuditStatus(AuditStatusEnum.APPROVED.getValue()); - knowledgePointDraftBaseService.updateById(oldDraft); - confirmedDrafts.add(oldDraft); + if (!toConfirmIds.isEmpty()) { + // 构建 dto 映射,O(1) 查找 + Map dtoMap = draftList.stream() + .filter(d -> d.getId() != null) + .collect(Collectors.toMap(DraftSaveDTO::getId, d -> d)); + List existingDrafts = knowledgePointDraftBaseService.listByIds(toConfirmIds); + for (KnowledgePointDraftEntity draft : existingDrafts) { + if (!AuditStatusEnum.PENDING.getValue().equals(draft.getAuditStatus())) { + continue; + } + DraftSaveDTO dto = dtoMap.get(draft.getId()); + if (dto == null) { + continue; } + draft.setContent(dto.getContent()); + draft.setKnowledgeType(dto.getKnowledgeType() != null ? dto.getKnowledgeType() : draft.getKnowledgeType()); + // aiContent 保留不动(AI原始返回用于审计对比) + draft.setAuditStatus(AuditStatusEnum.APPROVED.getValue()); + confirmedDrafts.add(draft); } + knowledgePointDraftBaseService.updateBatchById(confirmedDrafts); } // 7. 复制草稿content到正式知识点表 @@ -218,7 +235,7 @@ public class DraftReviewApplicationServiceImpl implements DraftReviewApplication .update(); // 9. 触发聚类 - triggerClustering(informationId, knowledgePoints); + CompletableFuture.runAsync(() -> triggerClustering(informationId, knowledgePoints)); log.info(">>> [草稿审核] 批量保存并确认完成, informationId={}, 草稿数={}", informationId, confirmedDrafts.size()); return Result.success("保存成功,已审核通过"); diff --git a/src/main/java/com/project/information/domain/entity/KnowledgePointEntity.java b/src/main/java/com/project/information/domain/entity/KnowledgePointEntity.java index 2392279..9e936a6 100644 --- a/src/main/java/com/project/information/domain/entity/KnowledgePointEntity.java +++ b/src/main/java/com/project/information/domain/entity/KnowledgePointEntity.java @@ -55,7 +55,9 @@ public class KnowledgePointEntity extends BaseEntity { @TableField(value = "exam_focus_list" , typeHandler = JacksonTypeHandler.class) @JdbcTypeCode(SqlTypes.JSON) - @Column(name = "exam_focus_list", columnDefinition = "json comment '考点集合'") + @Column(name = "exam_focus_list") + @Comment("考点集合") + private List examFocusList; diff --git a/src/main/java/com/project/question/domain/entity/QuestionEntity.java b/src/main/java/com/project/question/domain/entity/QuestionEntity.java index 56ee5f6..2fadc36 100644 --- a/src/main/java/com/project/question/domain/entity/QuestionEntity.java +++ b/src/main/java/com/project/question/domain/entity/QuestionEntity.java @@ -47,7 +47,8 @@ public class QuestionEntity extends BaseEntity { @TableField(value = "kp_id_list" , typeHandler = JacksonTypeHandler.class) @JdbcTypeCode(SqlTypes.JSON) - @Column(name = "kp_id_list", columnDefinition = "json comment '覆盖知识点ID列表'") + @Column(name = "kp_id_list") + @Comment("覆盖知识点ID列表") private List kpIdList; @@ -63,7 +64,8 @@ public class QuestionEntity extends BaseEntity { @TableField(value = "question_detail" , typeHandler = JacksonTypeHandler.class) @JdbcTypeCode(SqlTypes.JSON) - @Column(name = "question_detail", columnDefinition = "json comment '题目内容'") + @Column(name = "question_detail") + @Comment("题目内容") private QuestionDetail questionDetail; @Data diff --git a/src/main/java/com/project/statistics/domain/entity/ErrorProneStatisticsEntity.java b/src/main/java/com/project/statistics/domain/entity/ErrorProneStatisticsEntity.java index baee1a7..3609576 100644 --- a/src/main/java/com/project/statistics/domain/entity/ErrorProneStatisticsEntity.java +++ b/src/main/java/com/project/statistics/domain/entity/ErrorProneStatisticsEntity.java @@ -46,8 +46,9 @@ public class ErrorProneStatisticsEntity extends BaseEntity { * 生成式:多个题目ID,经典套题:只有一个题目ID */ @TableField(value = "question_id_list" , typeHandler = JacksonTypeHandler.class) - @Column(name = "question_id_list", columnDefinition = "json comment '关联题目列表'") + @Column(name = "question_id_list") @JdbcTypeCode(SqlTypes.JSON) + @Comment("关联题目列表") private List questionIdList; @Column(name = "kp_id") @@ -75,7 +76,9 @@ public class ErrorProneStatisticsEntity extends BaseEntity { @TableField(value = "option_detail" , typeHandler = JacksonTypeHandler.class) @JdbcTypeCode(SqlTypes.JSON) - @Column(name = "option_detail", columnDefinition = "json comment '选项内容'") + @Column(name = "option_detail") + @Comment("选项内容") + private List optionDetails; @Data diff --git a/src/main/java/com/project/task/domain/entity/TaskEntity.java b/src/main/java/com/project/task/domain/entity/TaskEntity.java index 47b03db..2edc888 100644 --- a/src/main/java/com/project/task/domain/entity/TaskEntity.java +++ b/src/main/java/com/project/task/domain/entity/TaskEntity.java @@ -99,8 +99,10 @@ public class TaskEntity extends BaseEntity { * 存储为 JSON 数组: [1, 10, 101] */ @TableField(value = "related_document_list" , typeHandler = JacksonTypeHandler.class) - @Column(name = "related_document_list", columnDefinition = "json comment '关联文档列表'") + @Column(name = "related_document_list") @JdbcTypeCode(SqlTypes.JSON) + @Comment("关联文档列表") + private List relatedDocumentList; diff --git a/src/main/java/com/project/task/domain/entity/TaskPaperSnapshotEntity.java b/src/main/java/com/project/task/domain/entity/TaskPaperSnapshotEntity.java index 9c119b9..6b1d6e4 100644 --- a/src/main/java/com/project/task/domain/entity/TaskPaperSnapshotEntity.java +++ b/src/main/java/com/project/task/domain/entity/TaskPaperSnapshotEntity.java @@ -57,6 +57,7 @@ public class TaskPaperSnapshotEntity extends BaseEntity { @TableField(value = "question_detail", typeHandler = JacksonTypeHandler.class) @JdbcTypeCode(SqlTypes.JSON) - @Column(name = "question_detail", columnDefinition = "json comment '题目内容快照(题干+选项+答案+解析,含图片URL)'") + @Column(name = "question_detail") + @Comment("题目内容快照(题干+选项+答案+解析,含图片URL)") private QuestionEntity.QuestionDetail questionDetail; }