3.3 KiB
3.3 KiB
实现方案 — 2026-04-16-16-51-00
技术思路
本次修复聚焦于 ReportEditor.tsx 中草稿(draft)恢复与默认模板加载的竞争条件问题。核心思路是:
- 拒绝加载空白草稿:将空字符串(或仅空白字符)的 draft 视为无效,不拦截默认模板加载流程。
- 草稿中携带模板信息:在自动保存 draft 时追加
loadedTemplateId,恢复草稿时同步还原,确保模板选择器显示正确。 - 统一初始化路径:
useEffect与useLayoutEffect中的草稿/默认模板判断逻辑保持一致,避免其中一个抢先设置空白内容。
修改文件清单
| 文件 | 变更类型 | 说明 |
|---|---|---|
src/pages/ReportEditor.tsx |
修改 | 修复草稿恢复条件、保存/恢复 loadedTemplateId、统一空白判断逻辑 |
关键代码变更说明
1. 保存 draft 时追加 loadedTemplateId
在 saveDraftToStorage 回调中,将当前 loadedTemplateId 一并持久化:
storage.set(key, {
content: contentRef.current,
loadedTemplateId, // 新增
draftReportId: reportId || null,
...stateRef.current
});
2. 恢复 draft 时同步恢复 loadedTemplateId(useEffect 初始化逻辑)
新建报告分支(无 reportId)
- 将条件
typeof draft.content === 'string'改为typeof draft.content === 'string' && draft.content.trim().length > 0。 - 若草稿有效,除了回填内容,还要执行
setLoadedTemplateId(draft.loadedTemplateId || '')。
编辑报告分支(有 reportId)
- 同样使用
draft.content.trim().length > 0判断,避免空白草稿覆盖已有报告内容。 - 恢复
loadedTemplateId(虽然在编辑模式下模板选择器通常不显示具体模板名,但保持一致性)。
3. useLayoutEffect 安全网逻辑同步修复
useLayoutEffect(第 611 行起)作为 editor ref 就绪后的二次安全网,其草稿判断条件也要同步修改:
typeof draft.content === 'string'→typeof draft.content === 'string' && draft.content.trim().length > 0- 恢复
loadedTemplateId
4. 默认模板加载时同步设置 loadedTemplateId
在加载 settings.defaultTemplate 对应模板内容时,当前代码已经设置了 setLoadedTemplateId(tpl.id),无需改动。
在兜底使用 defaultReportContent 时,loadedTemplateId 保持为空字符串(显示"无"),这符合语义,因为兜底内容不是用户选中的模板。
风险点及应对策略
| 风险 | 影响 | 应对策略 |
|---|---|---|
| 修改了多处 draft 判断逻辑,可能漏改 | 某些路由切换场景仍出现空白 | 在 useEffect 和 useLayoutEffect 两处共 4 个草稿加载点 统一替换判断条件 |
loadedTemplateId 加入 draft 后,旧 draft 兼容性 |
旧 draft 没有该字段,恢复时值为 undefined,模板选择器短暂显示"无" |
使用 `draft.loadedTemplateId |
| 用户之前确实清空了内容再离开 | 会被视为无效草稿而丢失空白状态 | 这是预期行为:空白内容等价于未开始编辑,应回退到默认模板 |
改动范围总结
- 仅修改
src/pages/ReportEditor.tsx,不触及路由、存储封装或其他页面逻辑。 - 不引入新依赖。