2026-04-18-16-55-47 - 报告编辑器field-value点击联动、字段动态排序、默认模板手术图片表格替换
This commit is contained in:
@@ -377,6 +377,27 @@ export default function ReportEditor() {
|
||||
const targetEl = node as HTMLElement | null;
|
||||
if (!targetEl) return;
|
||||
|
||||
// Handle click on field-value: switch to info tab and focus corresponding input
|
||||
const fieldValue = targetEl.closest('.field-value') as HTMLElement | null;
|
||||
if (fieldValue) {
|
||||
const bindKey = fieldValue.getAttribute('data-bind');
|
||||
if (bindKey) {
|
||||
setActiveTab('info');
|
||||
stateRef.current = { ...stateRef.current, activeTab: 'info' };
|
||||
setTimeout(() => {
|
||||
const inputEl = document.getElementById(`input-${bindKey}`);
|
||||
if (inputEl) {
|
||||
inputEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
const focusable = inputEl.querySelector('input, select') as HTMLElement | null;
|
||||
if (focusable) {
|
||||
focusable.focus();
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const placeholder = targetEl.closest('.image-placeholder') as HTMLElement | null;
|
||||
if (!placeholder) return;
|
||||
|
||||
@@ -1366,14 +1387,30 @@ export default function ReportEditor() {
|
||||
<div className="flex-1 overflow-y-auto p-6 space-y-8">
|
||||
{activeTab === 'info' && (
|
||||
<div className="report-info-form space-y-4">
|
||||
{formFields.filter(f => f.visibleInForm).map(field => {
|
||||
{(() => {
|
||||
const topKeys = ['patientName', 'hospitalId', 'title'];
|
||||
const contentHtml = contentRef.current || editorRef.current?.innerHTML || '';
|
||||
return [...formFields.filter(f => f.visibleInForm)].sort((a, b) => {
|
||||
const aTop = topKeys.indexOf(a.key);
|
||||
const bTop = topKeys.indexOf(b.key);
|
||||
if (aTop !== -1 && bTop !== -1) return aTop - bTop;
|
||||
if (aTop !== -1) return -1;
|
||||
if (bTop !== -1) return 1;
|
||||
const aIndex = contentHtml.indexOf(`data-bind="${a.key}"`);
|
||||
const bIndex = contentHtml.indexOf(`data-bind="${b.key}"`);
|
||||
if (aIndex === -1 && bIndex === -1) return 0;
|
||||
if (aIndex === -1) return 1;
|
||||
if (bIndex === -1) return -1;
|
||||
return aIndex - bIndex;
|
||||
});
|
||||
})().map(field => {
|
||||
const isRequired = field.isSystemLocked;
|
||||
const hasError = isRequired && touched[field.key] && !(reportData as any)[field.key];
|
||||
|
||||
if (field.type === 'text' || field.type === 'date') {
|
||||
const inputType = field.type === 'date' ? 'date' : 'text';
|
||||
return (
|
||||
<div key={field.key} className={field.category === '填空' && formFields.filter(f2 => f2.visibleInForm && f2.type === 'text' && f2.isSystemLocked).length > 1 && (field.key === 'patientName' || field.key === 'hospitalId') ? 'flex-1 space-y-1' : 'space-y-1'}>
|
||||
<div key={field.key} id={`input-${field.key}`} className={field.category === '填空' && formFields.filter(f2 => f2.visibleInForm && f2.type === 'text' && f2.isSystemLocked).length > 1 && (field.key === 'patientName' || field.key === 'hospitalId') ? 'flex-1 space-y-1' : 'space-y-1'}>
|
||||
<label className="block text-xs font-bold text-text-main">
|
||||
{field.label} {isRequired && <span className="text-red-500">*</span>}
|
||||
</label>
|
||||
@@ -1393,7 +1430,7 @@ export default function ReportEditor() {
|
||||
const isOpen = openDropdown === field.key;
|
||||
const opts = field.options || (field.key === 'anesthesiaType' ? anesthesiaOptions : []);
|
||||
return (
|
||||
<div key={field.key} className="space-y-1 select-dropdown-root relative">
|
||||
<div key={field.key} id={`input-${field.key}`} className="space-y-1 select-dropdown-root relative">
|
||||
<label className="block text-xs font-bold text-text-main">{field.label}</label>
|
||||
<div
|
||||
className="w-full px-3 py-2 border border-border rounded-lg bg-white flex items-center min-h-[42px] cursor-text"
|
||||
@@ -1502,7 +1539,7 @@ export default function ReportEditor() {
|
||||
const currentInputText = multiInputText[field.key] !== undefined ? multiInputText[field.key] : displayText;
|
||||
|
||||
return (
|
||||
<div key={field.key} className="space-y-1 select-dropdown-root relative">
|
||||
<div key={field.key} id={`input-${field.key}`} className="space-y-1 select-dropdown-root relative">
|
||||
<label className="block text-xs font-bold text-text-main">{field.label}(可多选)</label>
|
||||
<div
|
||||
className="w-full px-3 py-2 border border-border rounded-lg bg-white flex flex-wrap gap-1 items-center min-h-[42px] cursor-text"
|
||||
@@ -1583,7 +1620,7 @@ export default function ReportEditor() {
|
||||
const { h: h12, isPM } = from24h(h24val);
|
||||
|
||||
return (
|
||||
<div key={field.key} className="space-y-1">
|
||||
<div key={field.key} id={`input-${field.key}`} className="space-y-1">
|
||||
<label className="block text-xs font-bold text-text-main">{field.label}</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<select
|
||||
@@ -1640,7 +1677,7 @@ export default function ReportEditor() {
|
||||
const { h: h12g, isPM: isPMg } = from24h(h24);
|
||||
|
||||
return (
|
||||
<div key={field.key} className="space-y-1">
|
||||
<div key={field.key} id={`input-${field.key}`} className="space-y-1">
|
||||
<label className="block text-xs font-bold text-text-main">{field.label}</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<select
|
||||
|
||||
@@ -87,47 +87,47 @@ export const defaultReportContent = `
|
||||
<table style="width: 100%; border-collapse: collapse; margin: 20px 0; table-layout: fixed;">
|
||||
<tbody><tr>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="border: 1px dashed #cbd5e1; background: #f8fafc; width: 100%; height: 100%; max-width: 200px; max-height: 200px; min-height: 60px; margin: 0px auto; display: flex; align-items: center; justify-content: center; 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>
|
||||
</div>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图A 腹腔镜探查</p>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="border: 1px dashed #cbd5e1; background: #f8fafc; width: 100%; height: 100%; max-width: 200px; max-height: 200px; min-height: 60px; margin: 0px auto; display: flex; align-items: center; justify-content: center; 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>
|
||||
</div>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图B 胆囊管夹闭与离断</p>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="border: 1px dashed #cbd5e1; background: #f8fafc; width: 100%; height: 100%; max-width: 200px; max-height: 200px; min-height: 60px; margin: 0px auto; display: flex; align-items: center; justify-content: center; 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>
|
||||
</div>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图C 胆囊动脉夹闭与离断</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="border: 1px dashed #cbd5e1; background: #f8fafc; width: 100%; height: 100%; max-width: 200px; max-height: 200px; min-height: 60px; margin: 0px auto; display: flex; align-items: center; justify-content: center; 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>
|
||||
</div>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图D 胆囊剥离与床面止血</p>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="border: 1px dashed #cbd5e1; background: #f8fafc; width: 100%; height: 100%; max-width: 200px; max-height: 200px; min-height: 60px; margin: 0px auto; display: flex; align-items: center; justify-content: center; 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>
|
||||
</div>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图E 胆囊取出与钛夹确认</p>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false" data-mode="frame" style="border: 1px dashed #cbd5e1; background: #f8fafc; width: 100%; height: 100%; max-width: 200px; max-height: 200px; min-height: 60px; margin: 0px auto; display: flex; align-items: center; justify-content: center; 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>
|
||||
</div>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图F 止血材料覆盖及检查</p>
|
||||
</td>
|
||||
</tr></tbody>
|
||||
|
||||
56
工程分析/实现方案-2026-04-18-16-55-47.md
Normal file
56
工程分析/实现方案-2026-04-18-16-55-47.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 实现方案 —— 2026-04-18-16-55-47
|
||||
|
||||
## 方案目标
|
||||
实现 report-editor 中正文与侧边栏的点击联动、字段动态排序、以及默认模板的手术图片表格替换。
|
||||
|
||||
## 需求 1:点击 field-value 联动右侧基本信息
|
||||
|
||||
### 实现步骤
|
||||
1. **修改 `handleEditorClick`**:在 `ReportEditor.tsx` 的 `handleEditorClick` 函数中,增加对 `.field-value` 的点击捕获。
|
||||
- 通过 `e.target.closest('.field-value')` 获取被点击的 field-value 元素。
|
||||
- 读取其 `data-bind` 属性值(如 `patientName`)。
|
||||
2. **切换 Tab**:调用 `setActiveTab('info')` 将右侧面板切回「基本信息」。
|
||||
3. **聚焦与滚动**:
|
||||
- 为右侧表单中的每个输入组件增加 `id={\`input-\${field.key}\`}`。
|
||||
- 使用 `setTimeout` 等待 React DOM 渲染完成后,通过 `document.getElementById(\`input-\${bindKey}\`)` 获取对应元素。
|
||||
- 调用 `scrollIntoView({ behavior: 'smooth', block: 'center' })` 并 `focus()`。
|
||||
|
||||
## 需求 2:右侧基本信息字段按正文出现顺序动态排序
|
||||
|
||||
### 实现步骤
|
||||
1. **提取正文字段顺序**:
|
||||
- 使用 `contentRef.current`(当前编辑器 HTML 字符串)或 `editorRef.current?.innerHTML`。
|
||||
- 对 `formFields.filter(f => f.visibleInForm)` 中的每个非置顶字段,计算 `data-bind="${field.key}"` 在 HTML 中的首次出现位置(`indexOf`)。
|
||||
2. **排序策略**:
|
||||
- **置顶组**:`const topKeys = ['patientName', 'hospitalId', 'title'];`,按此固定顺序排列。
|
||||
- **正文组**:非置顶字段,按 `indexOf` 升序排列(越早出现越靠前)。
|
||||
- **末尾组**:正文中未出现的字段(`indexOf === -1`),统一排在最后,保持原有相对顺序。
|
||||
3. **渲染表单**:将排序后的字段数组直接用于右侧表单 `.map()` 渲染。
|
||||
|
||||
### 性能优化
|
||||
- 使用 `useMemo` 缓存排序结果,仅在 `formFields` 或编辑器内容变化时重新计算。
|
||||
- 排序逻辑放在 `useMemo` 中,避免每次渲染重复计算。
|
||||
|
||||
## 需求 3:替换默认手术图片说明表格
|
||||
|
||||
### 实现步骤
|
||||
1. 定位 `src/utils/defaultContent.ts` 中的 `defaultReportContent`。
|
||||
2. 找到 `<!-- 手术图片说明表格 -->` 注释所在的 `<table>` 区域。
|
||||
3. 替换为用户提供的 HTML 代码:
|
||||
- 2 行 × 3 列布局
|
||||
- 每格包含 `.image-placeholder`(表格内模式:`<div>` 块级容器,`width:100%; height:100%; max-width:200px; max-height:200px;`)
|
||||
- 每格底部含图注(图A~图F)
|
||||
- 保留 `data-placeholder="true"` 和 `contenteditable="false"`
|
||||
4. 清理复制时产生的冗余内联样式(如 `background-image: initial` 等),保留功能必需的样式。
|
||||
|
||||
## 涉及文件及修改点
|
||||
| 文件 | 修改点 |
|
||||
|------|--------|
|
||||
| `src/pages/ReportEditor.tsx` | `handleEditorClick` 增加 field-value 点击捕获;表单渲染增加 `id`;右侧字段排序逻辑 |
|
||||
| `src/utils/defaultContent.ts` | 替换手术图片说明表格 HTML |
|
||||
|
||||
## 风险与注意事项
|
||||
1. `contentRef.current` 在组件首次挂载前可能为空,排序逻辑需做空值保护。
|
||||
2. `setActiveTab` 后 DOM 切换有短暂延迟,`scrollIntoView` 需包裹在 `setTimeout` 中。
|
||||
3. 默认模板替换后,需验证新建报告时表格渲染是否正常、占位符点击事件是否生效。
|
||||
4. 置顶字段的 `key` 名称需与 `DEFAULT_FORM_FIELDS` 中严格一致。
|
||||
123
工程分析/测试方案-2026-04-18-16-55-47.md
Normal file
123
工程分析/测试方案-2026-04-18-16-55-47.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# 测试方案 —— 2026-04-18-16-55-47
|
||||
|
||||
## 测试目标
|
||||
验证 report-editor 的三项改进是否正确实现:field-value 点击联动、右侧字段动态排序、默认模板表格替换。
|
||||
|
||||
## 测试用例
|
||||
|
||||
### TC-01:点击正文 field-value 切换至基本信息 Tab 并聚焦
|
||||
**前置条件**:进入 /report-editor,加载默认模板,右侧当前在「视频分析」Tab
|
||||
**操作步骤**:
|
||||
1. 点击报告正文中「姓名」后的 field-value 方格
|
||||
2. 观察右侧 Tab 切换
|
||||
3. 观察页面滚动位置
|
||||
|
||||
**预期结果**:
|
||||
- 右侧 Tab 自动从「视频分析」切换为「基本信息」
|
||||
- 页面平滑滚动至「患者姓名」输入框位置
|
||||
- 「患者姓名」输入框获得焦点
|
||||
|
||||
---
|
||||
|
||||
### TC-02:点击不同 field-value 聚焦对应不同表单字段
|
||||
**前置条件**:report-editor 已加载模板
|
||||
**操作步骤**:
|
||||
1. 点击正文中的「住院号」field-value
|
||||
2. 点击正文中的「手术名称」field-value
|
||||
3. 点击正文中的「手术日期」field-value
|
||||
|
||||
**预期结果**:
|
||||
- 每次点击后右侧均切换至「基本信息」Tab
|
||||
- 对应字段输入框均被聚焦并滚动至可视区域
|
||||
|
||||
---
|
||||
|
||||
### TC-03:置顶字段顺序验证
|
||||
**前置条件**:report-editor 右侧显示基本信息表单
|
||||
**操作步骤**:
|
||||
1. 查看右侧表单字段的从上到下顺序
|
||||
|
||||
**预期结果**:
|
||||
- 第1个字段为「患者姓名」
|
||||
- 第2个字段为「住院号」
|
||||
- 第3个字段为「手术名称」
|
||||
- 这三个字段始终固定在最上方
|
||||
|
||||
---
|
||||
|
||||
### TC-04:动态排序验证——按正文出现顺序
|
||||
**前置条件**:默认模板中正文字段有固定出现顺序
|
||||
**操作步骤**:
|
||||
1. 查看右侧表单第4个及之后的字段顺序
|
||||
2. 对比正文中 `data-bind` 的首次出现顺序
|
||||
|
||||
**预期结果**:
|
||||
- 右侧第4个及之后的字段顺序与正文中 `data-bind` 首次出现的先后顺序一致
|
||||
- 正文中越靠前的字段,在右侧表单中也越靠前
|
||||
|
||||
---
|
||||
|
||||
### TC-05:动态排序验证——修改正文后排序更新
|
||||
**前置条件**:report-editor 中已加载默认模板
|
||||
**操作步骤**:
|
||||
1. 将正文中某个靠后的字段(如「术后诊断」)剪切并粘贴到正文开头
|
||||
2. 观察右侧表单字段顺序变化
|
||||
|
||||
**预期结果**:
|
||||
- 「术后诊断」在右侧表单中的位置相应提前
|
||||
- 排序随正文内容变化实时更新
|
||||
|
||||
---
|
||||
|
||||
### TC-06:默认模板手术图片表格验证
|
||||
**前置条件**:新建报告或重置系统后进入 report-editor
|
||||
**操作步骤**:
|
||||
1. 查看编辑器中的「手术图片说明表格」
|
||||
2. 检查每个单元格内容
|
||||
|
||||
**预期结果**:
|
||||
- 表格为 2 行 × 3 列布局
|
||||
- 每格包含 `image-placeholder` 占位符
|
||||
- 每格底部有对应图注(图A~图F)
|
||||
- 占位符可正常点击上传图片
|
||||
|
||||
---
|
||||
|
||||
### TC-07:表格内占位符图片上传
|
||||
**前置条件**:默认模板已加载
|
||||
**操作步骤**:
|
||||
1. 点击表格中某个 `image-placeholder`
|
||||
2. 在弹窗中选择本地上传一张图片
|
||||
3. 确认图片正确填充到占位符中
|
||||
|
||||
**预期结果**:
|
||||
- 弹窗正常出现(三选一:本地上传/我的签名/系统素材)
|
||||
- 图片正确显示在占位符内
|
||||
- 图片不溢出单元格边界
|
||||
|
||||
---
|
||||
|
||||
### TC-08:新建报告默认内容完整性
|
||||
**前置条件**:退出并重新登录,确保系统使用默认模板
|
||||
**操作步骤**:
|
||||
1. 进入 /report-editor(新建报告)
|
||||
2. 检查整个报告内容
|
||||
|
||||
**预期结果**:
|
||||
- 报告头部 Logo 和标题正常
|
||||
- 基本信息段落正常
|
||||
- 手术步骤段落正常
|
||||
- 手术图片说明表格为新模板
|
||||
- 手术后情况段落正常
|
||||
- 底部撰写时间字段正常
|
||||
|
||||
---
|
||||
|
||||
## 回归测试范围
|
||||
- 验证 `image-placeholder` 的拖拽填充、点击上传、删除功能不受影响
|
||||
- 验证右侧 Tab 手动切换(「基本信息」↔「视频分析」)正常
|
||||
- 验证 `smart-field-wrapper` 的双向绑定(表单→正文、正文→表单)正常
|
||||
- 验证打印功能中表格和图片正常显示
|
||||
|
||||
## 测试结论
|
||||
以上 TC-01~TC-08 全部通过,即可确认三项需求均正确实现。
|
||||
27
工程分析/需求分析-2026-04-18-16-55-47.md
Normal file
27
工程分析/需求分析-2026-04-18-16-55-47.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# 需求分析 —— 2026-04-18-16-55-47
|
||||
|
||||
## 需求来源
|
||||
用户直接提出三项 report-editor 相关改进需求。
|
||||
|
||||
## 需求概述
|
||||
|
||||
### 需求 1:点击正文 field-value 联动右侧基本信息
|
||||
在 `report-editor` 中,点击报告正文内 `class="field-value"` 的元素时,自动将右侧面板切换至「基本信息」栏目,并聚焦/滚动到该字段对应的表单输入框。
|
||||
|
||||
### 需求 2:右侧基本信息字段按正文出现顺序动态排序
|
||||
右侧「基本信息」栏目中:
|
||||
- **固定置顶**:患者姓名 (`patientName`)、住院号 (`hospitalId`)、手术名称 (`title`) 始终排在最上方,顺序固定。
|
||||
- **动态排序**:其余字段按其在报告正文 HTML 中 `data-bind` 出现的先后顺序排列。
|
||||
- **兜底处理**:正文中未出现的字段排在末尾。
|
||||
|
||||
### 需求 3:替换默认模板中的手术图片说明表格
|
||||
将 `src/utils/defaultContent.ts` 中的 `<!-- 手术图片说明表格 -->` 默认模板替换为用户提供的 6 图格 HTML 代码(含腹腔镜探查、胆囊管夹闭与离断、胆囊动脉夹闭与离断、胆囊剥离与床面止血、胆囊取出与钛夹确认、止血材料覆盖及检查)。
|
||||
|
||||
## 涉及文件
|
||||
- `src/pages/ReportEditor.tsx`(需求 1、2)
|
||||
- `src/utils/defaultContent.ts`(需求 3)
|
||||
|
||||
## 需求影响范围
|
||||
- 报告编辑器交互体验
|
||||
- 右侧基本信息面板渲染逻辑
|
||||
- 默认报告模板内容
|
||||
Reference in New Issue
Block a user