diff --git a/src/utils/download.ts b/src/utils/download.ts index 1d07484b..5bbfb9fe 100644 --- a/src/utils/download.ts +++ b/src/utils/download.ts @@ -34,16 +34,31 @@ const download = { download0(data, fileName, 'text/markdown') }, // 下载图片(允许跨域) - image: (url: string) => { + image: ({ + url, + canvasWidth, + canvasHeight, + drawWithImageSize = true + }: { + url: string + canvasWidth?: number // 指定画布宽度 + canvasHeight?: number // 指定画布高度 + drawWithImageSize?: boolean // 将图片绘制在画布上时带上图片的宽高值, 默认是要带上的 + }) => { const image = new Image() - image.setAttribute('crossOrigin', 'anonymous') + // image.setAttribute('crossOrigin', 'anonymous') image.src = url image.onload = () => { const canvas = document.createElement('canvas') - canvas.width = image.width - canvas.height = image.height - const ctx = canvas.getContext('2d') as CanvasDrawImage - ctx.drawImage(image, 0, 0, image.width, image.height) + canvas.width = canvasWidth || image.width + canvas.height = canvasHeight || image.height + const ctx = canvas.getContext('2d') as CanvasRenderingContext2D + ctx?.clearRect(0, 0, canvas.width, canvas.height) + if (drawWithImageSize) { + ctx.drawImage(image, 0, 0, image.width, image.height) + } else { + ctx.drawImage(image, 0, 0) + } const url = canvas.toDataURL('image/png') const a = document.createElement('a') a.href = url diff --git a/src/views/ai/image/index/components/ImageList.vue b/src/views/ai/image/index/components/ImageList.vue index 9ffde77e..ced006f0 100644 --- a/src/views/ai/image/index/components/ImageList.vue +++ b/src/views/ai/image/index/components/ImageList.vue @@ -150,7 +150,7 @@ const handleImageButtonClick = async (type: string, imageDetail: ImageVO) => { } // 下载 if (type === 'download') { - await download.image(imageDetail.picUrl) + await download.image({ url: imageDetail.picUrl }) return } // 重新生成 diff --git a/src/views/ai/mindmap/index/components/Right.vue b/src/views/ai/mindmap/index/components/Right.vue index 0550650d..24ed77cc 100644 --- a/src/views/ai/mindmap/index/components/Right.vue +++ b/src/views/ai/mindmap/index/components/Right.vue @@ -19,7 +19,7 @@
-
+
@@ -32,20 +32,20 @@ import { Markmap } from 'markmap-view' import { Transformer } from 'markmap-lib' import { Toolbar } from 'markmap-toolbar' import markdownit from 'markdown-it' +import download from '@/utils/download' const md = markdownit() const message = useMessage() // 消息弹窗 -// TODO @hhero:mindmap 改成 mindMap 更精准哈 const props = defineProps<{ - mindmapResult: string // 生成结果 TODO @hhero 改成 generatedContent 会不会好点 + generatedContent: string // 生成结果 isEnd: boolean // 是否结束 isGenerating: boolean // 是否正在生成 isStart: boolean // 开始状态,开始时需要清除 html }>() const contentRef = ref() // 右侧出来header以下的区域 const mdContainerRef = ref() // markdown 的容器,用来滚动到底下的 -const mindmapRef = ref() // 思维导图的容器 +const mindMapRef = ref() // 思维导图的容器 const svgRef = ref() // 思维导图的渲染 svg const toolBarRef = ref() // 思维导图右下角的工具栏,缩放等 const html = ref('') // 生成过程中的文本 @@ -66,15 +66,16 @@ onMounted(() => { } }) -watch(props, ({ mindmapResult, isGenerating, isEnd, isStart }) => { +watch(props, ({ generatedContent, isGenerating, isEnd, isStart }) => { // 开始生成的时候清空一下 markdown 的内容 if (isStart) { html.value = '' } // 生成内容的时候使用 markdown 来渲染 if (isGenerating) { - html.value = md.render(mindmapResult) + html.value = md.render(generatedContent) } + // 生成结束时更新思维导图 if (isEnd) { update() } @@ -83,7 +84,7 @@ watch(props, ({ mindmapResult, isGenerating, isEnd, isStart }) => { /** 更新思维导图的展示 */ const update = () => { try { - const { root } = transformer.transform(processContent(props.mindmapResult)) + const { root } = transformer.transform(processContent(props.generatedContent)) markMap?.setData(root) markMap?.fit() } catch (e) { @@ -106,31 +107,19 @@ const processContent = (text: string) => { } /** 下载图片 */ -// TODO @hhhero:可以抽到 download 这个里面,src/utils/download.ts 么?复用 image 方法? // download SVG to png file const downloadImage = () => { - const svgElement = mindmapRef.value + const svgElement = mindMapRef.value // 将 SVG 渲染到图片对象 const serializer = new XMLSerializer() - const source = - '\r\n' + serializer.serializeToString(svgRef.value!) - const image = new Image() - image.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(source) - - // 将图片对象渲染 - const canvas = document.createElement('canvas') - canvas.width = svgElement?.offsetWidth || 0 - canvas.height = svgElement?.offsetHeight || 0 - let context = canvas.getContext('2d') - context?.clearRect(0, 0, canvas.width, canvas.height) - - image.onload = function () { - context?.drawImage(image, 0, 0) - const a = document.createElement('a') - a.download = 'mindmap.png' - a.href = canvas.toDataURL(`image/png`) - a.click() - } + const source = `\r\n${serializer.serializeToString(svgRef.value!)}` + const base64Url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(source)}` + download.image({ + url: base64Url, + canvasWidth: svgElement?.offsetWidth, + canvasHeight: svgElement?.offsetHeight, + drawWithImageSize: false + }) } defineExpose({ diff --git a/src/views/ai/mindmap/index/index.vue b/src/views/ai/mindmap/index/index.vue index bae7408f..d7403ea2 100644 --- a/src/views/ai/mindmap/index/index.vue +++ b/src/views/ai/mindmap/index/index.vue @@ -10,7 +10,7 @@ >() // 左边组件 const rightRef = ref>() // 右边组件 @@ -41,7 +41,7 @@ const rightRef = ref>() // 右边组件 /** 使用已有内容直接生成 **/ const directGenerate = (existPrompt: string) => { isEnd.value = false // 先设置为false再设置为true,让子组建的watch能够监听到 - mindmapResult.value = existPrompt + generatedContent.value = existPrompt isEnd.value = true } @@ -58,7 +58,7 @@ const submit = (data: AiMindMapGenerateReqVO) => { isStart.value = true isEnd.value = false ctrl.value = new AbortController() // 请求控制赋值 - mindmapResult.value = '' // 清空生成数据 + generatedContent.value = '' // 清空生成数据 AiMindMapApi.generateMindMap({ data, onMessage: async (res) => { @@ -68,13 +68,13 @@ const submit = (data: AiMindMapGenerateReqVO) => { stopStream() return } - mindmapResult.value = mindmapResult.value + data + generatedContent.value = generatedContent.value + data await nextTick() rightRef.value?.scrollBottom() }, onClose() { isEnd.value = true - leftRef.value?.setGeneratedContent(mindmapResult.value) + leftRef.value?.setGeneratedContent(generatedContent.value) stopStream() }, onError(err) { @@ -87,6 +87,6 @@ const submit = (data: AiMindMapGenerateReqVO) => { /** 初始化 */ onMounted(() => { - mindmapResult.value = MindMapContentExample + generatedContent.value = MindMapContentExample })