# 需求分析 — 2026-04-17-13-32-07 ## 用户反馈 1. **Ctrl+Z 快捷键无法撤销对 `smart-field-wrapper` 的删除**,但点击工具栏的撤销按钮可以正常撤销。 2. **插入 `smart-field-wrapper` 时仍会分成两行**。用户怀疑是原本文本结构的问题,并提供了出现问题的 HTML 片段: ```html

手术日期:

... ``` 用户补充:把字段插到下面的内容中(即上述 HTML 中已有字段的位置)则没有问题。 --- ## 问题 1:Ctrl+Z 快捷键撤销失效 ### 现状 - `TemplateManage.tsx` 已实现了自定义的 `undoStack` / `redoStack` 以及 `handleUndo()` / `handleRedo()`。 - 工具栏的撤销/重做按钮调用的是自定义函数,能够正确恢复 `innerHTML` 历史快照。 - 键盘按下 `Ctrl+Z` 时,浏览器会触发**原生 `undo`**(`document.execCommand('undo')`),它与自定义历史栈完全脱节,因此: - 若原生栈为空(或已耗尽),则没有任何反应; - 若原生栈有记录,可能恢复出意料之外的状态。 ### 根因 - 当前只在编辑器上拦截了 `Backspace` / `Delete` 键(用于防止误删整段),**没有拦截 `Ctrl+Z` / `Ctrl+Y` 快捷键**。 ### 需求 - 在 `TemplateManage.tsx` 的编辑器 `keydown` 事件中,拦截以下快捷键并路由到自定义 Undo/Redo 逻辑: - `Ctrl+Z` / `Cmd+Z` → `handleUndo()` - `Ctrl+Shift+Z` / `Cmd+Shift+Z` → `handleRedo()` - `Ctrl+Y` / `Cmd+Y` → `handleRedo()` - 拦截后调用 `e.preventDefault()` 阻止浏览器原生行为。 --- ## 问题 2:插入 smart-field-wrapper 分成两行 ### 现状 - `insertSmartField()` 使用 `document.execCommand('insertHTML', false, html)` 插入字段。 - 当光标位于一个以 `
` 结尾的 `

` 标签末尾时,WebKit/Blink 内核的 `insertHTML` 会把 `` 插到 `

` **外部**,导致字段独自占据新行。 ### 根因 - 用户提供的 HTML 明确显示了这一现象:`` 跑到了 `

` 之后。 - `execCommand('insertHTML')` 对块级元素边界(尤其是末尾存在 `
` 时)的自动修正行为不可控。 ### 需求 - 将 `insertSmartField()` 的插入方式从 `execCommand('insertHTML')` 替换为**精确的 `Range.insertNode()` 手动插入**: 1. `restoreSelection()` 恢复光标; 2. 获取当前 `Selection` 的 `Range`; 3. `range.deleteContents()`(对 collapsed 光标无实际删除); 4. 将 HTML 字符串转为 `DocumentFragment`; 5. `range.insertNode(fragment)` 精确插入到 Range 位置; 6. 把光标移动到插入内容的末尾(最后一个节点之后),保持编辑连贯性。 - 该方式不依赖浏览器的 `execCommand` 自动修正,可避免 `` 被抛到 `

` 外部。 --- ## 影响范围 - **仅 `src/pages/TemplateManage.tsx`** 需要修改: - `insertSmartField()` 函数(替换插入逻辑)。 - `keydown` 事件监听 `useEffect`(增加快捷键拦截)。 - 其他页面(`ReportEditor.tsx`、`ReportManage.tsx` 等)不受影响。 --- ## 验收标准 1. 在 `TemplateManage` 编辑器中删除一个 `smart-field-wrapper`(通过点击 × 或 Backspace/Delete)后,立即按 `Ctrl+Z`,字段能够完整恢复;按 `Ctrl+Y`(或 `Ctrl+Shift+Z`)能够重做删除。 2. 在 `

` 标签末尾(尤其是存在 `
` 的情况下)插入 `smart-field-wrapper`,字段与段落保持在同一行,不再被拆成两行。 3. `npm run lint` 通过,无 TypeScript 编译错误。