Files
Mdeical_Sur_Report/过往经验/实现方案-2026-04-16-20-46-50.md

106 lines
4.1 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-16-20-46-50
## 根因分析
### 1. LocalStorage 容量超限QuotaExceededError
浏览器对单个域名的 `localStorage` 通常有 **5MB** 的严格容量限制。
当前代码在抽帧时使用了视频的原始分辨率:
```tsx
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const dataUrl = canvas.toDataURL('image/jpeg', 0.9);
```
如果上传的是 1080p 甚至 4K 视频:
- 单张 0.9 质量 JPEG Base64 图片可能达到 **300KB ~ 1MB**
- 自动提取 12 张关键帧 + 手动截图若干张,总数据量可能达到 **5MB ~ 10MB**
- 直接超过 `localStorage` 的 5MB 上限。
### 2. 静默失败
`src/utils/storage.ts` 中的 `set` 方法:
```typescript
set<T>(key: string, value: T): void {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch {
// ignore quota exceeded
}
}
```
当数据量超过 5MB 时,`localStorage.setItem` 抛出 `QuotaExceededError`,但被 `catch` 静默吞掉。
**实际发生的过程:**
1. 用户上传视频 → 此时 `videos` 数组中的 `url``blob:http://...`(短字符串),数据量很小,**保存成功**
2. 系统开始自动抽帧,生成巨大的 Base64 `dataUrl` 数组;
3. 调用 `saveDraftToStorage()` 尝试保存时,`localStorage.setItem` 触发超限报错;
4. 异常被 `catch` 忽略,**draft 没有被更新**(或更新失败);
5. 当用户离开页面再返回时localStorage 中读到的 draft 仍然停留在"仅有视频、没有关键帧"的状态。
这就是为什么:编辑器内容保留了,视频保留了,但**关键帧全部消失**。
## 修改方向
### 方向一:压缩关键帧分辨率与质量(快速修复,推荐优先执行)
关键帧只是用于插入报告的缩略图,通常不需要 4K 原画质。可以:
1. 设定最大宽度(如 800px等比缩放 Canvas
2. 将 JPEG 导出质量从 `0.9` 降到 `0.5 ~ 0.6`
3. 这样单张图片体积可从 500KB 压缩到 30KB~80KB十几张关键帧总计不到 1MB远低于 5MB 限制。
**修改点:**
- `captureFrame()`(手动截图)
- `autoCaptureFrames()`(自动抽帧)
### 方向二:增加存储超限的可见性
`storage.ts` 中不再静默吞掉异常,而是至少输出 `console.error`,甚至可以在 UI 层捕获后提示用户:
"报告数据过大,请降低视频截图质量或删除部分图片。"
### 方向三:迁移到 IndexedDB长期根治
`localStorage` 的 5MB 上限对于包含大量 Base64 图片的医疗报告系统来说迟早会不够用。长期方案是:
- 引入 `localforage``idb-keyval` 等轻量库;
-`storage.ts` 改造为基于 IndexedDB 的异步存储方案(容量可达数百 MB
**注意:** 方向三涉及全项目的 `storage.get/set` 调用点从同步改为异步,改动面较大,适合作为后续迭代项目。
## 建议的实施方案
**本次优先执行方向一 + 方向二**,以最快速度解决关键帧丢失问题,并让用户感知到存储异常:
1.`captureFrame``autoCaptureFrames` 中增加 Canvas 等比缩放逻辑:
```tsx
const MAX_WIDTH = 800;
const scale = Math.min(1, MAX_WIDTH / video.videoWidth);
canvas.width = video.videoWidth * scale;
canvas.height = video.videoHeight * scale;
ctx?.drawImage(video, 0, 0, canvas.width, canvas.height);
const dataUrl = canvas.toDataURL('image/jpeg', 0.6);
```
2. 在 `storage.ts` 中增加超限日志:
```tsx
} catch (e) {
console.error('Storage save failed (possibly quota exceeded):', e);
}
```
## 风险点
| 风险 | 级别 | 应对措施 |
|------|------|---------|
| 压缩后图片清晰度下降 | 低 | 800px 宽度 + 0.6 质量对于报告插入足够清晰 |
| 仍有个别超长视频压缩后接近 5MB | 极低 | 配合方向二的日志提示,便于后续继续优化 |
## 回滚策略
仅调整 Canvas 缩放参数和 JPEG 质量,不涉及数据结构和接口变更。如有异常可直接 revert。
---
**⚠️ 请审核以上方案,确认无误后回复「确认」或提出修改意见,我将进入测试方案编写阶段。**