2026-04-18-17-27-51 - 修复TemplateManage静态占位符插入、重构默认模板排版、修复Logo删除按钮交互
This commit is contained in:
@@ -1266,7 +1266,29 @@ export default function TemplateManage() {
|
||||
const text = showShortText ? '插图' : hintText;
|
||||
html = `<span id="${id}" class="image-placeholder" data-placeholder="true" contenteditable="false"${modeAttr} 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;">${text}</span></span>​`;
|
||||
}
|
||||
execCmd('insertHTML', html);
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = html;
|
||||
const fragment = document.createDocumentFragment();
|
||||
while (wrapper.firstChild) {
|
||||
fragment.appendChild(wrapper.firstChild);
|
||||
}
|
||||
const sel2 = window.getSelection();
|
||||
if (sel2 && sel2.rangeCount > 0) {
|
||||
const range = sel2.getRangeAt(0);
|
||||
range.deleteContents();
|
||||
range.insertNode(fragment);
|
||||
const lastNode = fragment.lastChild;
|
||||
if (lastNode) {
|
||||
range.setStartAfter(lastNode);
|
||||
range.collapse(true);
|
||||
sel2.removeAllRanges();
|
||||
sel2.addRange(range);
|
||||
}
|
||||
} else if (editorRef.current) {
|
||||
editorRef.current.appendChild(fragment);
|
||||
}
|
||||
editorRef.current?.focus();
|
||||
saveTemplateContent();
|
||||
setPlaceholderModal({...placeholderModal, isOpen: false});
|
||||
}} className="px-4 py-2 bg-accent text-white rounded text-sm">确认插入</button>
|
||||
</div>
|
||||
|
||||
@@ -1,65 +1,62 @@
|
||||
const smartField = (key: string) => `<span class="smart-field-wrapper" contenteditable="false" style="white-space:nowrap;position:relative;"><span class="field-value" data-bind="${key}" contenteditable="true" style="min-width:32px;padding:0 4px;margin:0 2px;border:1px solid #cbd5e1;border-radius:2px;display:inline-block;background:#f8fafc;color:#0f172a;line-height:1.2;font-size:inherit;vertical-align:text-bottom;box-sizing:border-box;min-height:1.2em;outline:none;"> </span><span class="delete-btn" contenteditable="false">×</span></span>​`;
|
||||
|
||||
export const defaultReportContent = `
|
||||
<!-- 医院Logo -->
|
||||
<p style="text-align: center; margin-bottom: 16px;" contenteditable="false">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="manual" 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;">
|
||||
<table style="width: 100%; border: none; margin-bottom: 16px;">
|
||||
<tr>
|
||||
<td style="width: 20%; vertical-align: bottom; border: none; text-align: left;">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="manual" style="position:relative;display:inline-flex;align-items:center;justify-content:center;width:65px;height:65px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;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>
|
||||
</td>
|
||||
<td style="width: 60%; text-align: center; vertical-align: middle; border: none;">
|
||||
<div style="font-size: 14pt; font-family: SimSun; border-bottom: 1px solid #000; padding-bottom: 4px; margin-bottom: 8px; display: inline-block;">西 安 交 通 大 学 第 一 附 属 医 院</div>
|
||||
<div style="font-size: 16pt; font-family: SimSun;">手术记录</div>
|
||||
</td>
|
||||
<td style="width: 20%; border: none;"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- 医院名称 -->
|
||||
<p style="text-align: center; font-family: SimSun; margin-bottom: 8px;" contenteditable="false">
|
||||
<strong><u>西 安 交 通 大 学 第 一 附 属 医 院</u></strong>
|
||||
</p>
|
||||
|
||||
<!-- 报告标题 -->
|
||||
<h1 style="font-family: SimSun; font-size: 20px; margin: 16px 0; text-align: center;" contenteditable="false">手术记录</h1>
|
||||
|
||||
<div class="template-info-section">
|
||||
<p style="font-family: SimSun;">
|
||||
姓名:${smartField('patientName')}
|
||||
性别:${smartField('patientGender')}
|
||||
年龄:${smartField('patientAge')}
|
||||
科别:${smartField('department')}
|
||||
床号:${smartField('bedNumber')}
|
||||
<div style="border-bottom: 1px solid #000; padding-bottom: 4px; margin-bottom: 12px;">
|
||||
<p style="font-family: SimSun; font-size: 11pt; font-weight: normal; margin: 0; line-height: 1.8;">
|
||||
姓名:${smartField('patientName')}
|
||||
性别:${smartField('patientGender')}
|
||||
年龄:${smartField('patientAge')}
|
||||
科别:${smartField('department')}
|
||||
床号:${smartField('bedNumber')}
|
||||
住院号:${smartField('hospitalId')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun;">
|
||||
<strong>手术日期:</strong>${smartField('surgeryDate')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun;">
|
||||
<strong>术前诊断:</strong>${smartField('preoperativeDiagnosis')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun;">
|
||||
<strong>术后诊断:</strong>${smartField('postoperativeDiagnosis')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun;">
|
||||
<strong>手术名称:</strong>${smartField('title')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun;">
|
||||
手术开始时间:${smartField('startTime')}
|
||||
手术终止时间:${smartField('endTime')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun;">
|
||||
手术者:${smartField('surgeon')}
|
||||
助手:${smartField('assistant')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun;">
|
||||
麻醉师:${smartField('anesthesiologist')}
|
||||
麻醉方式:${smartField('anesthesiaType')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="font-family: SimSun;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.8;">
|
||||
<strong>手术日期:</strong>${smartField('surgeryDate')}
|
||||
</p>
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.8;">
|
||||
<strong>术前诊断:</strong>${smartField('preoperativeDiagnosis')}
|
||||
</p>
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.8;">
|
||||
<strong>术中诊断:</strong>${smartField('postoperativeDiagnosis')}
|
||||
</p>
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.8;">
|
||||
<strong>手术名称:</strong>${smartField('title')}
|
||||
</p>
|
||||
|
||||
<table style="width: 100%; border: none; font-family: SimSun; font-size: 12pt; margin-bottom: 12pt;">
|
||||
<tr>
|
||||
<td style="border: none; padding: 4px 0; width: 50%;">手术开始时间:${smartField('startTime')}</td>
|
||||
<td style="border: none; padding: 4px 0; width: 50%;">手术终止时间:${smartField('endTime')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border: none; padding: 4px 0;">手术者:${smartField('surgeon')}</td>
|
||||
<td style="border: none; padding: 4px 0;">助手:${smartField('assistant')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border: none; padding: 4px 0;">麻醉师:${smartField('anesthesiologist')}</td>
|
||||
<td style="border: none; padding: 4px 0;">麻醉方式:${smartField('anesthesiaType')}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p style="font-family: SimSun; font-size: 12pt;">
|
||||
<strong>手术步骤、术中出现的情况及处理:</strong>
|
||||
</p>
|
||||
|
||||
|
||||
82
工程分析/实现方案-2026-04-18-17-27-51.md
Normal file
82
工程分析/实现方案-2026-04-18-17-27-51.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# 实现方案 —— 2026-04-18-17-27-51
|
||||
|
||||
## 方案目标
|
||||
修复 TemplateManage 静态占位符插入 Bug,重构默认报告模板顶部排版,修复 Logo 删除按钮交互。
|
||||
|
||||
## 需求 1:修复静态图片占位符插入不显示
|
||||
|
||||
### 问题根因
|
||||
`TemplateManage.tsx` 中 `insertImage()` 使用 `document.execCommand('insertHTML', false, html)`。现代浏览器对含 `contenteditable="false"` 的复杂嵌套标签会自动修正/拍平,导致外层 `.image-placeholder` 容器丢失,DOM 仅剩零散子元素,视觉上不可见。
|
||||
|
||||
### 解决步骤
|
||||
1. **定位 `insertImage` 函数**:找到 `TemplateManage.tsx` 中通过 `document.execCommand('insertHTML')` 插入占位符的逻辑。
|
||||
2. **替换为 `Range.insertNode`**:
|
||||
- 创建临时 `div`,将 HTML 字符串写入 `innerHTML`。
|
||||
- 将子节点逐个移入 `DocumentFragment`。
|
||||
- 获取当前 `Selection` 的 `RangeAt(0)`。
|
||||
- 调用 `range.deleteContents()` 清空当前选区。
|
||||
- 调用 `range.insertNode(fragment)` 精确插入。
|
||||
- 将光标移动到插入内容之后。
|
||||
3. **保持原有弹窗逻辑不变**:Modal 中的模式选择(frame/manual)、宽高输入等逻辑不受影响。
|
||||
|
||||
## 需求 2:重构默认报告模板排版
|
||||
|
||||
### 排版设计
|
||||
|
||||
#### 页眉(Logo + 医院名 + 标题)
|
||||
使用 3 列 `<table>`(左 20%、中 60%、右 20%),中间列绝对居中:
|
||||
- 左列:Logo 占位符(65×65,`data-mode="manual"`,`position:relative`)
|
||||
- 中列:
|
||||
- 第一行:14pt SimSun「西 安 交 通 大 学 第 一 附 属 医 院」(带 `border-bottom: 1px solid #000` 下划线,使用 `display: inline-block`)
|
||||
- 第二行:16pt SimSun「手术记录」
|
||||
- 右列:留空
|
||||
|
||||
#### 基本信息栏(下划线贯穿)
|
||||
使用 `<div style="border-bottom: 1px solid #000; padding-bottom: 4px; margin-bottom: 12px;">` 包裹一行:
|
||||
- 11pt SimSun,不加粗
|
||||
- 姓名、性别、年龄、科别、床号、住院号,用 ` ` 间隔
|
||||
|
||||
#### 诊断/手术信息(单行加粗)
|
||||
每项独立 `<p>`:
|
||||
- 12pt SimSun,`font-weight: bold`
|
||||
- 手术日期、术前诊断、术中诊断、手术名称
|
||||
|
||||
#### 双列信息(两项一行,不加粗)
|
||||
使用 `<table style="width: 100%; border: none;">`:
|
||||
- 三行两列,每列 50%
|
||||
- 12pt SimSun,不加粗
|
||||
- 手术开始/终止时间、手术者/助手、麻醉师/麻醉方式
|
||||
|
||||
#### 手术步骤标题
|
||||
- 12pt SimSun,`font-weight: bold`
|
||||
- 「手术步骤、术中出现的情况及处理:」
|
||||
|
||||
#### 保留内容
|
||||
- 5 条手术步骤段落文字(不变)
|
||||
- 手术图片说明表格(需求 3 中已替换的最新 6 图格表格)
|
||||
- 手术后情况段落(术后诊断、标本描述、病理检查、冰冻病理)
|
||||
- 手术者签名占位符 + 撰写时间字段
|
||||
|
||||
### 涉及文件
|
||||
`src/utils/defaultContent.ts` —— 完全重写 `defaultReportContent` 变量。
|
||||
|
||||
## 需求 3:修复顶部 Logo 删除按钮
|
||||
|
||||
### 解决步骤
|
||||
在 `defaultContent.ts` 中 Logo 占位符的 `style` 属性中增加 `position: relative;`,使绝对定位的 `.delete-btn` 相对于占位符自身定位,而非向外层逃逸。
|
||||
|
||||
```html
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="manual" style="position:relative;display:inline-flex;...">
|
||||
```
|
||||
|
||||
## 涉及文件及修改点
|
||||
| 文件 | 修改点 |
|
||||
|------|--------|
|
||||
| `src/pages/TemplateManage.tsx` | `insertImage` 中 `execCommand('insertHTML')` → `Range.insertNode` |
|
||||
| `src/utils/defaultContent.ts` | 完全重写顶部排版;Logo 增加 `position:relative`;保留手术步骤/表格/底部段落 |
|
||||
|
||||
## 风险与注意事项
|
||||
1. `Range.insertNode` 要求编辑器有有效光标/选区。若编辑器未聚焦或选区不在编辑器内,需增加保护逻辑(fallback 到 `editorRef.current.appendChild`)。
|
||||
2. 默认模板重写后,需验证 `smartField()` 生成的所有字段占位符在新排版中是否正确渲染。
|
||||
3. 打印时需确认新排版的下划线、表格边框在 `@media print` 中正常显示。
|
||||
4. ` ` 分隔的基本信息栏在打印时可能换行,需测试实际打印效果。
|
||||
155
工程分析/测试方案-2026-04-18-17-27-51.md
Normal file
155
工程分析/测试方案-2026-04-18-17-27-51.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# 测试方案 —— 2026-04-18-17-27-51
|
||||
|
||||
## 测试目标
|
||||
验证 TemplateManage 静态占位符插入修复、默认模板排版重构、Logo 删除按钮修复。
|
||||
|
||||
## 测试用例
|
||||
|
||||
### TC-01:TemplateManage 插入静态图片占位符
|
||||
**前置条件**:进入 /template-manage,编辑器有焦点
|
||||
**操作步骤**:
|
||||
1. 点击工具栏「插入图片占位符」
|
||||
2. 在弹窗中选择「静态图片占位」
|
||||
3. 输入宽度 200,高度 200
|
||||
4. 点击「确认插入」
|
||||
|
||||
**预期结果**:
|
||||
- 编辑器中出现虚线边框的占位符框
|
||||
- 占位符带有 `class="image-placeholder"` 和 `data-mode="manual"`
|
||||
- 占位符内部显示「插入/点击放置图片」文字
|
||||
- 占位符右上角显示红色「×」删除按钮
|
||||
|
||||
---
|
||||
|
||||
### TC-02:TemplateManage 插入手术影像占位符
|
||||
**前置条件**:进入 /template-manage
|
||||
**操作步骤**:
|
||||
1. 点击工具栏「插入图片占位符」
|
||||
2. 选择「手术影像占位」
|
||||
3. 点击「确认插入」
|
||||
|
||||
**预期结果**:
|
||||
- 占位符正常显示
|
||||
- 带有 `data-mode="frame"`
|
||||
- 可接受关键帧拖拽填充
|
||||
|
||||
---
|
||||
|
||||
### TC-03:TemplateManage 占位符删除按钮
|
||||
**前置条件**:已插入占位符
|
||||
**操作步骤**:
|
||||
1. 鼠标悬浮在占位符上
|
||||
2. 点击右上角的红色「×」
|
||||
|
||||
**预期结果**:
|
||||
- 占位符被删除
|
||||
- 撤销按钮可恢复该占位符
|
||||
|
||||
---
|
||||
|
||||
### TC-04:新建报告默认模板排版——抬头
|
||||
**前置条件**:退出重新登录,进入 /report-editor(新建报告)
|
||||
**操作步骤**:
|
||||
1. 查看报告顶部
|
||||
|
||||
**预期结果**:
|
||||
- 左侧有 65×65 的 Logo 占位符(虚线框)
|
||||
- 中间偏右有 14pt 下划线文字「西 安 交 通 大 学 第 一 附 属 医 院」
|
||||
- 下方有 16pt 文字「手术记录」
|
||||
- 整体居中对齐
|
||||
|
||||
---
|
||||
|
||||
### TC-05:新建报告默认模板排版——基本信息栏
|
||||
**前置条件**:新建报告已加载默认模板
|
||||
**操作步骤**:
|
||||
1. 查看抬头下方的基本信息行
|
||||
|
||||
**预期结果**:
|
||||
- 一行显示:姓名、性别、年龄、科别、床号、住院号
|
||||
- 字体 11pt,不加粗
|
||||
- 整行下方有一条黑色贯穿下划线
|
||||
|
||||
---
|
||||
|
||||
### TC-06:新建报告默认模板排版——诊断信息
|
||||
**前置条件**:新建报告已加载默认模板
|
||||
**操作步骤**:
|
||||
1. 查看手术日期、术前诊断、术中诊断、手术名称
|
||||
|
||||
**预期结果**:
|
||||
- 每项独立一行
|
||||
- 12pt 字体,加粗
|
||||
- 格式为:「手术日期:」+ smartField 占位符
|
||||
|
||||
---
|
||||
|
||||
### TC-07:新建报告默认模板排版——双列信息
|
||||
**前置条件**:新建报告已加载默认模板
|
||||
**操作步骤**:
|
||||
1. 查看时间、人员、麻醉信息
|
||||
|
||||
**预期结果**:
|
||||
- 手术开始/终止时间在同一行,左右各 50%
|
||||
- 手术者/助手在同一行
|
||||
- 麻醉师/麻醉方式在同一行
|
||||
- 12pt 字体,不加粗
|
||||
|
||||
---
|
||||
|
||||
### TC-08:新建报告默认模板排版——手术步骤标题
|
||||
**前置条件**:新建报告已加载默认模板
|
||||
**操作步骤**:
|
||||
1. 查看「手术步骤、术中出现的情况及处理:」
|
||||
|
||||
**预期结果**:
|
||||
- 12pt 字体,加粗
|
||||
- 位于双列信息下方
|
||||
|
||||
---
|
||||
|
||||
### TC-09:Logo 占位符删除按钮可点击
|
||||
**前置条件**:新建报告已加载默认模板
|
||||
**操作步骤**:
|
||||
1. 鼠标悬浮在顶部 Logo 占位符上
|
||||
2. 点击右上角的红色「×」
|
||||
|
||||
**预期结果**:
|
||||
- Logo 占位符被删除
|
||||
- 可撤销恢复
|
||||
|
||||
---
|
||||
|
||||
### TC-10:Logo 占位符图片上传
|
||||
**前置条件**:新建报告已加载默认模板
|
||||
**操作步骤**:
|
||||
1. 点击顶部 Logo 占位符
|
||||
2. 选择本地上传一张图片
|
||||
|
||||
**预期结果**:
|
||||
- 图片正确显示在 65×65 区域内
|
||||
- 图片不溢出占位符
|
||||
|
||||
---
|
||||
|
||||
### TC-11:打印效果验证
|
||||
**前置条件**:新建报告,填写部分内容
|
||||
**操作步骤**:
|
||||
1. 点击打印按钮
|
||||
2. 检查打印预览
|
||||
|
||||
**预期结果**:
|
||||
- 抬头排版正确(Logo + 医院名 + 标题)
|
||||
- 基本信息下划线可见
|
||||
- 双列信息左右对齐
|
||||
- 无多余虚线边框(placeholder 填充后 border 应消失)
|
||||
|
||||
---
|
||||
|
||||
## 回归测试范围
|
||||
- 验证 `ReportEditor` 中已有的 `image-placeholder` 点击上传、拖拽填充功能不受影响
|
||||
- 验证 `TemplateManage` 中智能字段插入、删除、撤销/重做功能正常
|
||||
- 验证 `smart-field-wrapper` 双向绑定正常工作
|
||||
|
||||
## 测试结论
|
||||
TC-01~TC-11 全部通过,即可确认三项需求均正确实现。
|
||||
29
工程分析/需求分析-2026-04-18-17-27-51.md
Normal file
29
工程分析/需求分析-2026-04-18-17-27-51.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# 需求分析 —— 2026-04-18-17-27-51
|
||||
|
||||
## 需求来源
|
||||
用户提出 TemplateManage 功能修复与默认报告模板排版重构需求。
|
||||
|
||||
## 需求概述
|
||||
|
||||
### 需求 1:修复 TemplateManage 静态图片占位符插入不显示
|
||||
在 `template-manage` 中通过弹窗选择「静态图片占位」并点击「确认插入」后,编辑器中没有出现 `class="image-placeholder"` 的占位符框。经分析,原因是 `document.execCommand('insertHTML')` 对复杂嵌套 HTML(含 `contenteditable="false"`)的自动修正/过滤行为不可靠。
|
||||
|
||||
### 需求 2:重构默认报告模板顶部排版
|
||||
根据用户提供的视觉参考图片,重写 `defaultContent.ts` 顶部排版:
|
||||
- **抬头**:左侧 Logo(65×65 静态占位),右侧 14 号字体的「西 安 交 通 大 学 第 一 附 属 医 院」(带下划线),下方 16 号字体「手术记录」。
|
||||
- **基本信息栏**:11 号字体、不加粗、带贯穿下划线的一行:姓名、性别、年龄、科别、床号、住院号。
|
||||
- **诊断/手术信息**:12 号字体、加粗的单行:手术日期、术前诊断、术中诊断、手术名称。
|
||||
- **双列信息**:12 号字体、不加粗、两项一行:手术开始/终止时间、手术者/助手、麻醉师/麻醉方式。
|
||||
- **手术步骤标题**:12 号字体、加粗的「手术步骤、术中出现的情况及处理:」。
|
||||
|
||||
### 需求 3:修复顶部 Logo 占位符删除按钮无法点击
|
||||
当前默认模板中 65px×65px 的 Logo 占位符右上角的「×」删除按钮无法点击。原因是占位符缺少 `position: relative`,导致绝对定位的删除按钮点击区域溢出或被遮挡。需保留其「静态图片占位 (`data-mode="manual"`)」逻辑。
|
||||
|
||||
## 涉及文件
|
||||
- `src/pages/TemplateManage.tsx`(需求 1:修复 insertImage 插入方式)
|
||||
- `src/utils/defaultContent.ts`(需求 2、3:重构模板排版 + Logo 修复)
|
||||
|
||||
## 需求影响范围
|
||||
- 模板管理页面的图片占位符插入功能
|
||||
- 新建报告时的默认模板视觉效果
|
||||
- 打印输出时的顶部排版
|
||||
Reference in New Issue
Block a user