From f174e7d73718f48c002ba8d218942a3043ef5d46 Mon Sep 17 00:00:00 2001 From: thzxx Date: Tue, 7 Apr 2026 01:36:19 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=81=8A=E5=A4=A9=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E6=94=B9=E7=94=A8=E5=8E=9F=E7=94=9F=E4=BF=9D=E5=AD=98=E5=AF=B9?= =?UTF-8?q?=E8=AF=9D=E6=A1=86=EF=BC=8C=E6=B8=85=E7=90=86=20downloadFile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - exportAsMarkdown/Html/Txt 全部改用 dialog.saveFile + fs.writeFile - 删除 utils.ts 中的 downloadFile 函数(不再使用) - 两处 a.download 保留为 fallback(bridge 不可用时降级) --- src/renderer/components/chat-area.ts | 37 ++++++++++++++++++++++------ src/renderer/utils/utils.ts | 11 --------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/renderer/components/chat-area.ts b/src/renderer/components/chat-area.ts index 46fef38..30ed2aa 100644 --- a/src/renderer/components/chat-area.ts +++ b/src/renderer/components/chat-area.ts @@ -4,7 +4,7 @@ import { state, KEYS } from '../state/state.js'; import { marked } from '../utils/marked-config.js'; -import { escapeHtml, formatTime, downloadFile } from '../utils/utils.js'; +import { escapeHtml, formatTime } from '../utils/utils.js'; import type { ChatSession, ChatMessage, ToolCallRecord } from '../types.js'; function getFileIcon(filename: string): string { @@ -385,7 +385,30 @@ export function enableAutoScroll(): void { // ── 导出功能 ── -export function exportAsMarkdown(session: ChatSession): void { +async function nativeSaveFile(defaultName: string, content: string): Promise { + const bridge = (window as any).metonaDesktop; + if (bridge) { + const ext = defaultName.split('.').pop() || 'txt'; + const filePath = await bridge.dialog.saveFile({ + defaultPath: defaultName, + filters: [{ name: ext.toUpperCase(), extensions: [ext] }] + }); + if (!filePath) return; + const result = await bridge.fs.writeFile(filePath, content, 'utf-8'); + if (!result.success) { + console.error('[ChatArea] 导出失败:', result.error); + } + } else { + // 回退 + const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); + const a = document.createElement('a'); + a.href = URL.createObjectURL(blob); + a.download = defaultName; + a.click(); + } +} + +export async function exportAsMarkdown(session: ChatSession): Promise { let md = `# ${session.title}\n\n**模型:** ${session.model} \n**时间:** ${formatTime(session.createdAt)}\n\n---\n\n`; session.messages.forEach(m => { const role = m.role === 'user' ? '👤 用户' : '🤖 AI'; @@ -395,10 +418,10 @@ export function exportAsMarkdown(session: ChatSession): void { } if (m.think) md += `> **思考:** ${m.think}\n\n`; }); - downloadFile(`${session.title}.md`, md, 'text/markdown'); + await nativeSaveFile(`${session.title}.md`, md); } -export function exportAsHtml(session: ChatSession): void { +export async function exportAsHtml(session: ChatSession): Promise { let html = `${escapeHtml(session.title)} ${m.role === 'user' ? '👤 用户' : '🤖 AI'}
${(m.content || '').replace(/\n/g, '
')}`; }); html += ''; - downloadFile(`${session.title}.html`, html, 'text/html'); + await nativeSaveFile(`${session.title}.html`, html); } -export function exportAsTxt(session: ChatSession): void { +export async function exportAsTxt(session: ChatSession): Promise { let txt = `${session.title}\n模型: ${session.model}\n时间: ${formatTime(session.createdAt)}\n${'='.repeat(50)}\n\n`; session.messages.forEach(m => { txt += `[${m.role === 'user' ? '用户' : 'AI'}]\n${m.content || ''}\n\n`; }); - downloadFile(`${session.title}.txt`, txt, 'text/plain'); + await nativeSaveFile(`${session.title}.txt`, txt); } diff --git a/src/renderer/utils/utils.ts b/src/renderer/utils/utils.ts index b7637f0..09114ff 100644 --- a/src/renderer/utils/utils.ts +++ b/src/renderer/utils/utils.ts @@ -48,17 +48,6 @@ export function escapeHtml(str: string): string { return String(str).replace(/[&<>"']/g, (c) => map[c]); } -/** 下载文件 */ -export function downloadFile(filename: string, content: string, type: string): void { - const blob = new Blob([content], { type: type + ';charset=utf-8' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = filename; - a.click(); - URL.revokeObjectURL(url); -} - /** 根据文件名检测语言标识(用于 Markdown 代码块) */ export function detectLanguage(filename: string): string { const ext = filename.split('.').pop()?.toLowerCase() || '';