feat(复习):mind-elixir 思维导图可视化
- MindMapViewer 组件封装 mind-elixir:展示/编辑/对比着色三种形态 - 对比结果以导图呈现:绿=命中、红=遗漏,点击带标签节点回看原文 - 标准导图展开后以导图渲染,编辑改为图上直接操作(Tab/Enter/双击) - 保存时从导图导出缩进大纲,与后端 MindMapTreeTool 格式一致
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
type RecallRecord,
|
||||
} from "@/api/standardMindMap";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import MindMapViewer, { type MindMapTreeNode } from "@/components/MindMapViewer.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -30,11 +31,34 @@ const standardExpanded = ref(false);
|
||||
const editingStandard = ref(false);
|
||||
const editOutline = ref("");
|
||||
const savingStandard = ref(false);
|
||||
const editViewer = ref<InstanceType<typeof MindMapViewer> | null>(null);
|
||||
|
||||
// 回忆历史
|
||||
const historyRecords = ref<RecallRecord[]>([]);
|
||||
const showHistory = ref(false);
|
||||
|
||||
// 解析标准导图 JSON 为树节点
|
||||
const standardTree = computed<MindMapTreeNode | null>(() => {
|
||||
if (!standard.value?.content) return null;
|
||||
try {
|
||||
return JSON.parse(standard.value.content) as MindMapTreeNode;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// 对比结果树(带 MATCHED/MISSED 标注)
|
||||
const compareTree = computed<MindMapTreeNode | null>(() => {
|
||||
return (lastResult.value?.matchedTree as MindMapTreeNode) || null;
|
||||
});
|
||||
|
||||
// 点击着色节点跳转原文
|
||||
const goToNodeSource = (node: { sourceType: string; sourceId: number }) => {
|
||||
if (node.sourceType === "REPORT" || node.sourceType === "FRAGMENT") {
|
||||
router.push(`/review/detail/${node.sourceType.toLowerCase()}/${node.sourceId}`);
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化覆盖率
|
||||
const ratioPercent = computed(() => {
|
||||
if (!lastResult.value?.recallRatio) return "0%";
|
||||
@@ -130,6 +154,17 @@ const saveStandardEdit = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 从导图编辑器导出大纲并保存
|
||||
const saveStandardEditFromViewer = async () => {
|
||||
const outline = editViewer.value?.toOutline() || "";
|
||||
if (!outline.trim()) {
|
||||
ElMessage.warning("导图内容不可为空");
|
||||
return;
|
||||
}
|
||||
editOutline.value = outline;
|
||||
await saveStandardEdit();
|
||||
};
|
||||
|
||||
const cancelStandardEdit = () => {
|
||||
editingStandard.value = false;
|
||||
editOutline.value = "";
|
||||
@@ -297,9 +332,14 @@ onMounted(() => {
|
||||
</div>
|
||||
|
||||
<!-- 对比结果 -->
|
||||
<div v-if="hasCompared && resultText" class="compare-result">
|
||||
<div v-if="hasCompared && compareTree" class="compare-result">
|
||||
<h4>📊 对比结果</h4>
|
||||
<pre class="compare-tree">{{ resultText }}</pre>
|
||||
<p class="panel-hint">绿色=回忆命中,红色=遗漏。点击带标签的节点可回看原文。</p>
|
||||
<MindMapViewer
|
||||
:tree="compareTree"
|
||||
:color-by-compare="true"
|
||||
@node-click="goToNodeSource"
|
||||
/>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@@ -339,12 +379,11 @@ onMounted(() => {
|
||||
</div>
|
||||
|
||||
<div v-else-if="editingStandard" class="edit-area">
|
||||
<p class="panel-hint">编辑大纲文本,保存后标准导图将被更新。</p>
|
||||
<el-input v-model="editOutline" type="textarea" :rows="12" />
|
||||
<p v-if="standard.summary" class="generator-info">{{ standard.summary }}</p>
|
||||
<p class="panel-hint">直接在导图上编辑(Tab 加子节点 / Enter 加同级 / 双击改文字),保存后生效。</p>
|
||||
<MindMapViewer ref="editViewer" :tree="standardTree" :editable="true" />
|
||||
<div class="edit-actions">
|
||||
<el-button @click="cancelStandardEdit">取消</el-button>
|
||||
<el-button type="primary" :loading="savingStandard" @click="saveStandardEdit">
|
||||
<el-button type="primary" :loading="savingStandard" @click="saveStandardEditFromViewer">
|
||||
保存更新
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -355,7 +394,8 @@ onMounted(() => {
|
||||
<span>来源:{{ standard.generator }}</span>
|
||||
<span>参考:{{ standard.sourceReportCount }} 份报告 + {{ standard.sourceFragmentCount }} 份残片</span>
|
||||
</div>
|
||||
<pre class="standard-outline">{{ standard.outline || standard.content }}</pre>
|
||||
<MindMapViewer v-if="standardTree" :tree="standardTree" @node-click="goToNodeSource" />
|
||||
<pre v-else class="standard-outline">{{ standard.outline || standard.content }}</pre>
|
||||
<p v-if="standard.summary" class="generator-info">{{ standard.summary }}</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user