fix(editor): AI注入后Ctrl+Z失效 + 字体格式统一

- confirmAiInjection改用Range.selectNodeContents + execCommand('insertHTML')保留浏览器撤销栈
- handleAIGenerate中对cleanHtml增加<p>标签内联样式注入:padding 0px、font-family SimSun、font-size 12pt、line-height 1.5
- 确保AI替换后的文字字体与原有文字完全一致
This commit is contained in:
2026-04-19 20:33:43 +08:00
parent b24ba08658
commit 7275906f3c
5 changed files with 208 additions and 1 deletions

View File

@@ -845,3 +845,38 @@ if (aiRegion && targetRegionEl) {
**D. 后续如何避免问题**
- 任何通过 iframe 或独立文档实现的打印/导出功能,都必须在 iframe 的 `<style>` 中独立维护打印样式,不能依赖外部 CSS 文件(因为外部样式不会自动注入 iframe
- 对于 diff 对比类 UI左右两侧容器应显式设置相同的默认字体样式避免依赖内容自带的内联样式造成视觉不一致。
---
## 记录 36AI 注入后 Ctrl+Z 失效 + 字体格式丢失
**A. 具体问题**
1. 点击「确认并写入报告」后Ctrl+Z 无法撤销 AI 的修改。
2. AI 替换后的文字丢失了原有内联样式(宋体 12pt显示为浏览器默认字体。
**B. 产生问题原因**
1. **撤销失效**`confirmAiInjection` 使用 `targetContent.innerHTML = newHtml;` 直接修改 DOM 属性。这种方式完全绕过了浏览器 `contentEditable` 的原生撤销/重做历史栈。
2. **字体丢失**:大模型返回的是纯净的 `<p>` 标签(如 `<p>内容</p>`),没有内联样式。替换后浏览器使用默认字体渲染,与原有 `<p style="font-family: SimSun; font-size: 12pt;">` 不一致。
**C. 解决问题方案**
1. **保留撤销栈**:将 `innerHTML = newHtml` 替换为:
```ts
targetContent.focus();
const sel = window.getSelection();
const range = document.createRange();
range.selectNodeContents(targetContent);
sel?.removeAllRanges();
sel?.addRange(range);
document.execCommand('insertHTML', false, newHtml);
```
`Range.selectNodeContents` 选中区域内所有旧内容,`execCommand('insertHTML')` 让浏览器原生撤销栈记录这次替换。
2. **注入内联样式**:在 `handleAIGenerate` 的 `cleanHtml` 清洗后增加:
```ts
cleanHtml = cleanHtml.replace(/<p>/gi, '<p style="padding: 0px; font-family: SimSun; font-size: 12pt; line-height: 1.5;">');
```
给所有 `<p>` 标签注入标准内联样式,确保替换后字体与原有文字一致。
**D. 后续如何避免问题**
- 在 `contentEditable` 环境中修改内容时,**优先使用 `Range.selectNodeContents` + `execCommand('insertHTML')` 而非直接 `innerHTML` 赋值**,前者能让浏览器原生撤销/重做栈正常工作。
- 当大模型返回的 HTML 缺少必要的内联样式时,应在**前端后处理阶段**统一注入样式,而不是依赖大模型生成完整的样式代码(大模型对样式生成的稳定性较差)。