Files
Mdeical_Sur_Report/工程分析/实现方案-2026-04-17-11-34-24.md
admin 424407a17e feat: field hover highlight, e-signature upload, surgeon signature linkage
- Add signature?: string to User type and 'signature' to FieldType
- Add surgeonSignature field to DEFAULT_FORM_FIELDS (category: 图片)
- UserManage: add canvas-based image compression (max 500px) and signature upload UI
- TemplateManage: add hover highlight on field buttons via direct DOM style manipulation
- TemplateManage: add '图片' category to field library for surgeonSignature insertion
- ReportEditor: auto-fill surgeonSignature with currentUser.signature image or placeholder text
- index.css & print.ts: add .report-signature-img styling (height 2.4em, vertical-align middle)
- Update experience record (#18)
2026-04-17 12:04:23 +08:00

5.4 KiB
Raw Blame History

实现方案 — 字段悬浮高亮、电子签上传与手术者签名联动2026-04-17-11-34-24

一、修改文件清单

  1. src/types.ts — 扩展 User / FieldType / DEFAULT_FORM_FIELDS
  2. src/pages/UserManage.tsx — 电子签上传组件 + 前端压缩逻辑
  3. src/pages/TemplateManage.tsx — 悬浮高亮 + 图片分类 + 手术者签名插入
  4. src/pages/ReportEditor.tsxsurgeonSignature 特殊同步逻辑
  5. src/index.css — 签名图片排版样式 + 打印样式
  6. src/utils/print.ts — 打印样式中增加签名图片规则

二、详细改动

2.1 src/types.ts

  • User 接口追加 signature?: string
  • FieldType 扩展为 'text' | 'single_select' | 'multi_select' | 'time' | 'date' | 'signature'
  • DEFAULT_FORM_FIELDS 末尾追加:
    { key: 'surgeonSignature', label: '手术者签名', category: '图片', type: 'signature', visibleInForm: false, isSystemLocked: true }
    

2.2 src/pages/UserManage.tsx

A. 前端压缩工具函数

const compressImage = (file: File, maxSize: number = 500): Promise<string> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = (e) => {
      const img = new Image();
      img.src = e.target?.result as string;
      img.onload = () => {
        const canvas = document.createElement('canvas');
        let { width, height } = img;
        if (width > height && width > maxSize) {
          height = Math.round((height * maxSize) / width);
          width = maxSize;
        } else if (height > maxSize) {
          width = Math.round((width * maxSize) / height);
          height = maxSize;
        }
        canvas.width = width;
        canvas.height = height;
        const ctx = canvas.getContext('2d');
        if (ctx) {
          ctx.fillStyle = '#FFFFFF';
          ctx.fillRect(0, 0, width, height);
          ctx.drawImage(img, 0, 0, width, height);
        }
        resolve(canvas.toDataURL('image/jpeg', 0.8));
      };
      img.onerror = reject;
    };
    reader.onerror = reject;
  });
};

B. 上传组件与保存逻辑

  • 在模态框表单中("状态"选择器下方或底部按钮上方)增加一个区块:
    • 标签:"电子签名"
    • formData.signature 有值,显示压缩后的预览图(高度限制 64px
    • "上传签名" 按钮(type="button"),触发隐藏的 <input type="file" accept="image/*">
    • "清除签名" 按钮(有值时显示)。
  • handleSubmit 中保存 signature 字段到用户对象。
  • 编辑当前登录用户时,同步更新 storage.set('currentUser', currentCached),确保 ReportEditor 能立即读取到最新签名。

2.3 src/pages/TemplateManage.tsx

A. 悬浮高亮

在字段库按钮上增加 onMouseEnteronMouseLeave

const highlightField = (key: string, active: boolean) => {
  if (!editorRef.current) return;
  const el = editorRef.current.querySelector(`[data-bind="${key}"]`) as HTMLElement | null;
  if (!el) return;
  if (active) {
    el.style.transition = 'all 0.2s';
    el.style.boxShadow = '0 0 0 2px #3b82f6';
    el.style.backgroundColor = '#e0f2fe';
  } else {
    el.style.boxShadow = '';
    el.style.backgroundColor = '';
  }
};

B. 图片分类与手术者签名

  • 插入字段分类数组从 ['填空', '单选', '多选', '时间'] 改为 ['填空', '单选', '多选', '时间', '图片']
  • surgeonSignature 字段会自动出现在"图片"分类下,按钮点击逻辑复用 insertSmartField(已支持唯一性校验)。

2.4 src/pages/ReportEditor.tsx

在"Sync form state -> rich text field values"的 useEffect 中,对 fieldKey === 'surgeonSignature' 做特殊分支:

if (fieldKey === 'surgeonSignature') {
  const signatureData = currentUser?.signature;
  if (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 {
    if (el.innerText !== '【请上传电子签】') {
      el.innerText = '【请上传电子签】';
      el.style.border = '';
      el.style.backgroundColor = '';
    }
  }
  return; // 跳过常规文本同步
}

2.5 src/index.css

增加签名图片样式:

.report-signature-img {
  height: 2.4em;
  width: auto;
  vertical-align: middle;
  display: inline-block;
  margin: -0.3em 0;
}

@media print 中同步增加:

@media print {
  .report-signature-img {
    height: 2.4em !important;
    width: auto !important;
    vertical-align: middle !important;
    display: inline-block !important;
    margin: -0.3em 0 !important;
  }
}

2.6 src/utils/print.ts

在打印 iframe 的 <style> 标签内,.smart-field-wrapper 规则之后追加:

.report-signature-img {
  height: 2.4em;
  width: auto;
  vertical-align: middle;
  display: inline-block;
  margin: -0.3em 0;
}

三、风险与回滚

  • 风险localStorage 容量有限,压缩后的签名图片通常在 10~50KB单用户存储安全。
  • 风险:旧用户的 User 对象没有 signature 字段,读取时为 undefined,代码中已通过可选链和默认值处理。
  • 回滚:如出现问题,可回退 6 个文件的修改。