feat(导图): 防抖/增量生成/移除冗余对比面板
- 重新生成按钮增加 :loading 防重复点击 - 生成进度提示(AI 正在生成中,已等待 X 秒) - 用户编辑后弹窗选择「全量重新生成」或「增量更新」 - 移除独立的对比结果面板,着色结果直接展示在标准导图中
This commit is contained in:
@@ -10,7 +10,7 @@ export interface StandardMindMap {
|
|||||||
content: string;
|
content: string;
|
||||||
outline: string;
|
outline: string;
|
||||||
summary: string;
|
summary: string;
|
||||||
generator: "BUILTIN" | "AI" | "USER";
|
generator: "BUILTIN" | "AI" | "USER" | "USER_MERGE";
|
||||||
generatorVersion?: string;
|
generatorVersion?: string;
|
||||||
sourceReportCount: number;
|
sourceReportCount: number;
|
||||||
sourceFragmentCount: number;
|
sourceFragmentCount: number;
|
||||||
@@ -38,9 +38,9 @@ export const getStandardMindMap = (taskNum: string) => {
|
|||||||
return request.get(`/review/standard-mind-map/${taskNum}`);
|
return request.get(`/review/standard-mind-map/${taskNum}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 强制重新生成标准思维导图 */
|
/** 强制重新生成标准思维导图(全量或增量) */
|
||||||
export const regenerateStandardMindMap = (taskNum: string) => {
|
export const regenerateStandardMindMap = (taskNum: string, mode: "full" | "incremental" = "full") => {
|
||||||
return request.post(`/review/standard-mind-map/${taskNum}/regenerate`);
|
return request.post(`/review/standard-mind-map/${taskNum}/regenerate?mode=${mode}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 用户编辑标准思维导图(大纲文本) */
|
/** 用户编辑标准思维导图(大纲文本) */
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ const standard = ref<StandardMindMap | null>(null);
|
|||||||
const comparing = ref(false);
|
const comparing = ref(false);
|
||||||
const comparingSeconds = ref(0);
|
const comparingSeconds = ref(0);
|
||||||
let comparingTimer: ReturnType<typeof setInterval> | null = null;
|
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 lastResult = ref<any>(null);
|
||||||
const hasCompared = ref(false);
|
const hasCompared = ref(false);
|
||||||
|
|
||||||
@@ -120,22 +124,60 @@ const loadData = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 重新生成
|
// 重新生成(防抖 + 用户编辑时弹窗选模式)
|
||||||
const handleRegenerate = async () => {
|
const handleRegenerate = async () => {
|
||||||
|
// 防抖:正在生成中跳过
|
||||||
|
if (regenerating.value) return;
|
||||||
|
|
||||||
|
let mode: "full" | "incremental" = "full";
|
||||||
|
|
||||||
|
// 如果用户编辑过,弹窗选择生成模式
|
||||||
|
if (standard.value?.generator === "USER" || standard.value?.generator === "USER_MERGE") {
|
||||||
try {
|
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: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
type: "warning",
|
type: "info",
|
||||||
});
|
});
|
||||||
loading.value = true;
|
|
||||||
const res = await regenerateStandardMindMap(taskNum.value);
|
|
||||||
standard.value = res?.data || null;
|
|
||||||
ElMessage.success("标准思维导图已重新生成");
|
|
||||||
} catch {
|
} 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 {
|
} 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" />
|
<MindMapViewer ref="recallViewer" :tree="recallTree" :editable="true" height="60vh" />
|
||||||
</article>
|
</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">
|
<article class="surface-card standard-panel">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h3>📖 标准思维导图</h3>
|
<h3>📖 标准思维导图</h3>
|
||||||
@@ -419,6 +449,7 @@ onMounted(() => {
|
|||||||
v-if="standardExpanded"
|
v-if="standardExpanded"
|
||||||
size="small"
|
size="small"
|
||||||
type="warning"
|
type="warning"
|
||||||
|
:loading="regenerating"
|
||||||
@click="handleRegenerate"
|
@click="handleRegenerate"
|
||||||
>
|
>
|
||||||
重新生成
|
重新生成
|
||||||
@@ -432,6 +463,10 @@ onMounted(() => {
|
|||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div v-if="!standard" class="empty-state">
|
<div v-if="!standard" class="empty-state">
|
||||||
|
|||||||
Reference in New Issue
Block a user