feat: 模板切换重置AI对话+Diff间距修复+API密钥DOM安全+模型切换(20260419_2344)
- 切换模板时同步清空 chatMessages/chatInput/aiUploadedImages/aiSelectedFrames - 修复stripHtml双换行导致diff modal原始版本段落间距过大 - API密钥input改为ref非受控组件, DOM中不再出现value=sk-xxx属性 - 默认模型名改为 moonshot-v1-32k-vision-preview
This commit is contained in:
98
工程分析/20260419_2344/功能变更实现方案文档.md
Normal file
98
工程分析/20260419_2344/功能变更实现方案文档.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# 功能变更实现方案文档(20260419_2344)
|
||||
|
||||
## 实现方案 A:切换模板时重置 AI 对话
|
||||
|
||||
### 变更点
|
||||
`ReportEditor.tsx` line 1240-1251(模板应用 useEffect 中)。
|
||||
|
||||
### 具体实现
|
||||
在 `setCapturedFrames([])` 之后、`updatePageHeight()` 之前,添加:
|
||||
```tsx
|
||||
setChatMessages([]);
|
||||
setChatInput('');
|
||||
setAiUploadedImages([]);
|
||||
setAiSelectedFrames([]);
|
||||
stateRef.current = {
|
||||
...stateRef.current,
|
||||
chatMessages: [],
|
||||
chatInput: '',
|
||||
videos: [],
|
||||
capturedFrames: []
|
||||
};
|
||||
```
|
||||
|
||||
同时更新 `stateRef.current`,确保草稿保存时不会残留旧 AI 数据。
|
||||
|
||||
---
|
||||
|
||||
## 实现方案 B:修复 diff modal 段落间距
|
||||
|
||||
### 变更点
|
||||
`ReportEditor.tsx` line 835-838 的 `stripHtml` 函数。
|
||||
|
||||
### 具体实现
|
||||
从:
|
||||
```ts
|
||||
tmp.innerHTML = html.replace(/<\/p>/gi, '</p>\n').replace(/<br\s*\/?>/gi, '\n');
|
||||
```
|
||||
|
||||
改为:
|
||||
```ts
|
||||
tmp.innerHTML = html.replace(/<br\s*\/?>/gi, '\n');
|
||||
```
|
||||
|
||||
`innerText` 本身会在块级 `<p>` 元素之间自动插入换行,无需手动添加。去掉手动插入后,段落间距恢复正常。
|
||||
|
||||
---
|
||||
|
||||
## 实现方案 C:API 密钥 DOM 暴露修复
|
||||
|
||||
### 变更点
|
||||
`src/pages/SystemSettings.tsx` line 362-377 的 API Key input。
|
||||
|
||||
### 具体实现
|
||||
1. 导入 `useRef`
|
||||
2. 创建 `apiKeyInputRef = useRef<HTMLInputElement>(null)`
|
||||
3. 使用 `useEffect` 在 apiKey 变化时通过 ref 设置 DOM value:
|
||||
```tsx
|
||||
const apiKeyInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (apiKeyInputRef.current) {
|
||||
const targetValue = settings.aiProviders[settings.activeAiProvider]?.apiKey || '';
|
||||
if (apiKeyInputRef.current.value !== targetValue) {
|
||||
apiKeyInputRef.current.value = targetValue;
|
||||
}
|
||||
}
|
||||
}, [settings.aiProviders[settings.activeAiProvider]?.apiKey]);
|
||||
```
|
||||
4. input 标签移除 `value` prop:
|
||||
```tsx
|
||||
<input
|
||||
ref={apiKeyInputRef}
|
||||
type="password"
|
||||
onChange={...}
|
||||
onCopy={(e) => e.preventDefault()}
|
||||
onCut={(e) => e.preventDefault()}
|
||||
placeholder="sk-xxxxxxxxxxxxxxxx"
|
||||
className="input-minimal"
|
||||
/>
|
||||
```
|
||||
|
||||
DOM 中不再出现 `value="sk-..."` HTML 属性。
|
||||
|
||||
---
|
||||
|
||||
## 实现方案 D:默认模型名切换
|
||||
|
||||
### 变更点
|
||||
- `src/types.ts` line 92:`modelName: 'moonshot-v1-32k-vision-preview'`
|
||||
- `src/pages/SystemSettings.tsx` migration fallback line 41:同步修改
|
||||
- `src/pages/ReportEditor.tsx` fallback line 901:同步修改
|
||||
|
||||
---
|
||||
|
||||
## 依赖与兼容性
|
||||
- 无新增 npm 依赖
|
||||
- API Key input 改为非受控后,不影响现有 onChange 保存逻辑
|
||||
- stripHtml 修改仅影响 diff modal 渲染,不影响编辑器本身
|
||||
53
工程分析/20260419_2344/功能变更测试文档.md
Normal file
53
工程分析/20260419_2344/功能变更测试文档.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# 功能变更测试文档(20260419_2344)
|
||||
|
||||
## 测试项 1:切换模板时重置 AI 对话
|
||||
|
||||
### 测试场景
|
||||
1. 打开报告编辑器,在 AI 面板发送几条消息,上传几张图片,选择几个视频帧
|
||||
2. 点击顶部模板下拉框,选择另一个模板并确认
|
||||
3. **预期结果**:
|
||||
- 右侧 AI 面板聊天历史完全清空
|
||||
- 输入框为空
|
||||
- 已上传图片和已选视频帧清零
|
||||
- 新模板内容正确加载
|
||||
|
||||
---
|
||||
|
||||
## 测试项 2:Diff Modal 段落间距
|
||||
|
||||
### 测试场景
|
||||
1. 在 AI 可编辑区域(如"手术步骤")发送修改请求
|
||||
2. AI 返回修改内容后,查看 diff 弹窗
|
||||
3. **预期结果**:
|
||||
- 左侧"原始版本"段落间距与右侧"AI 提议版本"一致
|
||||
- 段落之间没有多余的大段空白
|
||||
- 删除/添加的高亮标记正常显示
|
||||
|
||||
---
|
||||
|
||||
## 测试项 3:API 密钥 DOM 安全
|
||||
|
||||
### 测试场景
|
||||
1. 进入系统设置 → AI 接口集成
|
||||
2. 打开浏览器 DevTools → Elements 面板
|
||||
3. 找到 API 密钥的 `<input>` 元素
|
||||
4. **预期结果**:
|
||||
- `<input>` 标签中不存在 `value="sk-..."` 属性
|
||||
- 页面上显示密码圆点(正常视觉)
|
||||
- 输入新密钥、切换 provider 后功能正常
|
||||
|
||||
---
|
||||
|
||||
## 测试项 4:默认模型名
|
||||
|
||||
### 测试场景
|
||||
1. 清除 localStorage 或以新用户登录
|
||||
2. 进入系统设置 → AI 接口集成
|
||||
3. **预期结果**:模型名称默认为 `moonshot-v1-32k-vision-preview`
|
||||
|
||||
---
|
||||
|
||||
## 回归测试
|
||||
- `tsc --noEmit` 零错误
|
||||
- `npm run build` 构建成功
|
||||
- 预览服务器正常启动并可访问
|
||||
58
工程分析/20260419_2344/功能变更需求文档.md
Normal file
58
工程分析/20260419_2344/功能变更需求文档.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# 功能变更需求文档(20260419_2344)
|
||||
|
||||
## 需求 1:切换模板时重置 AI 对话内容
|
||||
|
||||
### 问题背景
|
||||
当前在顶部下拉框切换模板时,代码只替换了编辑器内容和 reportData,但右侧 AI 聊天面板中的历史对话(chatMessages)和输入框内容(chatInput)仍然残留,与新模板不匹配。
|
||||
|
||||
### 需求描述
|
||||
在 `ReportEditor.tsx` 模板切换的 `useEffect` 中,同步清空 AI 相关状态:
|
||||
- `setChatMessages([])`
|
||||
- `setChatInput('')`
|
||||
- `setAiUploadedImages([])`
|
||||
- `setAiSelectedFrames([])`
|
||||
|
||||
---
|
||||
|
||||
## 需求 2:修复"AI 修改确认"弹窗原始版本段落间距过大
|
||||
|
||||
### 问题背景
|
||||
Diff 弹窗左侧"原始版本"中,段落之间的间距明显过大(截图显示有大段空白),而右侧"AI 提议版本"间距正常。
|
||||
|
||||
### 根因分析
|
||||
`stripHtml` 函数中手动在每个 `</p>` 后插入 `\n`:
|
||||
```ts
|
||||
tmp.innerHTML = html.replace(/<\/p>/gi, '</p>\n').replace(/<br\s*\/?>/gi, '\n');
|
||||
```
|
||||
而浏览器 `innerText` 本身就会在块级 `<p>` 元素之间自动插入换行。两者叠加导致双换行 → `computeDiffHtml` 将 `\n` 转为 `<br>` → 左侧显示双 `<br>` 间距。
|
||||
|
||||
### 需求描述
|
||||
移除 `stripHtml` 中 `</p>\n` 的手动插入,仅保留 `<br>` 转 `\n` 的逻辑,让 `innerText` 自然处理段落间距。
|
||||
|
||||
---
|
||||
|
||||
## 需求 3:修复 API 密钥在 DOM 源码中暴露
|
||||
|
||||
### 问题背景
|
||||
即使 `type="password"`,浏览器的 Elements 面板中仍可直接看到 `<input value="sk-2IAFn8ORoSdUcCxYX6DmXJWbH7BxftSSA8kN88mD1KUDTmkv">` 的完整明文。
|
||||
|
||||
### 需求描述
|
||||
将 API Key 输入框从 React 受控组件(`value={...}`)改为 ref 控制的非受控组件:
|
||||
- JSX 中不写 `value` / `defaultValue` prop
|
||||
- 通过 `useEffect` + `useRef` 在 JavaScript 层面设置 DOM 的 `value` property(非 HTML attribute)
|
||||
- 当 provider 切换或 apiKey 变化时,ref 同步更新 input 值
|
||||
- 添加安全检查:仅当 ref 当前值与目标值不同时才设置,避免覆盖用户正在输入的字符
|
||||
|
||||
---
|
||||
|
||||
## 需求 4:默认模型名改为 moonshot-v1-32k-vision-preview
|
||||
|
||||
### 需求描述
|
||||
将 Kimi 默认模型从 `moonshot-v1-auto` 改为 `moonshot-v1-32k-vision-preview`,支持视觉输入。
|
||||
|
||||
---
|
||||
|
||||
## 影响范围
|
||||
- `src/pages/ReportEditor.tsx`
|
||||
- `src/pages/SystemSettings.tsx`
|
||||
- `src/types.ts`
|
||||
Reference in New Issue
Block a user