2026-04-18-18-08-37 - 编辑器工具栏新增字号行距选择、修复字体选择、模板排版间距调整
This commit is contained in:
@@ -505,6 +505,19 @@ export default function ReportEditor() {
|
||||
saveDraftToStorage();
|
||||
};
|
||||
|
||||
const changeLineHeight = (height: string) => {
|
||||
const sel = window.getSelection();
|
||||
if (!sel || !sel.rangeCount) return;
|
||||
let node = sel.getRangeAt(0).commonAncestorContainer;
|
||||
if (node.nodeType === Node.TEXT_NODE) node = node.parentNode as Node;
|
||||
const block = (node as HTMLElement).closest('p, div, td, h1, h2, h3, li');
|
||||
if (block) {
|
||||
(block as HTMLElement).style.lineHeight = height;
|
||||
if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
|
||||
saveDraftToStorage();
|
||||
}
|
||||
};
|
||||
|
||||
const insertTable = () => {
|
||||
editorRef.current?.focus();
|
||||
setTableModal({ isOpen: true, rows: '2', cols: '3' });
|
||||
@@ -1313,6 +1326,7 @@ export default function ReportEditor() {
|
||||
</div>
|
||||
<div className="flex gap-1 pr-3 mr-3 border-r border-border">
|
||||
<select
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onChange={(e) => { execCmd('fontName', e.target.value); e.target.value = ''; }}
|
||||
className="h-9 px-3 border border-border rounded-lg text-xs bg-white cursor-pointer focus:outline-hidden focus:border-accent"
|
||||
>
|
||||
@@ -1322,6 +1336,27 @@ export default function ReportEditor() {
|
||||
<option value="SimHei">黑体</option>
|
||||
<option value="KaiTi">楷体</option>
|
||||
</select>
|
||||
<select
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onChange={(e) => { if (e.target.value) { execCmd('fontSize', e.target.value); } e.target.value = ''; }}
|
||||
className="h-9 px-3 border border-border rounded-lg text-xs bg-white cursor-pointer focus:outline-hidden focus:border-accent"
|
||||
>
|
||||
<option value="">字号</option>
|
||||
<option value="3">12pt</option>
|
||||
<option value="4">14pt</option>
|
||||
<option value="5">18pt</option>
|
||||
<option value="6">24pt</option>
|
||||
</select>
|
||||
<select
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onChange={(e) => { if (e.target.value) { changeLineHeight(e.target.value); } e.target.value = ''; }}
|
||||
className="h-9 px-3 border border-border rounded-lg text-xs bg-white cursor-pointer focus:outline-hidden focus:border-accent"
|
||||
>
|
||||
<option value="">行距</option>
|
||||
<option value="1">1.0</option>
|
||||
<option value="1.5">1.5</option>
|
||||
<option value="2">2.0</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex gap-1 pr-3 mr-3 border-r border-border">
|
||||
<button onClick={() => execCmd('bold')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="粗体"><Bold size={16} /></button>
|
||||
|
||||
@@ -359,6 +359,18 @@ export default function TemplateManage() {
|
||||
editorRef.current?.focus();
|
||||
};
|
||||
|
||||
const changeLineHeight = (height: string) => {
|
||||
const sel = window.getSelection();
|
||||
if (!sel || !sel.rangeCount) return;
|
||||
let node = sel.getRangeAt(0).commonAncestorContainer;
|
||||
if (node.nodeType === Node.TEXT_NODE) node = node.parentNode as Node;
|
||||
const block = (node as HTMLElement).closest('p, div, td, h1, h2, h3, li');
|
||||
if (block) {
|
||||
(block as HTMLElement).style.lineHeight = height;
|
||||
saveTemplateContent();
|
||||
}
|
||||
};
|
||||
|
||||
const saveTemplateContent = () => {
|
||||
if (!currentTemplateId || !editorRef.current) return;
|
||||
const allTemplates = storage.get<Template[]>('templates', []);
|
||||
@@ -739,6 +751,27 @@ export default function TemplateManage() {
|
||||
<option value="SimHei">黑体</option>
|
||||
<option value="KaiTi">楷体</option>
|
||||
</select>
|
||||
<select
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onChange={(e) => { if (e.target.value) { execCmd('fontSize', e.target.value); } e.target.value = ''; }}
|
||||
className="h-9 px-3 border border-border rounded-lg text-xs bg-white cursor-pointer focus:outline-hidden focus:border-accent"
|
||||
>
|
||||
<option value="">字号</option>
|
||||
<option value="3">12pt</option>
|
||||
<option value="4">14pt</option>
|
||||
<option value="5">18pt</option>
|
||||
<option value="6">24pt</option>
|
||||
</select>
|
||||
<select
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onChange={(e) => { if (e.target.value) { changeLineHeight(e.target.value); } e.target.value = ''; }}
|
||||
className="h-9 px-3 border border-border rounded-lg text-xs bg-white cursor-pointer focus:outline-hidden focus:border-accent"
|
||||
>
|
||||
<option value="">行距</option>
|
||||
<option value="1">1.0</option>
|
||||
<option value="1.5">1.5</option>
|
||||
<option value="2">2.0</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex gap-1 pr-3 mr-3 border-r border-border">
|
||||
<button onMouseDown={(e) => e.preventDefault()} onClick={() => execCmd('bold')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="粗体"><Bold size={16} /></button>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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 = `
|
||||
<div style="display: flex; justify-content: center; align-items: center; gap: 12px; margin-bottom: 16px;">
|
||||
<div style="display: flex; justify-content: center; align-items: center; gap: 12px; margin-bottom: 4px;">
|
||||
<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>
|
||||
@@ -34,7 +34,7 @@ export const defaultReportContent = `
|
||||
<strong>手术名称:</strong>${smartField('title')}
|
||||
</p>
|
||||
|
||||
<table style="width: 100%; border: none; font-family: SimSun; font-size: 12pt; margin-bottom: 12pt;">
|
||||
<table style="width: 100%; border: none; font-family: SimSun; font-size: 12pt; margin-top: 0; margin-bottom: 0;">
|
||||
<tr>
|
||||
<td style="border: none; padding: 0; width: 50%; line-height: 1.5;">手术开始时间:${smartField('startTime')}</td>
|
||||
<td style="border: none; padding: 0; width: 50%; line-height: 1.5;">手术终止时间:${smartField('endTime')}</td>
|
||||
@@ -53,23 +53,23 @@ export const defaultReportContent = `
|
||||
<strong>手术步骤、术中出现的情况及处理:</strong>
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
1.患者仰卧位,麻醉成功后,常规消毒术野、铺无菌巾,于脐下穿刺建立CO2气腹,气腹压力为12mmHg,进镜探查无穿刺损伤,分别于剑突下2.0cm、右锁中线肋缘下2.0cm各点穿刺置穿刺器,插入相应手术器械。
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
2.腹腔镜探查:腹腔内无腹水形成,无明显粘连,肝脏色红质软,无明显结节硬化改变,胆囊大小约 cm× cm× cm,壁轻度水肿,张力可,胆囊三角解剖关系清楚,胆囊管及胆总管无明显扩张。胃、十二指肠、小肠、结肠、脾脏及盆腔未见明显异常。术中诊断:胆囊结石伴慢性胆囊炎。遂行腹腔镜胆囊切除术。
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
3.切除胆囊:钳夹胆囊颈部并解剖胆囊三角,游离出胆囊动脉及胆囊管,明确胆囊与胆总管的关系,距胆总管0.3cm处近端以一枚可吸收夹,远端夹一枚钛夹夹闭胆囊管,两夹间以剪刀剪断胆囊管,另用一枚可吸收夹夹闭胆囊动脉后离断。顺行游离胆囊浆膜,完整切除胆囊后装入标本袋取出。胆囊床严密止血并覆盖止血材料。
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
4.检查腹腔内无活动性出血及漏胆后,清点器械纱布无误,拔除腔镜器械,排出腹腔残余气体,缝合各刺孔,术毕。
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
5.手术顺利,麻醉满意。切除的标本经家属过目后送病理。术中出血约 ml,术中输血成分,输血量,是否有输血不良反应。
|
||||
</p>
|
||||
|
||||
@@ -124,23 +124,23 @@ export const defaultReportContent = `
|
||||
</table>
|
||||
|
||||
<div class="template-info-section">
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<strong>手术后情况</strong>:${smartField('postOpCondition')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<strong>切除标本描述</strong>:${smartField('specimenDescription')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<strong>是否送病理检查</strong>:${smartField('pathologyCheck')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<strong>冰冻病理结果</strong>:${smartField('frozenPathology')}
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun; line-height: 1.5; margin: 0; padding: 0;">
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
手术者签名:<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="manual" style="display:inline-flex;align-items:center;justify-content:center;width:200px;height:40px;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>
|
||||
|
||||
|
||||
91
工程分析/实现方案-2026-04-18-18-08-37.md
Normal file
91
工程分析/实现方案-2026-04-18-18-08-37.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# 实现方案 —— 2026-04-18-18-08-37
|
||||
|
||||
## 方案目标
|
||||
修复并增强编辑器工具栏的字体/字号/行距功能,调整默认模板排版细节。
|
||||
|
||||
## 需求 1:修复字体选择并新增字号、行距功能
|
||||
|
||||
### 修改文件
|
||||
`src/pages/ReportEditor.tsx` 和 `src/pages/TemplateManage.tsx`
|
||||
|
||||
### 实现步骤
|
||||
1. **修复字体选择**:确保工具栏中的字体选择 `<select>` 使用 `execCmd('fontName', value)`。若失效,检查是否有全局 CSS `font-family: !important` 覆盖。如有,在打印样式中保留覆盖,但在编辑器样式中移除。
|
||||
2. **新增字号选择**:在工具栏字体选择旁边增加 `<select>`:
|
||||
```tsx
|
||||
<select onChange={e => { if (e.target.value) { execCmd('fontSize', e.target.value); } e.target.value = ''; }}>
|
||||
<option value="">字号</option>
|
||||
<option value="3">12pt</option>
|
||||
<option value="4">14pt</option>
|
||||
<option value="5">18pt</option>
|
||||
</select>
|
||||
```
|
||||
`execCommand('fontSize')` 使用 1-7 的相对字号,3 对应 12pt,4 对应 14pt,5 对应 18pt。
|
||||
3. **新增行距选择**:`execCommand` 不支持行距,需手写 `changeLineHeight` 函数:
|
||||
```tsx
|
||||
const changeLineHeight = (height: string) => {
|
||||
const sel = window.getSelection();
|
||||
if (!sel || !sel.rangeCount) return;
|
||||
let node = sel.getRangeAt(0).commonAncestorContainer;
|
||||
if (node.nodeType === Node.TEXT_NODE) node = node.parentNode as Node;
|
||||
const block = (node as HTMLElement).closest('p, div, td, h1, h2, h3');
|
||||
if (block) {
|
||||
(block as HTMLElement).style.lineHeight = height;
|
||||
if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
|
||||
saveDraftToStorage();
|
||||
}
|
||||
};
|
||||
```
|
||||
在工具栏增加行距 `<select>` 绑定此函数。
|
||||
|
||||
## 需求 2:修复手术者签名右对齐时图片框换行
|
||||
|
||||
### 修改文件
|
||||
`src/utils/defaultContent.ts`
|
||||
|
||||
### 修改内容
|
||||
将「手术者签名」所在 `<p>` 增加 `white-space: nowrap;`,并将图片占位符的 `display` 改为 `inline-block`:
|
||||
```html
|
||||
<p style="text-align: right; font-family: SimSun; line-height: 1.5; margin: 0; padding: 0; white-space: nowrap;">
|
||||
手术者签名:<span class="image-placeholder" ... style="display:inline-block; vertical-align:middle; ...">...</span>
|
||||
</p>
|
||||
```
|
||||
|
||||
## 需求 3:缩减「手术记录」与「姓名」之间的距离
|
||||
|
||||
### 修改文件
|
||||
`src/utils/defaultContent.ts`
|
||||
|
||||
### 修改内容
|
||||
将顶部 Flex 容器的 `margin-bottom: 16px` 缩小为 `margin-bottom: 4px`。
|
||||
|
||||
## 需求 4:消除「手术名称」与「手术开始时间」之间的多余间距
|
||||
|
||||
### 修改文件
|
||||
`src/utils/defaultContent.ts`
|
||||
|
||||
### 修改内容
|
||||
将双列信息 `<table>` 的 `margin-bottom: 12pt` 改为 `margin-bottom: 0; margin-top: 0;`。同时确保「手术名称」`<p>` 的 `margin: 0; padding: 0;`。
|
||||
|
||||
## 需求 5:统一「手术日期」及以下内容为 12pt、1.5 行距、无段间距
|
||||
|
||||
### 修改文件
|
||||
`src/utils/defaultContent.ts`
|
||||
|
||||
### 修改内容
|
||||
为所有手术步骤段落(1~5)以及手术后情况段落补充 `font-size: 12pt;`:
|
||||
```html
|
||||
<p style="font-family: SimSun; font-size: 12pt; line-height: 1.5; margin: 0; padding: 0;">
|
||||
```
|
||||
|
||||
## 涉及文件及修改点
|
||||
| 文件 | 修改点 |
|
||||
|------|--------|
|
||||
| `src/pages/ReportEditor.tsx` | 工具栏新增字号选择、行距选择;修复字体选择 |
|
||||
| `src/pages/TemplateManage.tsx` | 工具栏新增字号选择、行距选择;修复字体选择 |
|
||||
| `src/utils/defaultContent.ts` | 签名行 `white-space: nowrap`; 顶部 `margin-bottom: 4px`; 表格 `margin: 0`; 补全 `font-size: 12pt` |
|
||||
|
||||
## 风险与注意事项
|
||||
1. `execCommand('fontSize')` 生成的是 `<font size="N">` 标签,与现代 HTML5 规范不完全兼容,但在 `contentEditable` 中是浏览器广泛支持的方式。
|
||||
2. `changeLineHeight` 直接操作 DOM style,在 `ReportEditor` 中修改后需同步 `contentRef.current` 和调用 `saveDraftToStorage()`。
|
||||
3. `TemplateManage` 中修改行距后需调用 `saveTemplateContent()`。
|
||||
4. `white-space: nowrap` 在签名行可能导致超长内容溢出,但考虑到签名行通常较短,风险可控。
|
||||
134
工程分析/测试方案-2026-04-18-18-08-37.md
Normal file
134
工程分析/测试方案-2026-04-18-18-08-37.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# 测试方案 —— 2026-04-18-18-08-37
|
||||
|
||||
## 测试目标
|
||||
验证编辑器工具栏字号/行距功能、字体选择修复,以及默认模板排版调整。
|
||||
|
||||
## 测试用例
|
||||
|
||||
### TC-01:ReportEditor 字体选择修复
|
||||
**前置条件**:进入 /report-editor,编辑器中有文字
|
||||
**操作步骤**:
|
||||
1. 选中一段文字
|
||||
2. 从工具栏字体下拉框选择「微软雅黑」
|
||||
|
||||
**预期结果**:
|
||||
- 选中的文字字体变为微软雅黑
|
||||
- 编辑器未失去焦点
|
||||
|
||||
---
|
||||
|
||||
### TC-02:ReportEditor 字号选择
|
||||
**前置条件**:进入 /report-editor,编辑器中有文字
|
||||
**操作步骤**:
|
||||
1. 选中一段文字
|
||||
2. 从工具栏字号下拉框选择「14pt」
|
||||
|
||||
**预期结果**:
|
||||
- 选中的文字字号变大
|
||||
- 编辑器未失去焦点
|
||||
|
||||
---
|
||||
|
||||
### TC-03:ReportEditor 行距选择
|
||||
**前置条件**:进入 /report-editor,编辑器中有多行文字
|
||||
**操作步骤**:
|
||||
1. 将光标放在某一段落内
|
||||
2. 从工具栏行距下拉框选择「2.0」
|
||||
|
||||
**预期结果**:
|
||||
- 当前段落行距变为 2.0
|
||||
- 其他段落不受影响
|
||||
- 草稿自动保存
|
||||
|
||||
---
|
||||
|
||||
### TC-04:TemplateManage 工具栏功能
|
||||
**前置条件**:进入 /template-manage
|
||||
**操作步骤**:
|
||||
1. 分别测试字体、字号、行距选择功能
|
||||
|
||||
**预期结果**:
|
||||
- 字体选择生效
|
||||
- 字号选择生效
|
||||
- 行距选择生效
|
||||
- 撤销/重做能恢复行距修改
|
||||
|
||||
---
|
||||
|
||||
### TC-05:手术者签名右对齐不换行
|
||||
**前置条件**:新建报告,加载默认模板
|
||||
**操作步骤**:
|
||||
1. 找到「手术者签名」行
|
||||
2. 将光标放在该行,点击工具栏「右对齐」
|
||||
|
||||
**预期结果**:
|
||||
- 「手术者签名:」文字和图片占位符在同一行
|
||||
- 两者一起靠右对齐
|
||||
- 图片框不会单独换到下一行
|
||||
|
||||
---
|
||||
|
||||
### TC-06:手术记录与姓名间距
|
||||
**前置条件**:新建报告,加载默认模板
|
||||
**操作步骤**:
|
||||
1. 查看「手术记录」标题与「姓名:」之间的间距
|
||||
|
||||
**预期结果**:
|
||||
- 间距明显缩小(约 4px)
|
||||
- 不再有过大的空白区域
|
||||
|
||||
---
|
||||
|
||||
### TC-07:手术名称与手术开始时间间距
|
||||
**前置条件**:新建报告,加载默认模板
|
||||
**操作步骤**:
|
||||
1. 查看「手术名称」与「手术开始时间」之间的间距
|
||||
|
||||
**预期结果**:
|
||||
- 两者间距仅为 1.5 行距的自然间距
|
||||
- 无额外 margin/padding 造成的空白
|
||||
|
||||
---
|
||||
|
||||
### TC-08:手术步骤段落字体统一
|
||||
**前置条件**:新建报告,加载默认模板
|
||||
**操作步骤**:
|
||||
1. 查看手术步骤 1~5 的字体大小
|
||||
|
||||
**预期结果**:
|
||||
- 所有手术步骤段落均为 12pt 字体
|
||||
- 与上方「手术日期」等诊断信息字体大小一致
|
||||
|
||||
---
|
||||
|
||||
### TC-09:手术后情况段落字体
|
||||
**前置条件**:新建报告,加载默认模板
|
||||
**操作步骤**:
|
||||
1. 查看「手术后情况」「切除标本描述」等段落的字体大小
|
||||
|
||||
**预期结果**:
|
||||
- 均为 12pt 字体
|
||||
- 行距 1.5,无段前段后间距
|
||||
|
||||
---
|
||||
|
||||
### TC-10:打印效果验证
|
||||
**前置条件**:报告有内容
|
||||
**操作步骤**:
|
||||
1. 点击打印
|
||||
2. 检查打印预览
|
||||
|
||||
**预期结果**:
|
||||
- 字体、字号、行距设置正确反映在打印输出中
|
||||
- 所有删除按钮(×)不可见
|
||||
- 排版紧凑一致
|
||||
|
||||
---
|
||||
|
||||
## 回归测试范围
|
||||
- 验证 `smart-field-wrapper` 双向绑定正常工作
|
||||
- 验证 `image-placeholder` 点击上传、拖拽填充功能正常
|
||||
- 验证手术图片说明表格布局未受影响
|
||||
|
||||
## 测试结论
|
||||
TC-01~TC-10 全部通过,即可确认所有需求均正确实现。
|
||||
34
工程分析/需求分析-2026-04-18-18-08-37.md
Normal file
34
工程分析/需求分析-2026-04-18-18-08-37.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# 需求分析 —— 2026-04-18-18-08-37
|
||||
|
||||
## 需求来源
|
||||
用户提出报告编辑器与模板管理器的工具栏功能增强,以及默认模板排版细节调整。
|
||||
|
||||
## 需求概述
|
||||
|
||||
### 需求 1:修复字体选择并新增字号、行距功能
|
||||
在 `report-editor` 和 `template-manage` 的工具栏中:
|
||||
- **修复字体选择**:当前 `document.execCommand('fontName')` 可能因浏览器兼容性或 CSS 覆盖而失效,需确保字体选择能正确生效。
|
||||
- **新增字号选择**:在工具栏字体选择旁边增加字号下拉框,支持 12pt/14pt/18pt 等常用字号。
|
||||
- **新增行距选择**:在工具栏增加行距下拉框,支持 1.0/1.5/2.0 等行距。由于 `execCommand` 不原生支持行距,需通过直接修改 DOM 元素的 `style.lineHeight` 实现。
|
||||
|
||||
### 需求 2:修复手术者签名右对齐时图片框换行
|
||||
当「手术者签名」所在行设置 `text-align: right` 时,文字跑到最右侧,而图片占位符(`display: inline-flex`)换到了下一行。需确保文字和图片在同一行内保持连续。
|
||||
|
||||
### 需求 3:缩减「手术记录」与「姓名」之间的距离
|
||||
当前顶部 Flex 容器的 `margin-bottom: 16px` 导致标题与基本信息栏间距过大。需缩小该间距。
|
||||
|
||||
### 需求 4:消除「手术名称」与「手术开始时间」之间的多余间距
|
||||
「手术名称」是 `<p>` 标签,「手术开始时间」在 `<table>` 中。`<table>` 的默认 margin 或 `<p>` 的默认间距导致两者距离过远。需消除多余间距,保持 1.5 行距且无段前段后间距。
|
||||
|
||||
### 需求 5:统一「手术日期」及以下内容为 12pt、1.5 行距、无段间距
|
||||
当前手术步骤段落(1~5)缺少 `font-size: 12pt`,导致与上方诊断信息字体大小不一致。需统一从「手术日期」开始往下的所有正文内容为 12pt、1.5 行距、无段前段后间距。
|
||||
|
||||
## 涉及文件
|
||||
- `src/pages/ReportEditor.tsx`(需求 1:工具栏增强)
|
||||
- `src/pages/TemplateManage.tsx`(需求 1:工具栏增强)
|
||||
- `src/utils/defaultContent.ts`(需求 2~5:模板排版修复)
|
||||
|
||||
## 需求影响范围
|
||||
- 编辑器工具栏交互
|
||||
- 默认报告模板视觉效果
|
||||
- 打印输出样式
|
||||
Reference in New Issue
Block a user