实现诊断报告模板的完整管理功能,包括诊断报告模板的创建、编辑、删除、应用等操作。用户可以通过诊断报告模板快速填充报告内容,提高工作效率。
[常用] 按钮:只显示常用诊断报告模板[全部] 按钮:显示所有诊断报告模板[管理] 按钮:打开诊断报告模板管理对话框DiagnosticReport 页面
├── ReportHeader(报告头部)
├── ReportMain(报告主体)
│ ├── MainContent(左侧,16列)
│ │ ├── 基本信息卡片
│ │ ├── 图像卡片
│ │ ├── 影像所见卡片
│ │ │ ├── 标题:"影像所见"
│ │ │ ├── **【"另存为诊断报告模板"按钮】** ← 🎯 入口1
│ │ │ └── 文本输入框
│ │ └── 诊断意见卡片
│ │ ├── 标题:"影像诊断"
│ │ └── 文本输入框
│ └── SidePanel(右侧,8列)
│ ├── 检查过滤卡片
│ └── **【诊断报告模板卡片】** ← 🎯 主要功能区域
│ ├── 筛选条:[常用] [全部] [管理] ← 🎯 入口2(管理按钮)
│ ├── 搜索框
│ └── 诊断报告模板列表
│ └── 诊断报告模板项(可点击应用)
└── ReportFooter(报告底部)
┌─────────────────────────────────────────────────────────────────────────┐
│ 诊断报告模板管理 [X] │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 左侧:诊断报告模板列表 │ 右侧:编辑区域 │
│ ┌─────────────────────────────┐ │ ┌─────────────────────────────┐ │
│ │ [+ 新建诊断报告模板] │ │ │ 诊断报告模板名称 * │ │
│ │ [标签过滤: 全部 ▼] │ │ │ ┌─────────────────────────┐ │ │
│ │ │ │ │ │ │ │ │
│ │ ┌─────────────────────────┐ │ │ │ └─────────────────────────┘ │ │
│ │ │ 名称 │ 标签 │ 常用 │ │ │ │ │ │
│ │ ├─────────────────────────┤ │ │ │ 影像所见 * │ │
│ │ │ 模板1 │ 胸部 │ ⭐ │ │ │ │ ┌─────────────────────────┐ │ │
│ │ │ 模板2 │ 腹部 │ │ │ │ │ │ │ │ │
│ │ │ ... │ ... │ ... │ │ │ │ │ │ │ │
│ │ └─────────────────────────┘ │ │ │ └─────────────────────────┘ │ │
│ │ │ │ │ │ │
│ │ │ │ │ 诊断意见 * │ │
│ │ │ │ │ ┌─────────────────────────┐ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ │ └─────────────────────────┘ │ │
│ │ │ │ │ │ │
│ │ │ │ │ 标签 │ │
│ │ │ │ │ ┌─────────────────────────┐ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ │ └─────────────────────────┘ │ │
│ │ │ │ │ │ │
│ │ │ │ │ ☐ 设为常用模板 │ │
│ │ │ │ │ │ │
│ └─────────────────────────────┘ │ │ [删除] [保存] │ │
│ │ └─────────────────────────────┘ │
│ │
│ [关闭] │
└─────────────────────────────────────────────────────────────────────────┘
说明:
[新建] 按钮:始终显示,点击后右侧显示空白编辑表单[复制] 按钮:仅在选中模板时显示,点击后复制当前模板(名称自动添加"- 副本"后缀)[删除] 按钮(红色危险按钮):仅在选中模板时显示,点击后删除当前选中的诊断报告模板[删除] 按钮:仅在编辑现有模板时显示,删除当前选中的诊断报告模板[保存] 按钮:保存编辑内容┌─────────────────────────────────────┐
│ 诊断报告模板 [X] │
├─────────────────────────────────────┤
│ 筛选条: │
│ [常用] [全部] [管理] │
│ │
│ 搜索: │
│ ┌─────────────────────────────────┐ │
│ │ 🔍 搜索诊断报告模板... │ │
│ └─────────────────────────────────┘ │
│ │
│ 诊断报告模板列表: │
│ ┌─────────────────────────────────┐ │
│ │ ⭐ 胸部正位诊断报告模板 │ │
│ │ 标签: 胸部 │ │
│ ├─────────────────────────────────┤ │
│ │ 腹部平扫诊断报告模板 │ │
│ │ 标签: 腹部 │ │
│ ├─────────────────────────────────┤ │
│ │ ... │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────┘
说明:
[常用] - 只显示常用诊断报告模板[全部] - 显示所有诊断报告模板[管理] - 打开诊断报告模板管理对话框TemplateManagementModal - 诊断报告模板管理对话框(左右分栏布局)
TemplateListItem - 诊断报告模板列表项组件
TemplatePanel - 诊断报告模板面板(需要完整实现)
FindingsSection - 影像所见区域(需要修改)
templateSlice - 诊断报告模板状态管理(需要完整实现)
templates: ReportTemplate[] - 诊断报告模板列表loading: boolean - 加载状态error: string | null - 错误信息filterMode: 'all' | 'staple' - 筛选模式(全部/常用)searchKeyword: string - 搜索关键词fetchTemplates() - 获取诊断报告模板列表createTemplate(template) - 创建诊断报告模板updateTemplate(id, template) - 更新诊断报告模板deleteTemplate(id) - 删除诊断报告模板setFilterMode(mode) - 设置筛选模式setSearchKeyword(keyword) - 设置搜索关键词fetchTemplatesThunk() - 异步获取诊断报告模板createTemplateThunk(template) - 异步创建诊断报告模板updateTemplateThunk(id, template) - 异步更新诊断报告模板deleteTemplateThunk(id) - 异步删除诊断报告模板findingsSlice - 影像所见状态(需要修改)
saveTemplate() action(保存为诊断报告模板)getReportTemplateList(params?) - 获取诊断报告模板列表createReportTemplate(template) - 创建诊断报告模板updateReportTemplate(templateId, template) - 更新诊断报告模板deleteReportTemplate(templateId) - 删除诊断报告模板ReportTemplate - 诊断报告模板数据结构(已存在)
interface ReportTemplate {
id?: string;
name: string;
findings: string;
impression: string;
tag: string;
staple: boolean;
}
templateSlice.tsTemplateManagementModal 组件[ ] 连接 Redux
[ ] 实现诊断报告模板列表项 TemplateListItem 组件
[ ] 创建组件文件
[ ] 实现列表项布局
[ ] 实现点击应用诊断报告模板功能
[ ] 实现悬停预览
TemplatePanel 组件[ ] 实现应用诊断报告模板功能
[ ] 修改影像所见区域 FindingsSection 组件
[ ] 实现"另存为诊断报告模板"功能
[ ] 连接诊断报告模板编辑对话框
sequenceDiagram
participant U as 用户
participant TP as TemplatePanel
participant TMM as TemplateManagementModal
participant Redux as Redux Store
participant API as Backend API
Note over U,API: 场景1: 查看和应用模板
U->>TP: 打开诊断报告页面
TP->>Redux: dispatch(fetchTemplatesThunk())
Redux->>API: getReportTemplateList()
API-->>Redux: 返回模板列表
Redux-->>TP: 更新模板列表
TP->>U: 显示模板列表
U->>TP: 点击某个模板
TP->>Redux: 获取模板内容
TP->>U: 确认是否应用模板?
U->>TP: 确认
TP->>Redux: dispatch(updateInputValue(findings))
TP->>Redux: dispatch(setDiagnosisDescription(impression))
Redux-->>U: 更新报告内容
Note over U,API: 场景2: 管理模板(新建)
U->>TP: 点击"编辑"按钮
TP->>TMM: 打开模板管理对话框
TMM->>U: 显示左侧模板列表
U->>TMM: 点击"新建模板"
TMM->>TMM: 右侧显示空白编辑表单
U->>TMM: 在右侧填写模板信息
U->>TMM: 点击"保存"
TMM->>TMM: 表单验证
TMM->>Redux: dispatch(createTemplateThunk(template))
Redux->>API: createReportTemplate(template)
API-->>Redux: 返回创建结果
Redux-->>TMM: 更新状态
TMM->>U: 显示成功提示
TMM->>Redux: 刷新左侧模板列表
TMM->>U: 更新显示
Note over U,API: 场景3: 编辑模板
U->>TMM: 点击左侧列表中的某个模板
TMM->>Redux: 获取模板数据
TMM->>TMM: 右侧显示预填充表单
TMM->>U: 显示模板详情
U->>TMM: 在右侧修改模板信息
U->>TMM: 点击"保存"
TMM->>Redux: dispatch(updateTemplateThunk(id, template))
Redux->>API: updateReportTemplate(id, template)
API-->>Redux: 返回更新结果
Redux-->>TMM: 更新状态
TMM->>U: 显示成功提示
TMM->>U: 刷新左侧列表
Note over U,API: 场景4: 删除模板
U->>TMM: 在右侧点击"删除"按钮
TMM->>U: 显示确认对话框
U->>TMM: 确认删除
TMM->>Redux: dispatch(deleteTemplateThunk(id))
Redux->>API: deleteReportTemplate(id)
API-->>Redux: 返回删除结果
Redux-->>TMM: 更新状态
TMM->>U: 显示成功提示并刷新列表
TMM->>TMM: 右侧清空编辑区域
Note over U,API: 场景5: 另存为模板
U->>U: 填写影像所见和诊断意见
U->>TP: 点击"另存为模板"按钮
TP->>TMM: 打开模板管理对话框
TMM->>Redux: 获取当前报告内容
TMM->>TMM: 右侧显示预填充表单
TMM->>U: 显示预填充的findings和impression
U->>TMM: 补充模板名称等信息
U->>TMM: 点击"保存"
TMM->>Redux: dispatch(createTemplateThunk(template))
Redux->>API: createReportTemplate(template)
API-->>Redux: 返回创建结果
Redux-->>TMM: 更新状态
TMM->>U: 显示成功提示
TMM->>U: 刷新左侧模板列表
graph TB
subgraph "用户界面层"
TP[TemplatePanel]
TMM[TemplateManagementModal<br/>左侧:列表 右侧:编辑区]
FS[FindingsSection]
DS[DiagnosisSection]
end
subgraph "状态管理层"
TS[templateSlice]
FiS[findingsSlice]
DiS[diagnosisSlice]
Store[Redux Store]
end
subgraph "API层"
API[ReportTemplateActions]
end
subgraph "后端"
Backend[Backend Server]
end
%% 查询流程
TP -->|dispatch fetchTemplatesThunk| TS
TMM -->|dispatch fetchTemplatesThunk| TS
TS -->|调用| API
API -->|HTTP GET| Backend
Backend -->|返回数据| API
API -->|返回| TS
TS -->|更新state| Store
Store -->|订阅更新| TP
Store -->|订阅更新| TMM
%% 创建/更新流程
TMM -->|dispatch createTemplateThunk| TS
TMM -->|dispatch updateTemplateThunk| TS
TS -->|调用| API
API -->|HTTP POST/PUT| Backend
Backend -->|返回结果| API
API -->|返回| TS
TS -->|更新state| Store
%% 删除流程
TMM -->|dispatch deleteTemplateThunk| TS
TS -->|调用| API
API -->|HTTP DELETE| Backend
Backend -->|返回结果| API
API -->|返回| TS
%% 应用模板流程
TP -->|应用模板| FiS
TP -->|应用模板| DiS
FiS -->|更新| Store
DiS -->|更新| Store
Store -->|订阅更新| FS
Store -->|订阅更新| DS
%% 另存为模板流程
FS -->|获取当前内容| FiS
FS -->|获取当前内容| DiS
FS -->|打开对话框| TMM
// Redux Store 结构
{
// ... 其他 slices
template: {
templates: ReportTemplate[], // 模板列表
loading: boolean, // 加载状态
error: string | null, // 错误信息
selectedTag: string, // 选中的标签过滤
},
findings: {
diagnosticDescriptionFromImage: string, // 影像所见内容
},
diagnosis: {
diagnosisDescription: string, // 诊断意见内容
},
// ... 其他 slices
}
// 报告模板
export interface ReportTemplate {
id?: string; // 模板ID(可选,创建时不需要)
name: string; // 模板名称
findings: string; // 影像所见内容
impression: string; // 诊断意见内容
tag: string; // 标签(用于分类)
staple: boolean; // 是否为常用模板
}
// 模板查询参数
export interface ReportTemplateQueryParams {
tag?: string; // 按标签过滤
is_staple?: boolean; // 是否只查询常用模板
is_pre_install?: boolean; // 是否只查询预装模板
}
// API响应结构
export interface ReportTemplateResponse {
code: string;
description: string;
solution: string;
data: any;
}
export interface ReportTemplateListResponse {
code: string;
description: string;
solution: string;
data: {
templates: ReportTemplate[];
count?: number;
};
}
// templateSlice state
export interface TemplateState {
templates: ReportTemplate[];
loading: boolean;
error: string | null;
selectedTag: string;
}
// findingsSlice state
export interface FindingsState {
diagnosticDescriptionFromImage: string;
}
// diagnosisSlice state
export interface DiagnosisState {
diagnosisDescription: string;
}
// TemplateEditModal Props
export interface TemplateEditModalProps {
visible: boolean;
template?: ReportTemplate; // 编辑时传入,新建时为undefined
onSave: (template: ReportTemplate) => void;
onCancel: () => void;
}
// TemplateManagementModal Props
export interface TemplateManagementModalProps {
visible: boolean;
onClose: () => void;
}
// TemplateListItem Props
export interface TemplateListItemProps {
template: ReportTemplate;
onClick: (template: ReportTemplate) => void;
}
用户操作: 从患者列表或其他入口进入诊断报告页面
↓
触发: DiagnosticReport 组件挂载
↓
执行: useEffect 初始化报告数据
↓
执行: TemplatePanel 组件挂载
↓
触发: dispatch(fetchTemplatesThunk())
↓
执行: 调用 API 获取模板列表
↓
结果: 模板列表显示在侧边栏
用户操作: 点击 TemplatePanel 中的"管理模板"按钮
↓
触发: 打开 TemplateManagementModal
↓
执行: 显示模板列表(表格形式)
↓
用户可以: 新建/编辑/删除模板
用户操作: 在 FindingsSection 中点击"另存为模板"按钮
↓
触发: 获取当前报告内容(findings + impression)
↓
触发: 打开 TemplateEditModal
↓
执行: 预填充表单(findings 和 impression)
↓
用户操作: 补充模板名称等信息并保存
用户操作: 在 TemplatePanel 中点击某个模板
↓
触发: 检查当前报告是否有内容
↓
如果有内容: 显示确认对话框
↓
用户确认: 应用模板
↓
执行: dispatch(updateInputValue(template.findings))
执行: dispatch(setDiagnosisDescription(template.impression))
↓
结果: 报告内容被模板内容替换
flowchart TD
Start([用户进入诊断报告页面]) --> Init[DiagnosticReport组件初始化]
Init --> LoadTemplates[TemplatePanel加载模板列表]
LoadTemplates --> FetchAPI[调用fetchTemplatesThunk]
FetchAPI --> DisplayList[显示模板列表]
DisplayList --> UserAction{用户操作}
UserAction -->|点击管理模板| OpenManagement[打开TemplateManagementModal]
UserAction -->|点击模板项| ApplyTemplate[应用模板流程]
UserAction -->|点击另存为模板| SaveAsTemplate[另存为模板流程]
OpenManagement --> ManagementActions{管理操作}
ManagementActions -->|新建| CreateNew[打开TemplateEditModal<br/>空表单]
ManagementActions -->|编辑| EditExisting[打开TemplateEditModal<br/>预填充数据]
ManagementActions -->|删除| DeleteConfirm[显示删除确认]
CreateNew --> FillForm[用户填写表单]
EditExisting --> FillForm
FillForm --> Validate{表单验证}
Validate -->|失败| ShowError[显示错误提示]
ShowError --> FillForm
Validate -->|成功| SaveAPI[调用API保存]
SaveAPI --> RefreshList[刷新模板列表]
RefreshList --> DisplayList
DeleteConfirm --> ConfirmDelete{用户确认?}
ConfirmDelete -->|是| CallDeleteAPI[调用deleteTemplateThunk]
ConfirmDelete -->|否| DisplayList
CallDeleteAPI --> RefreshList
ApplyTemplate --> CheckContent{当前有内容?}
CheckContent -->|是| ConfirmApply[显示确认对话框]
CheckContent -->|否| ApplyDirectly[直接应用]
ConfirmApply --> UserConfirm{用户确认?}
UserConfirm -->|是| ApplyDirectly
UserConfirm -->|否| DisplayList
ApplyDirectly --> UpdateFindings[更新影像所见]
UpdateFindings --> UpdateDiagnosis[更新诊断意见]
UpdateDiagnosis --> DisplayList
SaveAsTemplate --> GetCurrentContent[获取当前报告内容]
GetCurrentContent --> OpenEditModal[打开TemplateEditModal<br/>预填充findings和impression]
OpenEditModal --> FillForm
测试步骤:
预期结果:
测试数据:
测试步骤:
预期结果:
测试步骤:
预期结果:
测试步骤:
预期结果:
测试步骤:
预期结果:
测试步骤:
预期结果:
测试步骤:
预期结果:
测试步骤:
预期结果:
测试步骤:
预期结果:
测试步骤:
预期结果:
场景: 后端返回空模板列表 预期: 显示"暂无模板"提示
场景: 网络错误或API返回错误 预期: 显示友好的错误提示,不影响其他功能
场景: 模板内容超过1000字 预期: 正确保存和显示,文本框支持滚动
场景: 模板名称包含特殊字符(如:<>、&、") 预期: 正确转义和显示
场景: 快速连续点击保存按钮 预期: 防抖处理,只发送一次请求
场景: 模板列表包含100+个模板 预期:
场景: 所有操作 预期: 响应时间 < 500ms
场景: API调用期间 预期: 显示加载指示器(Spin)
场景: 创建/编辑/删除成功 预期: 显示Toast提示,3秒后自动消失
场景: 操作失败 预期: 显示清晰的错误信息和解决建议
问题: 多个用户同时编辑同一个模板 影响: 数据覆盖,后保存的覆盖先保存的 解决方案:
问题: API调用失败(网络断开、超时等) 影响: 用户操作失败,体验差 解决方案:
问题: 组件卸载时未清理订阅 影响: 内存占用增加,性能下降 解决方案:
问题: 表单数据与Redux状态不同步 影响: 数据不一致,保存失败 解决方案:
问题: 大量模板导致列表渲染慢 影响: 页面卡顿,用户体验差 解决方案:
问题: 用户快速连续点击保存按钮 影响: 发送多次重复请求 解决方案:
问题: 前端验证不足,后端返回错误 影响: 用户体验差 解决方案:
问题: 某些浏览器不支持特定API 影响: 功能异常 解决方案:
graph TB
subgraph "DiagnosticReport Page"
DR[DiagnosticReport]
RH[ReportHeader]
RM[ReportMain]
RF[ReportFooter]
end
subgraph "ReportMain"
MC[MainContent]
SP[SidePanel]
end
subgraph "MainContent"
BI[BaseInfo]
IL[ImageList]
FS[FindingsSection]
DS[DiagnosisSection]
end
subgraph "SidePanel"
SF[StudyFilter]
TP[TemplatePanel]
end
subgraph "TemplatePanel"
TPList[模板列表]
TPFilter[标签过滤]
TPManage[管理模板按钮]
end
subgraph "Modals"
TMM[TemplateManagementModal<br/>左:列表 右:编辑]
end
DR --> RH
DR --> RM
DR --> RF
RM --> MC
RM --> SP
MC --> BI
MC --> IL
MC --> FS
MC --> DS
SP --> SF
SP --> TP
TP --> TPList
TP --> TPFilter
TP --> TPManage
TPManage -.打开.-> TMM
FS -.打开.-> TMM
TPList -.应用模板.-> FS
TPList -.应用模板.-> DS
// templateSlice.ts
export const fetchTemplatesThunk = createAsyncThunk(
'template/fetchTemplates',
async (params?: ReportTemplateQueryParams, { rejectWithValue }) => {
try {
const response = await getReportTemplateList(params);
return response.data.templates;
} catch (error: any) {
return rejectWithValue(error.message);
}
}
);
export const createTemplateThunk = createAsyncThunk(
'template/createTemplate',
async (template: ReportTemplate, { rejectWithValue }) => {
try {
const response = await createReportTemplate(template);
return response.data;
} catch (error: any) {
return rejectWithValue(error.message);
}
}
);
const validateTemplate = (template: ReportTemplate): string[] => {
const errors: string[] = [];
if (!template.name || template.name.trim() === '') {
errors.push('模板名称不能为空');
}
if (template.name && template.name.length > 50) {
errors.push('模板名称不能超过50个字符');
}
if (!template.findings || template.findings.trim() === '') {
errors.push('影像所见不能为空');
}
if (!template.impression || template.impression.trim() === '') {
errors.push('诊断意见不能为空');
}
return errors;
};
const handleApplyTemplate = (template: ReportTemplate) => {
const hasContent =
findings.diagnosticDescriptionFromImage.trim() !== '' ||
diagnosis.diagnosisDescription.trim() !== '';
if (hasContent) {
Modal.confirm({
title: '确认应用模板',
content: '当前报告已有内容,是否替换为模板内容?',
onOk: () => {
dispatch(updateInputValue(template.findings));
dispatch(setDiagnosisDescription(template.impression));
message.success('模板已应用');
},
});
} else {
dispatch(updateInputValue(template.findings));
dispatch(setDiagnosisDescription(template.impression));
message.success('模板已应用');
}
};
虽然当前主要针对桌面端,但需要考虑:
对话框尺寸
模板列表
表单布局
本文档详细描述了诊断报告模板编辑功能的完整设计方案,包括:
通过本文档,开发团队可以清晰地了解功能的全貌,按照计划有序地实现各个模块,确保功能的质量和用户体验。
文档版本: v1.0
创建日期: 2025-12-25
最后更新: 2025-12-25
作者: Cline AI Assistant