Files
Mdeical_Sur_Report/工程分析/实现方案-2026-04-17-12-34-56.md
admin f7c7270053 fix: undo stack, field insertion wrap, backspace/delete precision; feat: signature size limit & isSigned control
- Replace direct DOM remove() with Range+execCommand('delete') in TemplateManage click and keydown handlers to restore undo stack
- Append ​ zero-width space to smart-field-wrapper HTML in insertSmartField and defaultContent.ts to prevent unwanted line breaks
- Refactor ReportEditor surgeonSignature rendering to depend on isSigned field
- Add isSigned to DEFAULT_FORM_FIELDS (single_select: 已签字/未签字)
- Change surgeonSignature to visibleInForm=true, isSystemLocked=false
- Constrain signature image with max-width:120px, max-height:40px, object-fit:contain in CSS and print.ts
- Add weak-blocking signature validation prompts in saveReport('completed')
- Update experience record (#19)
2026-04-17 12:41:07 +08:00

5.2 KiB
Raw Blame History

实现方案 — 撤销栈修复、字段删除交互优化与签名字段闭环2026-04-17-12-34-56

一、修改文件清单

  1. src/pages/TemplateManage.tsx — 删除逻辑改用 execCommand('delete');插入 HTML 增加零宽空格防换行
  2. src/types.ts — 修改 surgeonSignature 显隐属性;新增 isSigned 字段
  3. src/pages/ReportEditor.tsx — 初始值增加 isSigned;签名同步逻辑重构;完成报告签名校验
  4. src/index.css — 签名图片尺寸约束
  5. src/utils/print.ts — 打印样式同步签名尺寸约束

二、详细改动

2.1 src/pages/TemplateManage.tsx

A. 点击红 X 删除改用 execCommand('delete')

if (smartField && targetEl.closest('.delete-btn')) {
  e.stopPropagation();
  e.preventDefault();
  const sel = window.getSelection();
  const range = document.createRange();
  range.selectNode(smartField);
  sel?.removeAllRanges();
  sel?.addRange(range);
  document.execCommand('delete');
  saveTemplateContent();
  return;
}

B. 键盘 Backspace/Delete 改用 execCommand('delete')

handleKeyDown 中,当定位到 smart-field-wrapper 目标后:

if (target) {
  e.preventDefault();
  const sel = window.getSelection();
  const range = document.createRange();
  range.selectNode(target);
  sel?.removeAllRanges();
  sel?.addRange(range);
  document.execCommand('delete');
  saveTemplateContent();
}

C. 插入 HTML 防换行

insertSmartField 的 HTML 字符串末尾增加 ​(零宽空格),作为行内锚点,防止浏览器将字段挤到新行:

<span class="smart-field-wrapper" ...>...</span>&#8203;

2.2 src/types.ts

  • surgeonSignature 改为:
    { key: 'surgeonSignature', label: '手术者签名', category: '图片', type: 'signature', visibleInForm: true, isSystemLocked: false }
    
  • DEFAULT_FORM_FIELDS 末尾追加(放在 surgeonSignature 之前或之后均可):
    { key: 'isSigned', label: '手术者签名确认', category: '单选', type: 'single_select', visibleInForm: true, isSystemLocked: false, options: ['已签字', '未签字'] },
    

2.3 src/pages/ReportEditor.tsx

A. 初始 reportData 增加 isSigned

const [reportData, setReportData] = useState<Partial<Report>>({
  // ... 其他字段
  isSigned: '未签字',
  // ...
});

B. 签名同步逻辑重构

surgeonSignature 的特殊处理从 useEffect 移到更前面的位置,逻辑改为:

if (fieldKey === 'surgeonSignature') {
  const isSigned = (reportData as any).isSigned === '已签字';
  const signatureData = currentUser?.signature;
  if (isSigned && signatureData) {
    const imgHtml = `<img src="${signatureData}" class="report-signature-img" alt="签名" draggable="false" />`;
    if (el.innerHTML !== imgHtml) {
      el.innerHTML = imgHtml;
      el.style.border = 'none';
      el.style.backgroundColor = 'transparent';
    }
  } else {
    const placeholder = isSigned ? '【请上传电子签】' : '【未签字】';
    if (el.innerText !== placeholder) {
      el.innerText = placeholder;
      el.style.border = '';
      el.style.backgroundColor = '';
    }
  }
  return;
}

C. 完成报告签名校验

saveReportstatus === 'completed' 分支中,在现有患者信息校验之后追加:

const hasSignatureField = editorRef.current?.querySelector('[data-bind="surgeonSignature"]');
if (hasSignatureField) {
  const isSigned = reportData.isSigned === '已签字';
  const hasSignatureImage = !!currentUser?.signature;
  if (!isSigned) {
    const proceed = window.confirm('提示:模板中包含【手术者签名】字段,但您在基本信息中未选择"已签字"。是否继续完成报告?');
    if (!proceed) return;
  } else if (!hasSignatureImage) {
    const proceed = window.confirm('提示:您选择了"已签字",但您的账号尚未上传电子签名图片。报告中将不显示签名图片,是否继续完成?');
    if (!proceed) return;
  }
}

2.4 src/index.css

修改 .report-signature-img

.report-signature-img {
  max-width: 120px;
  max-height: 40px;
  width: auto;
  height: auto;
  object-fit: contain;
  vertical-align: middle;
  display: inline-block;
}

@media print 中同步:

@media print {
  .report-signature-img {
    max-width: 120px !important;
    max-height: 40px !important;
    width: auto !important;
    height: auto !important;
    object-fit: contain !important;
    vertical-align: middle !important;
    display: inline-block !important;
  }
}

2.5 src/utils/print.ts

在 iframe 的 <style> 中,.smart-field-wrapper 规则之后追加:

.report-signature-img { max-width: 120px; max-height: 40px; width: auto; height: auto; object-fit: contain; vertical-align: middle; display: inline-block; }

三、风险与回滚

  • 风险:改用 execCommand('delete') 后,少数旧版浏览器可能行为不一致,但现代 Chromium/Edge 支持良好。
  • 风险&#8203; 零宽空格在极少数场景下可能导致光标异常,但其为无形字符,影响极小。
  • 回滚:如出现问题,可回退上述 5 个文件的修改。