feat(复习): 支持会话维度复习 + 标准导图按会话过滤(后端)
- MindMapNode 新增 sessionNum 字段
- BuiltinMindMapGenerator 生成节点时填充 sessionNum
- MindMapTreeTool.filterBySession() 按会话过滤标准导图
- recallCompare 接受 sessionNum 参数
- ReviewRecallRecordEntity 新增 sessionNum 字段
- Flyway V20260705_1: review_recall_records 加 session_num 列
- 新增 GET /study-sessions/tasks/{taskNum}/sessions 端点
This commit is contained in:
@@ -156,6 +156,61 @@ public class MindMapTreeTool {
|
||||
return 1 + node.getChildren().stream().mapToInt(MindMapTreeTool::maxDepth).max().orElse(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤树:只保留与指定 sessionNum 相关的分支。
|
||||
* - 节点有 sessionNum 且匹配 → 保留
|
||||
* - 节点无 sessionNum(如 APPLICATION 或 AI 生成的节点) → 保留(视为任务级通用知识)
|
||||
* - 有子节点被保留时,父节点也保留
|
||||
*
|
||||
* @param root 树根
|
||||
* @param sessionNum 目标会话编码
|
||||
* @return 过滤后的树,若无相关节点则返回仅含根的空树
|
||||
*/
|
||||
public static MindMapNode filterBySession(MindMapNode root, String sessionNum) {
|
||||
if (root == null || sessionNum == null || sessionNum.isBlank()) return root;
|
||||
MindMapNode filtered = filterRecursive(root, sessionNum);
|
||||
return filtered != null ? filtered : new MindMapNode(root.getTitle() != null ? root.getTitle() : "");
|
||||
}
|
||||
|
||||
private static MindMapNode filterRecursive(MindMapNode node, String sessionNum) {
|
||||
if (node == null) return null;
|
||||
|
||||
// 先过滤子节点
|
||||
List<MindMapNode> keptChildren = new ArrayList<>();
|
||||
if (node.getChildren() != null) {
|
||||
for (MindMapNode child : node.getChildren()) {
|
||||
MindMapNode kept = filterRecursive(child, sessionNum);
|
||||
if (kept != null) {
|
||||
keptChildren.add(kept);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断当前节点是否应该保留:
|
||||
// 1. 有 sessionNum 且匹配 → 保留
|
||||
// 2. 无 sessionNum → 保留(任务级节点,如 APPLICATION 或 AI 生成)
|
||||
// 3. 有子节点保留 → 保留
|
||||
boolean selfMatch = (node.getSessionNum() == null) || sessionNum.equals(node.getSessionNum());
|
||||
if (selfMatch || !keptChildren.isEmpty()) {
|
||||
MindMapNode result = copyNodeShallow(node);
|
||||
result.setChildren(keptChildren.isEmpty() ? node.getChildren() : keptChildren);
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 浅拷贝节点(仅拷贝标量字段,不拷贝 children) */
|
||||
private static MindMapNode copyNodeShallow(MindMapNode node) {
|
||||
MindMapNode copy = new MindMapNode();
|
||||
copy.setTitle(node.getTitle());
|
||||
copy.setNotes(node.getNotes());
|
||||
copy.setSourceType(node.getSourceType());
|
||||
copy.setSourceId(node.getSourceId());
|
||||
copy.setSessionNum(node.getSessionNum());
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** 序列化整棵树为 JSON */
|
||||
public static String toJson(MindMapNode root, ObjectMapper mapper) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user