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

131 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实现方案 —— 2026-04-18-20-03-44
## 方案目标
实现模板的导入/导出迁移能力,统一默认模板 Logo 的交互行为。
## 需求 1模板导出功能
### 修改文件
`src/pages/TemplateManage.tsx`
### 修改内容
在模板列表的每个模板行操作列中增加「导出」按钮(使用 Download 图标)。点击时:
```ts
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. **新增状态**
```ts
const [importedContent, setImportedContent] = useState<{content: string, fields: FormField[]} | null>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
```
2. **新增导入处理函数**
```ts
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`,优先使用导入的内容和字段:
```ts
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 中标题下方加入导入区域:
```tsx
<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`
```html
<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. 新增模板弹窗关闭时,需同步重置 `importedContent` 为 `null`,避免影响下一次创建。