From ea789cee268bdcd6f0638b5f38ed29d9fa0b82cc Mon Sep 17 00:00:00 2001 From: admin <572701190@qq.com> Date: Mon, 20 Apr 2026 01:01:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=AE=AF=E9=A3=9E=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=80=BC+AI=E5=9B=BE=E7=89=87=E5=90=8C?= =?UTF-8?q?=E6=AD=A5+TemplateManage=E7=A9=BA=E8=A1=8C=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ReportEditor: 讯飞语音读取xfSpeechConfig增加DEFAULT_XF_SPEECH后备,旧用户无需手动保存 - ReportEditor: 切换到AI面板时强制同步编辑器图片到视觉参考上下文 - TemplateManage: saveCurrentTemplate/saveTemplateContent保存前清理空段落和标签间空白 - types.ts: 新增XfSpeechConfig接口和DEFAULT_XF_SPEECH常量 --- src/pages/ReportEditor.tsx | 16 ++++++++++++++-- src/pages/TemplateManage.tsx | 18 ++++++++++++++++-- src/types.ts | 14 +++++++++++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/pages/ReportEditor.tsx b/src/pages/ReportEditor.tsx index 536f995..fd1dbfe 100644 --- a/src/pages/ReportEditor.tsx +++ b/src/pages/ReportEditor.tsx @@ -8,7 +8,7 @@ import { Video, Play, Pause, Plus, X, ChevronLeft, Download, Bot, Mic, MicOff, ImagePlus, Sparkles, Send } from 'lucide-react'; -import { User, Report, Template, CapturedFrame, SystemSettings, FormField, DEFAULT_FORM_FIELDS } from '../types'; +import { User, Report, Template, CapturedFrame, SystemSettings, FormField, DEFAULT_FORM_FIELDS, DEFAULT_XF_SPEECH } from '../types'; import { defaultReportContent } from '../utils/defaultContent'; import { printDocument } from '../utils/print'; import { storage, getDefaultApiKey } from '../utils/storage'; @@ -115,6 +115,18 @@ export default function ReportEditor() { stateRef.current.chatInput = chatInput; }, [chatInput]); + // 切换到 AI 面板时强制同步编辑器中的图片 + useEffect(() => { + if (activeTab !== 'ai' || !editorRef.current) return; + const imgs = Array.from(editorRef.current.querySelectorAll('.image-placeholder.has-image img')) + .map((img, idx) => ({ id: `editor-img-${idx}-${(img as HTMLImageElement).src.slice(-16)}`, src: (img as HTMLImageElement).src })) + .filter(img => img.src); + setEditorImages(prev => { + const same = prev.length === imgs.length && prev.every((p, i) => p.src === imgs[i]?.src); + return same ? prev : imgs; + }); + }, [activeTab]); + useEffect(() => { if (!editorRef.current) return; const allFields = editorRef.current.querySelectorAll('.field-value'); @@ -920,7 +932,7 @@ export default function ReportEditor() { if (xfMediaStreamRef.current) { xfMediaStreamRef.current.getTracks().forEach(t => t.stop()); xfMediaStreamRef.current = null; } return; } - const xfConfig = storage.get('systemSettings', {} as SystemSettings).xfSpeechConfig; + const xfConfig = storage.get('systemSettings', {} as SystemSettings).xfSpeechConfig || DEFAULT_XF_SPEECH; if (!xfConfig?.appId || !xfConfig?.apiKey || !xfConfig?.apiSecret) { alert('请先在系统设置中配置讯飞语音 APPID/APIKey/APISecret'); return; diff --git a/src/pages/TemplateManage.tsx b/src/pages/TemplateManage.tsx index c3448f0..c273301 100644 --- a/src/pages/TemplateManage.tsx +++ b/src/pages/TemplateManage.tsx @@ -419,9 +419,16 @@ export default function TemplateManage() { const saveTemplateContent = () => { if (!currentTemplateId || !editorRef.current) return; + let cleanContent = editorRef.current.innerHTML; + cleanContent = cleanContent.replace(/

\s*\s*<\/p>/gi, ''); + cleanContent = cleanContent.replace(/

<\/p>/gi, ''); + cleanContent = cleanContent.replace(/>(\s+)<'); + if (cleanContent !== editorRef.current.innerHTML) { + editorRef.current.innerHTML = cleanContent; + } const allTemplates = storage.get('templates', []); const updated = allTemplates.map(t => - t.id === currentTemplateId ? { ...t, content: editorRef.current!.innerHTML, updatedAt: new Date().toISOString() } : t + t.id === currentTemplateId ? { ...t, content: cleanContent, updatedAt: new Date().toISOString() } : t ); setTemplates(prevTemplates => prevTemplates.map(t => updated.find(u => u.id === t.id) || t)); storage.set('templates', updated); @@ -603,10 +610,17 @@ export default function TemplateManage() { const saveCurrentTemplate = () => { if (!currentTemplateId || !editorRef.current) return; + let cleanContent = editorRef.current.innerHTML; + cleanContent = cleanContent.replace(/

\s*\s*<\/p>/gi, ''); + cleanContent = cleanContent.replace(/

<\/p>/gi, ''); + cleanContent = cleanContent.replace(/>(\s+)<'); + if (cleanContent !== editorRef.current.innerHTML) { + editorRef.current.innerHTML = cleanContent; + } const allTemplates = storage.get('templates', []); const updated = allTemplates.map(t => { if (t.id === currentTemplateId) { - return { ...t, content: editorRef.current!.innerHTML, updatedAt: new Date().toISOString() }; + return { ...t, content: cleanContent, updatedAt: new Date().toISOString() }; } return t; }); diff --git a/src/types.ts b/src/types.ts index 650a7d1..047f43a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -76,6 +76,18 @@ export interface AiProviderConfig { modelName: string; } +export interface XfSpeechConfig { + appId: string; + apiKey: string; + apiSecret: string; +} + +export const DEFAULT_XF_SPEECH: XfSpeechConfig = { + appId: 'e0fe23e3', + apiKey: '7fd08be316718c2280e85af4fe126306', + apiSecret: 'ZGI5MjAzZDA0YzYwNDhjMWZiNTM2NDE0' +}; + export interface SystemSettings { frameCount: number; framePositions: number[]; @@ -86,7 +98,7 @@ export interface SystemSettings { autoInsertDelay?: number; activeAiProvider: string; aiProviders: Record; - xfSpeechConfig?: { appId: string; apiKey: string; apiSecret: string }; + xfSpeechConfig?: XfSpeechConfig; } export const DEFAULT_AI_PROVIDERS: Record = {