Files
Mdeical_Sur_Report/工程分析/实现方案-2026-04-18-20-03-44.md

5.4 KiB
Raw Blame History

实现方案 —— 2026-04-18-20-03-44

方案目标

实现模板的导入/导出迁移能力,统一默认模板 Logo 的交互行为。

需求 1模板导出功能

修改文件

src/pages/TemplateManage.tsx

修改内容

在模板列表的每个模板行操作列中增加「导出」按钮(使用 Download 图标)。点击时:

const handleExportTemplate = (template: Template) => {
  const exportData = {
    version: '1.0',
    type: 'surclaw_template_package',
    title: template.title,
    description: template.description,
    content: template.content,
    fields: template.fields || []
  };
  const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `模板导出-${template.title}.json`;
  a.click();
  URL.revokeObjectURL(url);
};

需求 2模板导入功能

修改文件

src/pages/TemplateManage.tsx

修改内容

  1. 新增状态

    const [importedContent, setImportedContent] = useState<{content: string, fields: FormField[]} | null>(null);
    const fileInputRef = useRef<HTMLInputElement>(null);
    
  2. 新增导入处理函数

    const handleImportFile = (e: React.ChangeEvent<HTMLInputElement>) => {
      const file = e.target.files?.[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = (event) => {
        try {
          const json = JSON.parse(event.target?.result as string);
          if (json.type !== 'surclaw_template_package') {
            alert('无效的模板包文件');
            return;
          }
          setNewTemplateTitle(json.title || '');
          setNewTemplateDescription(json.description || '');
          setImportedContent({
            content: json.content || '',
            fields: Array.isArray(json.fields) ? json.fields : []
          });
        } catch {
          alert('文件解析失败,请检查 JSON 格式');
        }
      };
      reader.readAsText(file);
    };
    
  3. 修改创建逻辑:在 handleCreateTemplate 中,如果有 importedContent,优先使用导入的内容和字段:

    const newTemplate: Template = {
      id: 'tmpl_' + Date.now(),
      title: newTemplateTitle,
      description: newTemplateDescription,
      content: importedContent?.content || `<div style="font-size:12pt;line-height:1.5;"><p>请输入模板内容...</p></div>`,
      fields: importedContent?.fields || [],
      createdAt: new Date().toISOString()
    };
    
  4. UI 调整:在新增模板 Modal 中标题下方加入导入区域:

    <div className="flex items-center gap-3 mb-4 p-3 bg-slate-50 rounded-xl border border-dashed border-slate-200">
      <div className="text-xs text-text-muted flex-1">已有模板文件?点击右侧图标导入</div>
      <button
        onClick={() => fileInputRef.current?.click()}
        className="w-8 h-8 bg-accent text-white rounded-lg flex items-center justify-center hover:bg-blue-700 transition-colors shadow-sm"
      >
        <Upload size={16} />
      </button>
      <input ref={fileInputRef} type="file" accept=".json" className="hidden" onChange={handleImportFile} />
    </div>
    
  5. 关闭 Modal 时重置setImportedContent(null)

需求 3Logo 替换为可交互占位符

修改文件

src/utils/defaultContent.ts

修改内容

将默认模板顶部的 Logo HTML 替换为标准 image-placeholder

<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="manual" style="display:inline-block;text-align:center;width:65px;height:65px;line-height:65px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;position:relative;">
    <span class="delete-btn" contenteditable="false">×</span>
    <span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);display:block;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">LOGO</span>
</span>

关键点:

  • class="image-placeholder":触发编辑器中的占位符交互逻辑
  • data-mode="manual":标记为静态图片占位,不支持自动帧插入
  • position:relative + position:absolute 居中:确保提示文字绝对居中
  • delete-btn:支持点击右上方的「×」删除

涉及文件及修改点

文件 修改点
src/pages/TemplateManage.tsx 新增 handleExportTemplate;新增 importedContent 状态和 handleImportFile;修改 handleCreateTemplate 使用导入数据;新增模板 Modal 中增加导入 UI模板列表操作列增加导出按钮
src/utils/defaultContent.ts 顶部 Logo 替换为标准 image-placeholder

风险与注意事项

  1. 导入的 JSON 中 fields 数组需要与 FormField 类型结构兼容。由于 JSON 导入的是纯数据,直接赋值给 template.fields 即可TypeScript 编译时类型校验通过)。
  2. 导出文件名中包含模板标题,需注意标题中的特殊字符可能影响文件名(但浏览器通常会自动处理)。
  3. Logo 占位符替换后,原有「西安交通大学第一附属医院」的样式应保持不变,仅替换 Logo 部分。
  4. 新增模板弹窗关闭时,需同步重置 importedContentnull,避免影响下一次创建。