feat:【antd】【ai】mindmap 的代码优化

This commit is contained in:
YunaiV
2025-10-26 15:16:09 +08:00
parent a35350d055
commit 4d388bdb04
8 changed files with 60 additions and 48 deletions

View File

@@ -3,13 +3,15 @@ import type { AiMindmapApi } from '#/api/ai/mindmap';
import { nextTick, onMounted, ref } from 'vue';
import { alert, Page } from '@vben/common-ui';
import { Page } from '@vben/common-ui';
import { MindMapContentExample } from '@vben/constants';
import { message } from 'ant-design-vue';
import { generateMindMap } from '#/api/ai/mindmap';
import Left from './modules/Left.vue';
import Right from './modules/Right.vue';
import Left from './modules/left.vue';
import Right from './modules/right.vue';
const ctrl = ref<AbortController>(); // 请求控制
const isGenerating = ref(false); // 是否正在生成思维导图
@@ -26,8 +28,9 @@ function directGenerate(existPrompt: string) {
generatedContent.value = existPrompt;
isEnd.value = true;
}
/** 提交生成 */
function submit(data: AiMindmapApi.AiMindMapGenerateReq) {
function handleSubmit(data: AiMindmapApi.AiMindMapGenerateReqVO) {
isGenerating.value = true;
isStart.value = true;
isEnd.value = false;
@@ -38,8 +41,8 @@ function submit(data: AiMindmapApi.AiMindMapGenerateReq) {
onMessage: async (res: any) => {
const { code, data, msg } = JSON.parse(res.data);
if (code !== 0) {
alert(`生成思维导图异常! ${msg}`);
stopStream();
message.error(`生成思维导图异常! ${msg}`);
handleStopStream();
return;
}
generatedContent.value = generatedContent.value + data;
@@ -49,19 +52,20 @@ function submit(data: AiMindmapApi.AiMindMapGenerateReq) {
onClose() {
isEnd.value = true;
leftRef.value?.setGeneratedContent(generatedContent.value);
stopStream();
handleStopStream();
},
onError(err) {
console.error('生成思维导图失败', err);
stopStream();
handleStopStream();
// 需要抛出异常,禁止重试
throw err;
},
ctrl: ctrl.value,
});
}
/** 停止 stream 生成 */
function stopStream() {
function handleStopStream() {
isGenerating.value = false;
isStart.value = false;
ctrl.value?.abort();
@@ -80,7 +84,7 @@ onMounted(() => {
ref="leftRef"
class="mr-4"
:is-generating="isGenerating"
@submit="submit"
@submit="handleSubmit"
@direct-generate="directGenerate"
/>
<Right

View File

@@ -8,7 +8,9 @@ import { Button, Textarea } from 'ant-design-vue';
defineProps<{
isGenerating: boolean;
}>();
const emits = defineEmits(['submit', 'directGenerate']);
const formData = reactive({
prompt: '',
});

View File

@@ -18,6 +18,7 @@ const props = defineProps<{
isGenerating: boolean; //
isStart: boolean; // html
}>();
const md = MarkdownIt();
const contentRef = ref<HTMLDivElement>(); // header
const mdContainerRef = ref<HTMLDivElement>(); // markdown
@@ -30,12 +31,14 @@ let markMap: Markmap | null = null;
const transformer = new Transformer();
let resizeObserver: null | ResizeObserver = null;
const initialized = false;
/** 初始化 */
onMounted(() => {
resizeObserver = new ResizeObserver(() => {
contentAreaHeight.value = contentRef.value?.clientHeight || 0;
//
if (contentAreaHeight.value && !initialized) {
/** 初始化思维导图 */
//
try {
if (!markMap) {
markMap = Markmap.create(svgRef.value!);
@@ -52,11 +55,15 @@ onMounted(() => {
resizeObserver.observe(contentRef.value);
}
});
/** 卸载 */
onBeforeUnmount(() => {
if (resizeObserver && contentRef.value) {
resizeObserver.unobserve(contentRef.value);
}
});
/** 监听 props 变化 */
watch(props, ({ generatedContent, isGenerating, isEnd, isStart }) => {
// markdown
if (isStart) {
@@ -84,6 +91,7 @@ function update() {
console.error(error);
}
}
/** 处理内容 */
function processContent(text: string) {
const arr: string[] = [];
@@ -98,6 +106,7 @@ function processContent(text: string) {
}
return arr.join('\n');
}
/** 下载图片download SVG to png file */
function downloadImage() {
const svgElement = mindMapRef.value;
@@ -112,6 +121,7 @@ function downloadImage() {
drawWithImageSize: false,
});
}
defineExpose({
scrollBottom() {
mdContainerRef.value?.scrollTo(0, mdContainerRef.value?.scrollHeight);
@@ -135,7 +145,6 @@ defineExpose({
</div>
</template>
<div ref="contentRef" class="hide-scroll-bar box-border h-full">
<!--展示 markdown 的容器最终生成的是 html 字符串直接用 v-html 嵌入-->
<div
v-if="isGenerating"
ref="mdContainerRef"
@@ -146,7 +155,6 @@ defineExpose({
v-html="html"
></div>
</div>
<div ref="mindMapRef" class="wh-full">
<svg
ref="svgRef"