Files
Mdeical_Sur_Report/工程分析/20260419_2030/实现方案.md
admin 7275906f3c 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替换后的文字字体与原有文字完全一致
2026-04-19 20:33:43 +08:00

3.4 KiB
Raw Blame History

实现方案

修改文件

  • src/pages/ReportEditor.tsx

修改 1confirmAiInjection 保留撤销栈(约 line 981-998

原代码

  const confirmAiInjection = (newHtml: string, regionId: string) => {
    if (!editorRef.current) return;
    const targetContent = editorRef.current.querySelector(`.ai-region[data-ai-id="${regionId}"] .ai-content`) as HTMLElement;
    if (targetContent) {
      targetContent.innerHTML = newHtml;
      targetContent.style.transition = 'background-color 0.3s ease';
      targetContent.style.backgroundColor = '#bfdbfe';
      setTimeout(() => {
        targetContent.style.backgroundColor = '#eff6ff';
        setTimeout(() => {
          targetContent.style.backgroundColor = 'transparent';
        }, 800);
      }, 400);
      contentRef.current = editorRef.current.innerHTML;
      saveDraftToStorage();
    }
    setDiffModal(null);
  };

新代码

  const confirmAiInjection = (newHtml: string, regionId: string) => {
    if (!editorRef.current) return;
    const targetContent = editorRef.current.querySelector(`.ai-region[data-ai-id="${regionId}"] .ai-content`) as HTMLElement;
    if (targetContent) {
      targetContent.focus();
      const sel = window.getSelection();
      const range = document.createRange();
      range.selectNodeContents(targetContent);
      sel?.removeAllRanges();
      sel?.addRange(range);
      document.execCommand('insertHTML', false, newHtml);
      targetContent.style.transition = 'background-color 0.3s ease';
      targetContent.style.backgroundColor = '#bfdbfe';
      setTimeout(() => {
        targetContent.style.backgroundColor = '#eff6ff';
        setTimeout(() => {
          targetContent.style.backgroundColor = 'transparent';
        }, 800);
      }, 400);
      contentRef.current = editorRef.current.innerHTML;
      saveDraftToStorage();
    }
    setDiffModal(null);
  };

变更点

  1. 去掉 targetContent.innerHTML = newHtml;
  2. 增加 targetContent.focus()
  3. 使用 Range.selectNodeContents(targetContent) 选中区域内所有旧内容
  4. 使用 document.execCommand('insertHTML', false, newHtml) 执行替换
  5. 浏览器撤销栈会记录这次替换Ctrl+Z 可正常撤销

修改 2handleAIGenerate<p> 标签注入样式(约 line 955-970

原代码

      if (responseJson.updatedHtml && aiModifyEnabled) {
        let cleanHtml = responseJson.updatedHtml;
        cleanHtml = cleanHtml.replace(/<br\s*\/?>/gi, '');
        cleanHtml = cleanHtml.replace(/<\/p>\s*<p>/gi, '</p><p>');
        cleanHtml = cleanHtml.trim();
        if (targetRegionEl) {

新代码

      if (responseJson.updatedHtml && aiModifyEnabled) {
        let cleanHtml = responseJson.updatedHtml;
        cleanHtml = cleanHtml.replace(/<br\s*\/?>/gi, '');
        cleanHtml = cleanHtml.replace(/<\/p>\s*<p>/gi, '</p><p>');
        cleanHtml = cleanHtml.trim();
        cleanHtml = cleanHtml.replace(/<p>/gi, '<p style="padding: 0px; font-family: SimSun; font-size: 12pt; line-height: 1.5;">');
        if (targetRegionEl) {

变更点:在 cleanHtml.trim() 后增加一行正则替换,将所有 <p> 标签替换为带标准内联样式的 <p> 标签。

样式值说明

  • padding: 0px:与原始段落一致
  • font-family: SimSun:宋体
  • font-size: 12pt12pt 字号
  • line-height: 1.51.5 倍行高