feat:【antd】【ai】mindmap 的代码优化
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -8,7 +8,9 @@ import { Button, Textarea } from 'ant-design-vue';
|
||||
defineProps<{
|
||||
isGenerating: boolean;
|
||||
}>();
|
||||
|
||||
const emits = defineEmits(['submit', 'directGenerate']);
|
||||
|
||||
const formData = reactive({
|
||||
prompt: '',
|
||||
});
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user