feat(复习):标准思维导图生成与回忆对比

- 新增 review_standard_mind_maps / review_recall_records 数据表
- BuiltinMindMapGenerator:从报告/残片/应用场景规则生成标准导图
- MindMapAiClient 接口 + RemoteAiMindMapClient 预留
- StandardMindMapService:生成/编辑/重新生成/回忆对比
- 对比算法:标题归一化 + Bigram Jaccard 模糊匹配
- ReviewController 新增 6 个端点
- MindMapTreeTool / MindMapNode / CompareResult 工具类
- 完整单元测试(10 个,全部通过)
- 更新 docs/review-module-design.md
This commit is contained in:
2026-07-03 08:53:51 +08:00
parent 5f3f35c53b
commit 32b247526b
34 changed files with 1890 additions and 153 deletions
@@ -3,18 +3,14 @@ package com.guo.learningprogresstracker.service.impl;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.guo.learningprogresstracker.dto.ReviewFeedItem;
import com.guo.learningprogresstracker.dto.request.CreateReviewApplicationRequest;
import com.guo.learningprogresstracker.dto.request.UpsertReviewMindMapRequest;
import com.guo.learningprogresstracker.entity.ReviewApplicationEntity;
import com.guo.learningprogresstracker.entity.ReviewMindMapEntity;
import com.guo.learningprogresstracker.entity.StudyReportFragmentsEntity;
import com.guo.learningprogresstracker.entity.StudyReportsEntity;
import com.guo.learningprogresstracker.entity.StudySessionsEntity;
import com.guo.learningprogresstracker.entity.TaskEntity;
import com.guo.learningprogresstracker.enums.ReviewApplicationStatusEnum;
import com.guo.learningprogresstracker.enums.ReviewMindMapFileFormatEnum;
import com.guo.learningprogresstracker.enums.ReviewMindMapParseStatusEnum;
import com.guo.learningprogresstracker.mapper.ReviewApplicationMapper;
import com.guo.learningprogresstracker.mapper.ReviewMindMapMapper;
import com.guo.learningprogresstracker.mapper.StudyReportFragmentsMapper;
import com.guo.learningprogresstracker.mapper.StudyReportsMapper;
@@ -50,7 +46,6 @@ class ReviewServiceImplTest {
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), StudyReportFragmentsEntity.class);
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), StudySessionsEntity.class);
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), TaskEntity.class);
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), ReviewApplicationEntity.class);
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), ReviewMindMapEntity.class);
}
@@ -69,9 +64,6 @@ class ReviewServiceImplTest {
@Mock
private TasksMapper tasksMapper;
@Mock
private ReviewApplicationMapper reviewApplicationMapper;
@Mock
private ReviewMindMapMapper reviewMindMapMapper;
@@ -109,27 +101,6 @@ class ReviewServiceImplTest {
assertEquals("Task", items.get(0).getTaskName());
}
@Test
void createApplication_shouldUseDefaultStatusWhenStatusInvalid() throws Exception {
when(tasksMapper.exists(any())).thenReturn(true);
when(reviewApplicationMapper.insert(any())).thenAnswer(invocation -> {
ReviewApplicationEntity entity = invocation.getArgument(0);
entity.setId(7);
return 1;
});
CreateReviewApplicationRequest request = new CreateReviewApplicationRequest();
request.setTaskNum("T1");
request.setTitle("Build a demo");
request.setStatus("invalid");
ReviewApplicationEntity entity = reviewService.createApplication(request);
assertEquals(7, entity.getId());
assertEquals(ReviewApplicationStatusEnum.TODO.getCode(), entity.getStatus());
verify(reviewApplicationMapper).insert(any(ReviewApplicationEntity.class));
}
@Test
void upsertMindMap_shouldCreateWhenMissing() throws Exception {
when(tasksMapper.exists(any())).thenReturn(true);