fix: 修复节点点击无响应 + 支持对比后返回完整导图重新选择复习范围

- MindMapViewer: mind-elixir v5 的 selectNode(el) 不传第二参数导致 selectNewNode 永不触发,改为 monkey-patch selectNode 捕获节点点击
- MindMapViewer: 根节点加入 nodePathMap,子节点路径补全根标题前缀
- ReviewRecall: 新增 resetComparison(),对比完成后可点击「返回完整导图」清空结果,重新选择节点开始新一轮复习

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cat-win
2026-07-08 22:43:13 +08:00
parent e66bdb79dc
commit 1ea15db504
2 changed files with 55 additions and 9 deletions
+36 -8
View File
@@ -99,11 +99,26 @@ const toElixirNode = (node: MindMapTreeNode, ancestors: string[] = []): any => {
const toElixirData = (tree: MindMapTreeNode): MindElixirData => { const toElixirData = (tree: MindMapTreeNode): MindElixirData => {
nodeCounter = 0; nodeCounter = 0;
const rootTitle = tree.title || "思维导图";
// register root node in path map so clicking it also works
if (props.selectable) {
nodePathMap["root"] = {
title: rootTitle,
path: rootTitle,
childCount: (tree.children || []).reduce(
(sum, c) => sum + 1 + countAllDescendants(c),
0,
),
};
}
return { return {
nodeData: { nodeData: {
id: "root", id: "root",
topic: tree.title || "思维导图", topic: rootTitle,
children: (tree.children || []).map(c => toElixirNode(c)), // pass root title as ancestor so child paths include it (e.g. "根 / 子节点")
children: (tree.children || []).map((c) =>
toElixirNode(c, [rootTitle]),
),
}, },
} as MindElixirData; } as MindElixirData;
}; };
@@ -147,18 +162,31 @@ const render = () => {
}); });
} }
instance.bus.addListener("selectNewNode", (node: any) => { // mind-elixir v5: selectNode(el) is called on every node click, but the
if (props.selectable && node?.id) { // selectNewNode event is never fired (it requires selectNode(el, true),
const info = nodePathMap[node.id]; // which the default click handler never passes). Monkey-patch selectNode
// to hook into node clicks for both selectable and source-navigation modes.
const origSelectNode = instance.selectNode.bind(instance);
instance.selectNode = function (el: any, fireEvent?: boolean) {
origSelectNode(el, fireEvent);
if (!el?.nodeObj) return;
const nodeData = el.nodeObj;
// selectable mode → emit node-select with title/path/childCount
if (props.selectable && nodeData?.id) {
const info = nodePathMap[nodeData.id];
if (info) { if (info) {
emit("node-select", info); emit("node-select", info);
return; return;
} }
} }
if (node?.sourceType && node?.sourceId != null) { // source navigation → emit node-click with sourceType/sourceId
emit("node-click", { sourceType: String(node.sourceType), sourceId: Number(node.sourceId) }); if (nodeData?.sourceType && nodeData?.sourceId != null) {
} emit("node-click", {
sourceType: String(nodeData.sourceType),
sourceId: Number(nodeData.sourceId),
}); });
}
};
}; };
watch( watch(
+19 -1
View File
@@ -223,6 +223,14 @@ const resetRecall = () => {
recallTree.value = buildEmptyRecallTree(); recallTree.value = buildEmptyRecallTree();
}; };
// 返回完整标准导图,重新选择复习范围
const resetComparison = () => {
lastResult.value = null;
hasCompared.value = false;
focusPath.value = "";
recallTree.value = buildEmptyRecallTree();
};
// 编辑标准导图 // 编辑标准导图
const startEditStandard = () => { const startEditStandard = () => {
editOutline.value = standard.value?.outline || ""; editOutline.value = standard.value?.outline || "";
@@ -438,8 +446,18 @@ onMounted(() => {
<!-- 标准导图含对比着色 --> <!-- 标准导图含对比着色 -->
<article class="surface-card standard-panel"> <article class="surface-card standard-panel">
<div class="panel-header"> <div class="panel-header">
<h3>📖 标准思维导图</h3> <h3>
{{ hasCompared ? '📖 标准思维导图(对比结果)' : '📖 标准思维导图' }}
</h3>
<div class="panel-actions"> <div class="panel-actions">
<el-button
v-if="hasCompared"
size="small"
type="success"
@click="resetComparison"
>
返回完整导图
</el-button>
<el-button size="small" @click="standardExpanded = !standardExpanded"> <el-button size="small" @click="standardExpanded = !standardExpanded">
{{ standardExpanded ? "折叠" : "展开" }} {{ standardExpanded ? "折叠" : "展开" }}
</el-button> </el-button>