fix: 讯飞配置默认值+AI图片同步+TemplateManage空行清理
- ReportEditor: 讯飞语音读取xfSpeechConfig增加DEFAULT_XF_SPEECH后备,旧用户无需手动保存 - ReportEditor: 切换到AI面板时强制同步编辑器图片到视觉参考上下文 - TemplateManage: saveCurrentTemplate/saveTemplateContent保存前清理空段落和标签间空白 - types.ts: 新增XfSpeechConfig接口和DEFAULT_XF_SPEECH常量
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
|||||||
Video, Play, Pause, Plus, X, ChevronLeft, Download,
|
Video, Play, Pause, Plus, X, ChevronLeft, Download,
|
||||||
Bot, Mic, MicOff, ImagePlus, Sparkles, Send
|
Bot, Mic, MicOff, ImagePlus, Sparkles, Send
|
||||||
} from 'lucide-react';
|
} 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 { defaultReportContent } from '../utils/defaultContent';
|
||||||
import { printDocument } from '../utils/print';
|
import { printDocument } from '../utils/print';
|
||||||
import { storage, getDefaultApiKey } from '../utils/storage';
|
import { storage, getDefaultApiKey } from '../utils/storage';
|
||||||
@@ -115,6 +115,18 @@ export default function ReportEditor() {
|
|||||||
stateRef.current.chatInput = chatInput;
|
stateRef.current.chatInput = 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(() => {
|
useEffect(() => {
|
||||||
if (!editorRef.current) return;
|
if (!editorRef.current) return;
|
||||||
const allFields = editorRef.current.querySelectorAll('.field-value');
|
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; }
|
if (xfMediaStreamRef.current) { xfMediaStreamRef.current.getTracks().forEach(t => t.stop()); xfMediaStreamRef.current = null; }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const xfConfig = storage.get<SystemSettings>('systemSettings', {} as SystemSettings).xfSpeechConfig;
|
const xfConfig = storage.get<SystemSettings>('systemSettings', {} as SystemSettings).xfSpeechConfig || DEFAULT_XF_SPEECH;
|
||||||
if (!xfConfig?.appId || !xfConfig?.apiKey || !xfConfig?.apiSecret) {
|
if (!xfConfig?.appId || !xfConfig?.apiKey || !xfConfig?.apiSecret) {
|
||||||
alert('请先在系统设置中配置讯飞语音 APPID/APIKey/APISecret');
|
alert('请先在系统设置中配置讯飞语音 APPID/APIKey/APISecret');
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -419,9 +419,16 @@ export default function TemplateManage() {
|
|||||||
|
|
||||||
const saveTemplateContent = () => {
|
const saveTemplateContent = () => {
|
||||||
if (!currentTemplateId || !editorRef.current) return;
|
if (!currentTemplateId || !editorRef.current) return;
|
||||||
|
let cleanContent = editorRef.current.innerHTML;
|
||||||
|
cleanContent = cleanContent.replace(/<p>\s*<br\s*\/?>\s*<\/p>/gi, '');
|
||||||
|
cleanContent = cleanContent.replace(/<p><\/p>/gi, '');
|
||||||
|
cleanContent = cleanContent.replace(/>(\s+)</g, '><');
|
||||||
|
if (cleanContent !== editorRef.current.innerHTML) {
|
||||||
|
editorRef.current.innerHTML = cleanContent;
|
||||||
|
}
|
||||||
const allTemplates = storage.get<Template[]>('templates', []);
|
const allTemplates = storage.get<Template[]>('templates', []);
|
||||||
const updated = allTemplates.map(t =>
|
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));
|
setTemplates(prevTemplates => prevTemplates.map(t => updated.find(u => u.id === t.id) || t));
|
||||||
storage.set('templates', updated);
|
storage.set('templates', updated);
|
||||||
@@ -603,10 +610,17 @@ export default function TemplateManage() {
|
|||||||
|
|
||||||
const saveCurrentTemplate = () => {
|
const saveCurrentTemplate = () => {
|
||||||
if (!currentTemplateId || !editorRef.current) return;
|
if (!currentTemplateId || !editorRef.current) return;
|
||||||
|
let cleanContent = editorRef.current.innerHTML;
|
||||||
|
cleanContent = cleanContent.replace(/<p>\s*<br\s*\/?>\s*<\/p>/gi, '');
|
||||||
|
cleanContent = cleanContent.replace(/<p><\/p>/gi, '');
|
||||||
|
cleanContent = cleanContent.replace(/>(\s+)</g, '><');
|
||||||
|
if (cleanContent !== editorRef.current.innerHTML) {
|
||||||
|
editorRef.current.innerHTML = cleanContent;
|
||||||
|
}
|
||||||
const allTemplates = storage.get<Template[]>('templates', []);
|
const allTemplates = storage.get<Template[]>('templates', []);
|
||||||
const updated = allTemplates.map(t => {
|
const updated = allTemplates.map(t => {
|
||||||
if (t.id === currentTemplateId) {
|
if (t.id === currentTemplateId) {
|
||||||
return { ...t, content: editorRef.current!.innerHTML, updatedAt: new Date().toISOString() };
|
return { ...t, content: cleanContent, updatedAt: new Date().toISOString() };
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
|
|||||||
14
src/types.ts
14
src/types.ts
@@ -76,6 +76,18 @@ export interface AiProviderConfig {
|
|||||||
modelName: string;
|
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 {
|
export interface SystemSettings {
|
||||||
frameCount: number;
|
frameCount: number;
|
||||||
framePositions: number[];
|
framePositions: number[];
|
||||||
@@ -86,7 +98,7 @@ export interface SystemSettings {
|
|||||||
autoInsertDelay?: number;
|
autoInsertDelay?: number;
|
||||||
activeAiProvider: string;
|
activeAiProvider: string;
|
||||||
aiProviders: Record<string, AiProviderConfig>;
|
aiProviders: Record<string, AiProviderConfig>;
|
||||||
xfSpeechConfig?: { appId: string; apiKey: string; apiSecret: string };
|
xfSpeechConfig?: XfSpeechConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_AI_PROVIDERS: Record<string, AiProviderConfig> = {
|
export const DEFAULT_AI_PROVIDERS: Record<string, AiProviderConfig> = {
|
||||||
|
|||||||
Reference in New Issue
Block a user