Files
Mdeical_Sur_Report/工程分析/实现方案-2026-04-19-03-03-55.md

119 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实现方案 — 2026-04-19-03-03-55
## 1. 方案概述
三处修补:① endpoint 尾部斜杠净化防止 404② testApi 捕获模型列表并动态切换 Model Name 输入框为下拉栏;③ 将 `chatMessages` 纳入现有草稿持久化生命周期。
## 2. 详细步骤
### 步骤 1`src/pages/ReportEditor.tsx` — endpoint 净化
**目标文件**`src/pages/ReportEditor.tsx`
**修改内容**
`handleAIGenerate` 中,将:
```ts
const apiEndpoint = provider?.endpoint || 'https://api.moonshot.cn/v1';
```
改为:
```ts
const apiEndpoint = (provider?.endpoint || 'https://api.moonshot.cn/v1').replace(/\/+$/, '');
```
### 步骤 2`src/pages/ReportEditor.tsx` — 聊天记录持久化
**目标文件**`src/pages/ReportEditor.tsx`
**修改内容**
1. `stateRef` 增加 `chatMessages`
```ts
const stateRef = useRef({ reportData, videos, capturedFrames, activeTab, loadedTemplateId, chatMessages });
```
2. `saveDraftToStorage` 增加 `chatMessages`
```ts
storage.set(key, {
content: currentContent,
draftReportId: reportId || null,
reportData: stateRef.current.reportData,
videos: stateRef.current.videos,
capturedFrames: stateRef.current.capturedFrames,
activeTab: stateRef.current.activeTab,
loadedTemplateId: stateRef.current.loadedTemplateId,
chatMessages: stateRef.current.chatMessages
});
```
3. 在 `setChatMessages` 的调用处同步更新 `stateRef.current.chatMessages`
- `handleAIGenerate` 中发送 user 消息时
- `handleAIGenerate` 中收到 model 消息时
- 也可在 `setChatInput('')` 之后统一用 `useEffect` 监听 `chatMessages` 变化来同步 ref
更简单的方案:增加一个 `useEffect` 监听 `chatMessages`
```ts
useEffect(() => {
stateRef.current.chatMessages = chatMessages;
}, [chatMessages]);
```
4. 初始化 `useEffect`draft 恢复分支)中恢复 `chatMessages`
```ts
if (draft.chatMessages) {
setChatMessages(draft.chatMessages);
}
```
### 步骤 3`src/pages/SystemSettings.tsx` — 模型名称下拉栏
**目标文件**`src/pages/SystemSettings.tsx`
**修改内容**
1. 新增 state
```ts
const [availableModels, setAvailableModels] = useState<string[]>([]);
```
2. 修改 `testApi`
```ts
const testApi = async () => {
const provider = settings.aiProviders[settings.activeAiProvider];
if (!provider?.apiKey) { alert('请先输入 API 密钥'); return; }
try {
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();
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([]);
}
};
```
3. Model Name UI 改为条件渲染:
```tsx
{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" ... />
)}
```
## 3. 依赖关系
- 步骤 1 和步骤 2 可并行(都在 ReportEditor.tsx
- 步骤 3 独立SystemSettings.tsx
## 4. 风险预案
- 若 `/models` 接口返回格式非标准 OpenAI 格式(无 `data` 数组),`models` 列表为空,自动回退到 input 输入框
- 若 draft 中没有 `chatMessages`(旧 draft`setChatMessages` 不执行,保持空数组