新增导出功能

This commit is contained in:
liuziting
2026-01-21 20:28:46 +08:00
parent 69803860c3
commit 0d41391407
2 changed files with 44 additions and 20 deletions

View File

@@ -9,5 +9,12 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>
<script type="text/javascript">
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "v4wwefc38i");
</script>
</body> </body>
</html> </html>

View File

@@ -44,7 +44,6 @@ import { VueFlow, useVueFlow, Position, MarkerType, Handle } from '@vue-flow/cor
import { Background, BackgroundVariant } from '@vue-flow/background' import { Background, BackgroundVariant } from '@vue-flow/background'
import { Controls } from '@vue-flow/controls' import { Controls } from '@vue-flow/controls'
import { MiniMap } from '@vue-flow/minimap' import { MiniMap } from '@vue-flow/minimap'
import { toPng } from 'html-to-image'
// 导入 VueFlow 样式 // 导入 VueFlow 样式
import '@vue-flow/core/dist/style.css' import '@vue-flow/core/dist/style.css'
@@ -315,23 +314,42 @@ const resetLayout = () => {
/** /**
* 导出为图片 * 导出为图片
*/ */
const exportImage = async () => { const exportMarkdown = () => {
const el = document.querySelector('.vue-flow') as HTMLElement if (flowNodes.value.length === 0) return
if (!el) return
try { // 找到根节点
const dataUrl = await toPng(el, { const rootNode = flowNodes.value.find(n => n.data.type === 'root')
backgroundColor: '#ffffff', if (!rootNode) return
quality: 1,
pixelRatio: 2 let markdown = `# ${rootNode.data.label}\n\n`
// 递归构建 Markdown 内容
const buildMarkdown = (parentId: string, level: number) => {
const children = flowEdges.value
.filter(e => e.source === parentId)
.map(e => flowNodes.value.find(n => n.id === e.target))
.filter(n => n !== undefined)
children.forEach(child => {
const indent = ' '.repeat(level - 1)
markdown += `${indent}- ${child!.data.label}\n`
if (child!.data.detailedContent) {
const detailIndent = ' '.repeat(level)
markdown += `${detailIndent}> ${child!.data.detailedContent.replace(/\n/g, `\n${detailIndent}> `)}\n`
}
buildMarkdown(child!.id, level + 1)
}) })
const link = document.createElement('a')
link.download = `thinkflow-${Date.now()}.png`
link.href = dataUrl
link.click()
} catch (err) {
console.error('Export failed:', err)
} }
buildMarkdown(rootNode.id, 1)
const blob = new Blob([markdown], { type: 'text/markdown' })
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.download = `thinkflow-${rootNode.data.label}-${Date.now()}.md`
link.href = url
link.click()
URL.revokeObjectURL(url)
} }
/** /**
@@ -647,7 +665,6 @@ const startNewSession = () => {
<!-- 桌面端工具按钮组 --> <!-- 桌面端工具按钮组 -->
<div class="hidden md:flex items-center gap-2"> <div class="hidden md:flex items-center gap-2">
<div class="h-4 w-[1px] bg-slate-100 mx-1 flex-shrink-0"></div>
<!-- 布局控制 --> <!-- 布局控制 -->
<button @click="fitView({ padding: 0.2, duration: 800 })" class="toolbar-btn text-blue-500 hover:bg-blue-50 border-blue-100 flex-shrink-0" :title="t('nav.fit')"> <button @click="fitView({ padding: 0.2, duration: 800 })" class="toolbar-btn text-blue-500 hover:bg-blue-50 border-blue-100 flex-shrink-0" :title="t('nav.fit')">
@@ -703,8 +720,8 @@ const startNewSession = () => {
<div class="h-4 w-[1px] bg-slate-100 mx-1 flex-shrink-0"></div> <div class="h-4 w-[1px] bg-slate-100 mx-1 flex-shrink-0"></div>
<!-- 导出图片 --> <!-- 导出选项 -->
<button @click="exportImage" class="toolbar-btn text-emerald-600 hover:bg-emerald-50 border-emerald-100 flex-shrink-0"> <button @click="exportMarkdown" class="toolbar-btn text-indigo-600 hover:bg-indigo-50 border-indigo-100 flex-shrink-0" :title="t('nav.export')">
<Download class="w-3.5 h-3.5 md:w-4 h-4" /> <Download class="w-3.5 h-3.5 md:w-4 h-4" />
<span>{{ t('nav.export') }}</span> <span>{{ t('nav.export') }}</span>
</button> </button>
@@ -804,8 +821,8 @@ const startNewSession = () => {
<span>{{ t('nav.map') }}</span> <span>{{ t('nav.map') }}</span>
</button> </button>
<!-- 导出图片 --> <!-- 导出选项 -->
<button @click="exportImage(); isToolsExpanded = false" class="toolbar-btn text-emerald-600 hover:bg-emerald-50 border-emerald-100"> <button @click="exportMarkdown(); isToolsExpanded = false" class="toolbar-btn text-indigo-600 hover:bg-indigo-50 border-indigo-100" :title="t('nav.export')">
<Download class="w-4 h-4" /> <Download class="w-4 h-4" />
<span>{{ t('nav.export') }}</span> <span>{{ t('nav.export') }}</span>
</button> </button>