2026-04-19-03-03-55 修复AI撰写体验:API endpoint斜杠净化、模型列表下拉栏、聊天记录持久化存储
This commit is contained in:
@@ -73,6 +73,10 @@ export default function ReportEditor() {
|
||||
const [isEditingPrompts, setIsEditingPrompts] = useState(false);
|
||||
const [diffModal, setDiffModal] = useState<{isOpen: boolean, originalHtml: string, newHtml: string, targetId: string} | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
stateRef.current.chatMessages = chatMessages;
|
||||
}, [chatMessages]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!editorRef.current) return;
|
||||
const allFields = editorRef.current.querySelectorAll('.field-value');
|
||||
@@ -118,7 +122,7 @@ export default function ReportEditor() {
|
||||
const videoInputRef = useRef<HTMLInputElement>(null);
|
||||
const contentLoadedRef = useRef(false);
|
||||
const contentRef = useRef('');
|
||||
const stateRef = useRef({ reportData, videos, capturedFrames, activeTab, loadedTemplateId });
|
||||
const stateRef = useRef({ reportData, videos, capturedFrames, activeTab, loadedTemplateId, chatMessages });
|
||||
|
||||
const draftKey = currentUser ? `reportEditorDraft_${currentUser.username}` : '';
|
||||
|
||||
@@ -143,7 +147,8 @@ export default function ReportEditor() {
|
||||
videos: stateRef.current.videos,
|
||||
capturedFrames: stateRef.current.capturedFrames,
|
||||
activeTab: stateRef.current.activeTab,
|
||||
loadedTemplateId: stateRef.current.loadedTemplateId
|
||||
loadedTemplateId: stateRef.current.loadedTemplateId,
|
||||
chatMessages: stateRef.current.chatMessages
|
||||
});
|
||||
}
|
||||
}, [reportId]);
|
||||
@@ -187,12 +192,14 @@ export default function ReportEditor() {
|
||||
setCapturedFrames(draft.capturedFrames.sort((a: CapturedFrame, b: CapturedFrame) => a.time - b.time));
|
||||
}
|
||||
if (draft.activeTab) setActiveTab(draft.activeTab);
|
||||
if (draft.chatMessages) setChatMessages(draft.chatMessages);
|
||||
stateRef.current = {
|
||||
...stateRef.current,
|
||||
reportData: draft.reportData,
|
||||
videos: draft.videos,
|
||||
capturedFrames: draft.capturedFrames,
|
||||
loadedTemplateId: draft.loadedTemplateId || ''
|
||||
loadedTemplateId: draft.loadedTemplateId || '',
|
||||
chatMessages: draft.chatMessages || []
|
||||
};
|
||||
if (editorRef.current && typeof draft.content === 'string' && draft.content.trim().length > 0) {
|
||||
editorRef.current.innerHTML = draft.content;
|
||||
@@ -247,12 +254,14 @@ export default function ReportEditor() {
|
||||
setCapturedFrames(draft.capturedFrames.sort((a: CapturedFrame, b: CapturedFrame) => a.time - b.time));
|
||||
}
|
||||
if (draft.activeTab) setActiveTab(draft.activeTab);
|
||||
if (draft.chatMessages) setChatMessages(draft.chatMessages);
|
||||
stateRef.current = {
|
||||
...stateRef.current,
|
||||
reportData: draft.reportData,
|
||||
videos: draft.videos,
|
||||
capturedFrames: draft.capturedFrames,
|
||||
loadedTemplateId: draft.loadedTemplateId || ''
|
||||
loadedTemplateId: draft.loadedTemplateId || '',
|
||||
chatMessages: draft.chatMessages || []
|
||||
};
|
||||
if (editorRef.current && typeof draft.content === 'string' && draft.content.trim().length > 0) {
|
||||
editorRef.current.innerHTML = draft.content;
|
||||
@@ -851,7 +860,7 @@ export default function ReportEditor() {
|
||||
const settings = storage.get<SystemSettings>('systemSettings', {} as SystemSettings);
|
||||
const provider = settings.aiProviders?.[settings.activeAiProvider || 'kimi'];
|
||||
const apiKey = provider?.apiKey || '';
|
||||
const apiEndpoint = provider?.endpoint || 'https://api.moonshot.cn/v1';
|
||||
const apiEndpoint = (provider?.endpoint || 'https://api.moonshot.cn/v1').replace(/\/+$/, '');
|
||||
const modelName = provider?.modelName || 'kimi-k2-5';
|
||||
if (!apiKey) {
|
||||
setChatMessages(prev => [...prev, { id: Date.now().toString(), role: 'model', content: '【系统提示】尚未配置 AI API Key,请前往系统设置填写。' }]);
|
||||
@@ -1150,7 +1159,8 @@ export default function ReportEditor() {
|
||||
reportData: draft.reportData,
|
||||
videos: draft.videos,
|
||||
capturedFrames: draft.capturedFrames,
|
||||
loadedTemplateId: draft.loadedTemplateId || ''
|
||||
loadedTemplateId: draft.loadedTemplateId || '',
|
||||
chatMessages: draft.chatMessages || []
|
||||
};
|
||||
setTimeout(() => updatePageHeight(), 0);
|
||||
return;
|
||||
|
||||
@@ -20,6 +20,7 @@ export default function SystemSettings() {
|
||||
const [isSaved, setIsSaved] = useState(false);
|
||||
const [pendingFrameCount, setPendingFrameCount] = useState<number | null>(null);
|
||||
const [modeModalOpen, setModeModalOpen] = useState(false);
|
||||
const [availableModels, setAvailableModels] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const user = storage.get<User | null>('currentUser', null);
|
||||
@@ -99,18 +100,27 @@ export default function SystemSettings() {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await fetch(`${provider.endpoint}/models`, {
|
||||
const res = await fetch(`${provider.endpoint.replace(/\/+$/, '')}/models`, {
|
||||
method: 'GET',
|
||||
headers: { 'Authorization': `Bearer ${provider.apiKey}`, 'Content-Type': 'application/json' }
|
||||
});
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
alert(`连接成功!可用模型数: ${data.data?.length || '未知'}`);
|
||||
const models = data.data?.map((m: any) => m.id).filter((id: string) => id) || [];
|
||||
setAvailableModels(models);
|
||||
if (models.length > 0 && !provider.modelName) {
|
||||
const next = { ...settings.aiProviders };
|
||||
next[settings.activeAiProvider] = { ...next[settings.activeAiProvider], modelName: models[0] };
|
||||
setSettings({ ...settings, aiProviders: next });
|
||||
}
|
||||
alert(`连接成功!可用模型数: ${models.length}`);
|
||||
} else {
|
||||
alert(`连接失败: ${res.status} ${res.statusText}`);
|
||||
setAvailableModels([]);
|
||||
}
|
||||
} catch (e: any) {
|
||||
alert(`连接失败: ${e.message}`);
|
||||
setAvailableModels([]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -361,18 +371,34 @@ export default function SystemSettings() {
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<label className="block text-xs font-bold text-text-main uppercase tracking-wider">模型名称 (Model Name)</label>
|
||||
<input
|
||||
type="text"
|
||||
value={settings.aiProviders[settings.activeAiProvider]?.modelName || ''}
|
||||
onChange={(e) => {
|
||||
const next = { ...settings.aiProviders };
|
||||
next[settings.activeAiProvider] = { ...next[settings.activeAiProvider], modelName: e.target.value };
|
||||
setSettings({ ...settings, aiProviders: next });
|
||||
}}
|
||||
placeholder="kimi-k2-5"
|
||||
className="input-minimal"
|
||||
/>
|
||||
<p className="text-[11px] text-text-muted">当前服务商使用的具体模型版本,可随时修改以切换模型。</p>
|
||||
{availableModels.length > 0 ? (
|
||||
<select
|
||||
value={settings.aiProviders[settings.activeAiProvider]?.modelName || ''}
|
||||
onChange={(e) => {
|
||||
const next = { ...settings.aiProviders };
|
||||
next[settings.activeAiProvider] = { ...next[settings.activeAiProvider], modelName: e.target.value };
|
||||
setSettings({ ...settings, aiProviders: next });
|
||||
}}
|
||||
className="input-minimal bg-white"
|
||||
>
|
||||
{availableModels.map(m => (
|
||||
<option key={m} value={m}>{m}</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
<input
|
||||
type="text"
|
||||
value={settings.aiProviders[settings.activeAiProvider]?.modelName || ''}
|
||||
onChange={(e) => {
|
||||
const next = { ...settings.aiProviders };
|
||||
next[settings.activeAiProvider] = { ...next[settings.activeAiProvider], modelName: e.target.value };
|
||||
setSettings({ ...settings, aiProviders: next });
|
||||
}}
|
||||
placeholder="kimi-k2-5"
|
||||
className="input-minimal"
|
||||
/>
|
||||
)}
|
||||
<p className="text-[11px] text-text-muted">{availableModels.length > 0 ? '已从服务商获取可用模型列表' : '点击"测试连接"成功后,此处可下拉选择模型'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user