- 默认模板: 手术步骤段落包裹进 .ai-region AI可编辑区域 - API密钥: DEFAULT_AI_PROVIDERS.kimi.apiKey 预设默认值, 输入框增加onCopy/onCut防复制, storage.ts增加XOR+Base64透明加密 - 默认模型: kimi modelName改为 moonshot-v1-auto - 抽帧配置: 12个位置改为指定百分比[7.9,9.3,46.2,49.1,63.9,64.8, 68.8,73.7,80.2,85.0,96.3,98.6], 默认模式从uniform改为keep
139 lines
4.6 KiB
Markdown
139 lines
4.6 KiB
Markdown
# 功能变更实现方案文档(20260419_2316)
|
||
|
||
## 实现方案 A:模板手术步骤 AI 区域化
|
||
|
||
### 变更点
|
||
`src/utils/defaultContent.ts` line 54-76。
|
||
|
||
### 具体实现
|
||
将原有的:
|
||
```html
|
||
<p style="..."><strong>手术步骤、术中出现的情况及处理:</strong></p>
|
||
<p>1.患者仰卧位...</p>
|
||
<p>2.腹腔镜探查...</p>
|
||
...
|
||
```
|
||
|
||
替换为:
|
||
```html
|
||
<p style="..."><strong>手术步骤、术中出现的情况及处理:</strong></p>
|
||
<div class="ai-region" data-ai-id="手术步骤" data-ai-title="手术步骤、术中出现的情况及处理" style="border: 1px dashed #3b82f6; padding: 16px 12px 12px; margin: 8px 0; position: relative; min-height: 60px; background: #f8fafc; border-radius: 6px;">
|
||
<div contenteditable="false" style="position: absolute; top: -10px; right: 10px; background: #3b82f6; color: white; font-size: 10px; padding: 2px 8px; border-radius: 12px; z-index: 10; user-select: none;">手术步骤、术中出现的情况及处理-AI可编辑区域</div>
|
||
<div class="ai-content" style="min-height: 20px;">
|
||
<p>1.患者仰卧位...</p>
|
||
<p>2.腹腔镜探查...</p>
|
||
...
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## 实现方案 B:API 密钥安全增强
|
||
|
||
### 变更点 1:默认值预设
|
||
`src/types.ts` line 92:
|
||
```ts
|
||
kimi: { endpoint: 'https://api.moonshot.cn/v1', apiKey: 'sk-2IAFn8ORoSdUcCxYX6DmXJWbH7BxftSSA8kN88mD1KUDTmkv', modelName: 'moonshot-v1-auto' }
|
||
```
|
||
|
||
### 变更点 2:前端防复制
|
||
`src/pages/SystemSettings.tsx` API Key input 添加事件拦截:
|
||
```tsx
|
||
onCopy={(e) => e.preventDefault()}
|
||
onCut={(e) => e.preventDefault()}
|
||
```
|
||
|
||
### 变更点 3:轻度加密存储
|
||
`src/utils/storage.ts` 增加透明加密层:
|
||
- 使用 XOR + Base64 对 `systemSettings` key 的数据进行加解密
|
||
- 加密密钥固定为 `'MedicalReportSys2024'`
|
||
- 完全透明:所有调用方无需改动,`get`/`set` 自动处理
|
||
|
||
```ts
|
||
const CRYPTO_KEY = 'MedicalReportSys2024';
|
||
|
||
function xorEncrypt(text: string, key: string): string {
|
||
let result = '';
|
||
for (let i = 0; i < text.length; i++) {
|
||
result += String.fromCharCode(text.charCodeAt(i) ^ key.charCodeAt(i % key.length));
|
||
}
|
||
return btoa(result);
|
||
}
|
||
|
||
function xorDecrypt(encrypted: string, key: string): string {
|
||
const text = atob(encrypted);
|
||
let result = '';
|
||
for (let i = 0; i < text.length; i++) {
|
||
result += String.fromCharCode(text.charCodeAt(i) ^ key.charCodeAt(i % key.length));
|
||
}
|
||
return result;
|
||
}
|
||
```
|
||
|
||
在 `get` 和 `set` 中:
|
||
```ts
|
||
if (key === 'systemSettings') {
|
||
data = xorEncrypt(JSON.stringify(value), CRYPTO_KEY);
|
||
// 存储时加一个前缀标记以便区分
|
||
}
|
||
```
|
||
|
||
为保持向后兼容(旧数据是明文 JSON),解密时先尝试 `JSON.parse`,如果失败再尝试 XOR 解密:
|
||
```ts
|
||
get<T>(key: string, fallback: T): T {
|
||
try {
|
||
const raw = localStorage.getItem(key);
|
||
if (!raw) return fallback;
|
||
if (key === 'systemSettings') {
|
||
// 先尝试直接 JSON.parse(兼容旧明文数据)
|
||
try {
|
||
return JSON.parse(raw) as T;
|
||
} catch {
|
||
// 旧数据解析失败,尝试解密
|
||
return JSON.parse(xorDecrypt(raw, CRYPTO_KEY)) as T;
|
||
}
|
||
}
|
||
return JSON.parse(raw) as T;
|
||
} catch {
|
||
return fallback;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 实现方案 C:默认模型名切换
|
||
|
||
### 变更点
|
||
- `src/types.ts` line 92:`modelName: 'moonshot-v1-auto'`
|
||
- `src/pages/SystemSettings.tsx` migration fallback line 41:`modelName: 'moonshot-v1-auto'`
|
||
- `src/pages/ReportEditor.tsx` fallback line 901:`modelName = provider?.modelName || 'moonshot-v1-auto'`
|
||
|
||
---
|
||
|
||
## 实现方案 D:抽帧百分比 + 模式默认值
|
||
|
||
### 硬编码数组
|
||
```ts
|
||
const DEFAULT_FRAME_POSITIONS = [7.9, 9.3, 46.2, 49.1, 63.9, 64.8, 68.8, 73.7, 80.2, 85.0, 96.3, 98.6];
|
||
```
|
||
|
||
### 变更点
|
||
| 文件 | 位置 | 变更 |
|
||
|------|------|------|
|
||
| `src/pages/Login.tsx` | `initData()` framePositions | 从均匀计算改为硬编码数组 |
|
||
| `src/pages/Login.tsx` | `initData()` frameMode | `'uniform'` → `'keep'` |
|
||
| `src/pages/SystemSettings.tsx` | `useState` framePositions | `[5,10,...]` → 硬编码数组 |
|
||
| `src/pages/SystemSettings.tsx` | `useState` frameMode | `'uniform'` → `'keep'` |
|
||
| `src/pages/SystemSettings.tsx` | loaded settings fallback | `'uniform'` → `'keep'` |
|
||
| `src/pages/SystemSettings.tsx` | `resetToDefault()` | framePositions + frameMode |
|
||
| `src/pages/ReportEditor.tsx` | fallback framePositions | `[5,10,...]` → 硬编码数组 |
|
||
|
||
---
|
||
|
||
## 依赖与兼容性
|
||
- 无新增 npm 依赖
|
||
- storage 加密保持向后兼容:旧明文数据可正常读取,新写入的数据自动加密
|
||
- 所有变更均为默认值修改,不影响已有用户配置(除非手动重置)
|