Files
Mdeical_Sur_Report/工程分析/需求分析-2026-04-17-13-32-07.md
admin b155dd42d6 fix(TemplateManage): Ctrl+Z undo and smart-field insertion layout
- Intercept Ctrl+Z/Y keyboard shortcuts in keydown listener and route
to custom undoStack/redoStack to fix undo inconsistency.
- Replace execCommand('insertHTML') with precise Range.insertNode()
in insertSmartField to prevent <span> escaping out of <p> when
preceded by <br>.
2026-04-17 13:39:16 +08:00

3.6 KiB
Raw Blame History

需求分析 — 2026-04-17-13-32-07

用户反馈

  1. Ctrl+Z 快捷键无法撤销对 smart-field-wrapper 的删除,但点击工具栏的撤销按钮可以正常撤销。
  2. 插入 smart-field-wrapper 时仍会分成两行。用户怀疑是原本文本结构的问题,并提供了出现问题的 HTML 片段:
    <p style="font-family: SimSun;">
        <strong>手术日期:</strong><br>
    </p>
    <span class="smart-field-wrapper" ...>...</span>
    
    用户补充:把字段插到下面的内容中(即上述 HTML 中已有字段的位置)则没有问题。

问题 1Ctrl+Z 快捷键撤销失效

现状

  • TemplateManage.tsx 已实现了自定义的 undoStack / redoStack 以及 handleUndo() / handleRedo()
  • 工具栏的撤销/重做按钮调用的是自定义函数,能够正确恢复 innerHTML 历史快照。
  • 键盘按下 Ctrl+Z 时,浏览器会触发原生 undodocument.execCommand('undo')),它与自定义历史栈完全脱节,因此:
    • 若原生栈为空(或已耗尽),则没有任何反应;
    • 若原生栈有记录,可能恢复出意料之外的状态。

根因

  • 当前只在编辑器上拦截了 Backspace / Delete 键(用于防止误删整段),没有拦截 Ctrl+Z / Ctrl+Y 快捷键

需求

  • TemplateManage.tsx 的编辑器 keydown 事件中,拦截以下快捷键并路由到自定义 Undo/Redo 逻辑:
    • Ctrl+Z / Cmd+ZhandleUndo()
    • Ctrl+Shift+Z / Cmd+Shift+ZhandleRedo()
    • Ctrl+Y / Cmd+YhandleRedo()
  • 拦截后调用 e.preventDefault() 阻止浏览器原生行为。

问题 2插入 smart-field-wrapper 分成两行

现状

  • insertSmartField() 使用 document.execCommand('insertHTML', false, html) 插入字段。
  • 当光标位于一个以 <br> 结尾的 <p> 标签末尾时WebKit/Blink 内核的 insertHTML 会把 <span> 插到 <p> 外部,导致字段独自占据新行。

根因

  • 用户提供的 HTML 明确显示了这一现象:<span> 跑到了 </p> 之后。
  • execCommand('insertHTML') 对块级元素边界(尤其是末尾存在 <br> 时)的自动修正行为不可控。

需求

  • insertSmartField() 的插入方式从 execCommand('insertHTML') 替换为精确的 Range.insertNode() 手动插入
    1. restoreSelection() 恢复光标;
    2. 获取当前 SelectionRange
    3. range.deleteContents()(对 collapsed 光标无实际删除);
    4. 将 HTML 字符串转为 DocumentFragment
    5. range.insertNode(fragment) 精确插入到 Range 位置;
    6. 把光标移动到插入内容的末尾(最后一个节点之后),保持编辑连贯性。
  • 该方式不依赖浏览器的 execCommand 自动修正,可避免 <span> 被抛到 <p> 外部。

影响范围

  • src/pages/TemplateManage.tsx 需要修改:
    • insertSmartField() 函数(替换插入逻辑)。
    • keydown 事件监听 useEffect(增加快捷键拦截)。
  • 其他页面(ReportEditor.tsxReportManage.tsx 等)不受影响。

验收标准

  1. TemplateManage 编辑器中删除一个 smart-field-wrapper(通过点击 × 或 Backspace/Delete立即按 Ctrl+Z,字段能够完整恢复;按 Ctrl+Y(或 Ctrl+Shift+Z)能够重做删除。
  2. <p> 标签末尾(尤其是存在 <br> 的情况下)插入 smart-field-wrapper,字段与段落保持在同一行,不再被拆成两行。
  3. npm run lint 通过,无 TypeScript 编译错误。