Files
Mdeical_Sur_Report/工程分析/实现方案-2026-04-17-19-26-17.md
admin 5fee3352c1 refactor: unify image-placeholder across editors and remove image field type
- Remove surgeonSignature and hospitalLogo from DEFAULT_FORM_FIELDS.
- Replace logo and signature in default template with inline image-placeholder spans.
- Enhance insertImage() in both editors with prompt for max-width/height (px).
- Abbreviate placeholder text to '插入图片' when width < 80px.
- Force inline insertion using display:inline-flex + vertical-align:middle.
- Port image-source picker modal from ReportEditor to TemplateManage.
- Remove legacy triggerPlaceholderUpload direct upload logic.
2026-04-17 19:34:03 +08:00

7.3 KiB
Raw Blame History

实现方案 — 2026-04-17-19-26-17

变更文件

  1. src/types.ts
  2. src/utils/defaultContent.ts
  3. src/pages/TemplateManage.tsx
  4. src/pages/ReportEditor.tsx

一、types.ts 修改

DEFAULT_FORM_FIELDS 中移除以下两个字段:

  • surgeonSignature
  • hospitalLogo

同时从 FieldType 中移除 'image'(因为图片不再作为可插入的字段类型,仅作为占位符存在)。若移除 'image' 会导致大量类型错误,也可保留类型但不在 UI 中暴露。为最小侵入,保留 'image' 类型但不再在 DEFAULT_FORM_FIELDS 中使用。

实际执行:删除 DEFAULT_FORM_FIELDS 中的最后两项(surgeonSignaturehospitalLogo)。


二、defaultContent.ts 修改

将原有的 div.image-placeholder 替换为 span.image-placeholder(保持居中):

<!-- 医院Logo -->
<p style="text-align: center; margin-bottom: 16px;" contenteditable="false">
    <span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;width:65px;height:65px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 auto;cursor:pointer;">
        <span class="delete-btn" contenteditable="false">×</span>
        <span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入图片</span>
    </span>
</p>

2.2 手术者签名

手术者签名:${smartField('surgeonSignature')} 替换为:

    <p style="font-family: SimSun;">
        手术者签名:<span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;min-width:80px;min-height:24px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入图片</span></span>
    </p>

三、TemplateManage.tsx 修改

3.1 移除"图片"分类暴露

  • expandedCategories 初始值从 ['填空','单选','多选','时间','图片'] 改为 ['填空','单选','多选','时间']
  • "插入字段"Tab 的遍历数组从 ['填空','单选','多选','时间','图片'] 改为 ['填空','单选','多选','时间']
  • "字段管理"Tab 的遍历数组同样移除 '图片'
  • 新增字段表单的 category select 中移除 <option value="图片">图片</option>
  • type select 的条件渲染中移除图片相关的 option。

3.2 改造 insertImage()

将现有的 insertImage() 替换为:

const insertImage = () => {
  const widthStr = prompt('请输入占位符最大宽度 (px),留空无限制:\n(提示:正文一行文字高度约为 20 像素左右)', '');
  const heightStr = prompt('请输入占位符最大高度 (px),留空无限制:', '');
  const width = parseInt(widthStr || '0');
  const height = parseInt(heightStr || '0');

  let styleStr = 'display:inline-flex;align-items:center;justify-content:center;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;';
  if (width > 0) styleStr += ` max-width:${width}px;`;
  if (height > 0) styleStr += ` max-height:${height}px;`;
  if (!width && !height) styleStr += ' padding:8px 16px;';

  const showShortText = width > 0 && width < 80;
  const hintText = showShortText ? '插入图片' : '插入/点击放置图片';

  const id = 'ph_' + Date.now();
  const html = `<span id="${id}" class="image-placeholder" data-placeholder="true" contenteditable="false" style="${styleStr}"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">${hintText}</span></span>&#8203;`;

  editorRef.current?.focus();
  restoreSelection();
  pushHistory();
  execCmd('insertHTML', html);
};

3.3 统一图片源选择弹窗

ReportEditor.tsx 复用以下逻辑到 TemplateManage.tsx

  • 新增状态:imagePickerOpenimagePickerTargetimageAssets(已存在)。
  • 新增 fillPlaceholderSrc 函数。
  • 修改 handleEditorClick 中的 placeholder 点击逻辑:
    if (!placeholder.classList.contains('has-image')) {
      e.preventDefault();
      e.stopPropagation();
      setImagePickerTarget(placeholder);
      setImagePickerOpen(true);
    }
    
  • 删除原有的 triggerPlaceholderUpload 函数及其直接调用。
  • 在 JSX 底部(isModalOpen 弹窗之后)新增 imagePickerOpen 弹窗组件(与 ReportEditor 完全一致)。

3.4 清理删除后的重置逻辑

当 placeholder 被删除(点击 × 后)时,重置为:

<span class="delete-btn" contenteditable="false">×</span>
<span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入/点击放置图片</span>

同时保留原有内联样式(避免把 inline-flex 等样式清掉)。


四、ReportEditor.tsx 修改

4.1 改造 insertImage()

与 TemplateManage 保持一致:

const insertImage = () => {
  editorRef.current?.focus();
  const widthStr = prompt('请输入占位符最大宽度 (px),留空无限制:\n(提示:正文一行文字高度约为 20 像素左右)', '');
  const heightStr = prompt('请输入占位符最大高度 (px),留空无限制:', '');
  const width = parseInt(widthStr || '0');
  const height = parseInt(heightStr || '0');

  let styleStr = 'display:inline-flex;align-items:center;justify-content:center;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;';
  if (width > 0) styleStr += ` max-width:${width}px;`;
  if (height > 0) styleStr += ` max-height:${height}px;`;
  if (!width && !height) styleStr += ' padding:8px 16px;';

  const showShortText = width > 0 && width < 80;
  const hintText = showShortText ? '插入图片' : '插入/点击放置图片';

  const id = 'ph_' + Date.now();
  const html = `<span id="${id}" class="image-placeholder" data-placeholder="true" contenteditable="false" style="${styleStr}"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">${hintText}</span></span>&#8203;`;
  execCmd('insertHTML', html);
};

4.2 删除后重置逻辑

handleEditorClickplaceholder 删除后重置的 HTML 改为使用 <span> 结构并保留内联样式:

placeholder.innerHTML = `
  <span class="delete-btn" contenteditable="false">×</span>
  <span class="placeholder-text" style="color: #94a3b8; font-size: 11px; pointer-events: none; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">插入/点击放置图片</span>
`;

4.3 fillPlaceholderSrc 保持兼容

已有 fillPlaceholderSrc 可继续使用,但建议填充的图片增加 max-width: 100%; max-height: 100%; object-fit: contain;


回滚策略

修改前最新提交为 0c57409。若失败可 git reset --hard 0c57409

无新增 npm 依赖