feat(导图): 防抖/增量生成/移除冗余对比面板

- 重新生成按钮增加 :loading 防重复点击
- 生成进度提示(AI 正在生成中,已等待 X 秒)
- 用户编辑后弹窗选择「全量重新生成」或「增量更新」
- 移除独立的对比结果面板,着色结果直接展示在标准导图中
This commit is contained in:
2026-07-05 15:18:02 +08:00
parent e5adb4095b
commit 5a5a294f06
2 changed files with 64 additions and 29 deletions
+4 -4
View File
@@ -10,7 +10,7 @@ export interface StandardMindMap {
content: string;
outline: string;
summary: string;
generator: "BUILTIN" | "AI" | "USER";
generator: "BUILTIN" | "AI" | "USER" | "USER_MERGE";
generatorVersion?: string;
sourceReportCount: number;
sourceFragmentCount: number;
@@ -38,9 +38,9 @@ export const getStandardMindMap = (taskNum: string) => {
return request.get(`/review/standard-mind-map/${taskNum}`);
};
/** 强制重新生成标准思维导图 */
export const regenerateStandardMindMap = (taskNum: string) => {
return request.post(`/review/standard-mind-map/${taskNum}/regenerate`);
/** 强制重新生成标准思维导图(全量或增量) */
export const regenerateStandardMindMap = (taskNum: string, mode: "full" | "incremental" = "full") => {
return request.post(`/review/standard-mind-map/${taskNum}/regenerate?mode=${mode}`);
};
/** 用户编辑标准思维导图(大纲文本) */
+57 -22
View File
@@ -23,6 +23,10 @@ const standard = ref<StandardMindMap | null>(null);
const comparing = ref(false);
const comparingSeconds = ref(0);
let comparingTimer: ReturnType<typeof setInterval> | null = null;
const regenerating = ref(false);
const regeneratingSeconds = ref(0);
let regeneratingTimer: ReturnType<typeof setInterval> | null = null;
const lastResult = ref<any>(null);
const hasCompared = ref(false);
@@ -120,22 +124,60 @@ const loadData = async () => {
}
};
// 重新生成
// 重新生成(防抖 + 用户编辑时弹窗选模式)
const handleRegenerate = async () => {
// 防抖:正在生成中跳过
if (regenerating.value) return;
let mode: "full" | "incremental" = "full";
// 如果用户编辑过,弹窗选择生成模式
if (standard.value?.generator === "USER" || standard.value?.generator === "USER_MERGE") {
try {
await ElMessageBox.confirm("重新生成将丢弃用户编辑的内容,确定?", "提示", {
await ElMessageBox.confirm(
"检测到您已编辑过标准思维导图,请选择重新生成方式:",
"重新生成",
{
confirmButtonText: "全量重新生成",
cancelButtonText: "增量更新(保留编辑)",
type: "warning",
distinguishCancelAndClose: true,
}
);
// confirm → 全量(保持 mode = "full"
} catch (e: any) {
if (e === "cancel" || e?.toString()?.includes("cancel")) {
mode = "incremental";
} else {
return; // 点 X 关闭 → 不做操作
}
}
} else {
// 未编辑过的简单确认
try {
await ElMessageBox.confirm("重新生成将从学习数据中重新生成标准思维导图,确定?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
type: "info",
});
loading.value = true;
const res = await regenerateStandardMindMap(taskNum.value);
standard.value = res?.data || null;
ElMessage.success("标准思维导图已重新生成");
} catch {
// 用户取消或接口错误
return;
}
}
// 开始生成
regenerating.value = true;
regeneratingSeconds.value = 0;
regeneratingTimer = setInterval(() => { regeneratingSeconds.value++; }, 1000);
try {
const res = await regenerateStandardMindMap(taskNum.value, mode);
standard.value = res?.data || null;
ElMessage.success(mode === "incremental" ? "标准思维导图已增量更新" : "标准思维导图已重新生成");
} catch (e: any) {
ElMessage.error(e.message || "重新生成失败");
} finally {
loading.value = false;
regenerating.value = false;
if (regeneratingTimer) { clearInterval(regeneratingTimer); regeneratingTimer = null; }
}
};
@@ -395,19 +437,7 @@ onMounted(() => {
<MindMapViewer ref="recallViewer" :tree="recallTree" :editable="true" height="60vh" />
</article>
<!-- 对比结果 -->
<article class="surface-card" v-if="hasCompared && compareTree">
<h3>📊 对比结果</h3>
<p class="panel-hint">绿色=回忆命中红色=遗漏点击带标签的节点可回看原文</p>
<MindMapViewer
:tree="compareTree"
:color-by-compare="true"
height="60vh"
@node-click="goToNodeSource"
/>
</article>
<!-- 标准导图 -->
<!-- 标准导图含对比着色 -->
<article class="surface-card standard-panel">
<div class="panel-header">
<h3>📖 标准思维导图</h3>
@@ -419,6 +449,7 @@ onMounted(() => {
v-if="standardExpanded"
size="small"
type="warning"
:loading="regenerating"
@click="handleRegenerate"
>
重新生成
@@ -432,6 +463,10 @@ onMounted(() => {
编辑
</el-button>
</div>
<p v-if="regenerating" class="ai-waiting" style="margin-top: 4px; width: 100%;">
<template v-if="regeneratingSeconds < 3">正在准备生成</template>
<template v-else>AI 正在生成中已等待 {{ regeneratingSeconds }} 请稍候</template>
</p>
</div>
<div v-if="!standard" class="empty-state">