# RIS数据双击保存功能实现方案 ## 需求描述 在worklist页面中,实现通过双击列表中的数据行来触发"RIS数据保存到本地"功能的需求。具体要求: - 双击RIS数据行(具备entry_id字段)时,自动触发保存到本地的功能 - 双击本地study数据行(无entry_id字段)时,保持原有进入检查的逻辑 - 保存成功后显示成功提示并自动刷新列表 - 保存失败时显示错误提示 ## 当前状态分析 ### 现有实现 1. **双击逻辑**:`src/pages/patient/worklist.tsx` 中的 `handleRowDoubleClick` 函数目前对所有数据行都调用 `worklistToExam(record)` 进入检查 2. **保存逻辑**:`src/pages/patient/components/ActionPanel.tsx` 中的 `handleRisSave` 函数实现了"RIS数据保存到本地"的完整功能 3. **数据区分**:RIS数据具有 `entry_id` 字段,本地study数据没有此字段 ### 存在问题 - 双击事件没有区分数据类型,所有双击都进入检查 - 保存逻辑集中在UI组件中,缺乏业务逻辑分离 ## 实现思路 ### 架构设计 采用分层架构,将业务逻辑从UI层分离: 1. **Domain层**:`src/domain/patient/risSaveLogic.ts` - 封装RIS保存的核心业务逻辑 - 负责API调用、消息处理、列表刷新等 - 与 `worklistToExam.ts` 保持一致的架构风格 2. **UI层**:`src/pages/patient/worklist.tsx` - 负责数据类型判断 - 调用相应的domain函数处理业务逻辑 ### 技术方案 - 在双击事件中通过 `record.entry_id` 字段判断数据类型 - RIS数据:调用domain层的保存函数 - 本地数据:调用原有的 `worklistToExam` 函数 - 保持与ActionPanel中保存逻辑的一致性 ## 具体实现步骤 ### 步骤1:创建Domain层逻辑 创建 `src/domain/patient/risSaveLogic.ts` 文件: ```typescript import { saveRisBatch } from '@/API/patient/risActions'; import { Modal, message } from 'antd'; import store from '@/states/store'; import { setPage, setPageSize } from '@/states/patient/worklist/slices/searchSlice'; import { fetchWorkThunk } from '@/states/patient/worklist/slices/workSlice'; import { WorkFilter } from '@/states/patient/worklist/types/workfilter'; /** * RIS数据保存成功弹框 */ const showSaveSuccessModal = (count: number) => { Modal.success({ title: '🎉 保存成功', content: (

成功保存 {count} 条RIS数据到本地

系统将自动刷新列表显示最新数据

), okText: '确定', centered: true, afterClose: () => { // 弹框自动消失后执行列表刷新 triggerSearch(); } }); }; /** * 触发搜索刷新列表(复用SearchPanel的逻辑) */ const triggerSearch = () => { const dispatch = store.dispatch; const searchState = store.getState().search; // 重置分页 dispatch(setPage(1)); dispatch(setPageSize(10)); // 构建过滤条件 const filters: WorkFilter = { patient_id: searchState.id, patient_name: searchState.name, access_number: searchState.acc_no, start_time: searchState.start_time, end_time: searchState.end_time, status: 'Arrived,InProgress', }; // 调用搜索 dispatch(fetchWorkThunk({ page: 1, pageSize: 10, filters })); }; /** * 保存单个RIS数据到本地 * @param entryId RIS条目ID */ export const saveRisData = async (entryId: string) => { try { console.log('RIS双击保存本地参数:', entryId); // 调用RIS批量保存API(传递单个entryId的数组) await saveRisBatch([entryId]); console.log('RIS双击保存本地成功'); // 显示成功弹框(暂逝后自动刷新) showSaveSuccessModal(1); } catch (error) { console.error('RIS双击保存本地失败:', error); const errorMessage = error instanceof Error ? error.message : '保存过程中发生未知错误'; Modal.error({ title: '❌ 保存失败', content: (

{errorMessage}

请检查网络连接或联系技术支持

), okText: '确定', centered: true }); } }; ``` ### 步骤2:修改UI层逻辑 修改 `src/pages/patient/worklist.tsx` 文件: ```typescript // 添加导入 import { saveRisData } from '@/domain/patient/risSaveLogic'; // 修改handleRowDoubleClick函数 const handleRowDoubleClick = (record: Task) => { console.log( '[WorklistTable] Row double-clicked:', JSON.stringify(record, null, 2) ); // 判断是否为RIS数据 if (record.entry_id) { // RIS数据:触发保存到本地 saveRisData(record.entry_id); } else { // 本地study数据:进入检查 worklistToExam(record); } }; ``` ## 测试方案 ### 功能测试 1. **RIS数据双击保存测试**: - 前置条件:worklist中存在有entry_id的RIS数据 - 操作步骤: 1. 在worklist页面找到一条有entry_id的RIS数据行 2. 双击该数据行 - 预期结果: 1. 触发RIS保存API调用 2. 显示保存成功弹框 3. 弹框自动关闭后列表自动刷新 4. 控制台显示相应的日志信息 2. **本地数据双击进入检查测试**: - 前置条件:worklist中存在无entry_id的本地study数据 - 操作步骤: 1. 在worklist页面找到一条无entry_id的本地数据行 2. 双击该数据行 - 预期结果: 1. 正常进入检查流程 2. 页面跳转到exam或process页面 ### 异常测试 1. **保存失败测试**: - 前置条件:模拟网络异常或API错误 - 操作步骤:双击RIS数据行 - 预期结果:显示保存失败的错误弹框 2. **边界情况测试**: - 测试entry_id为空字符串的情况 - 测试entry_id为undefined的情况 - 测试网络超时的情况 ### 回归测试 1. **原有功能验证**: - 验证单选/多选功能正常 - 验证其他按钮功能正常 - 验证分页、搜索功能正常 2. **性能测试**: - 测试大量数据下的双击响应速度 - 测试连续双击的处理能力 ## 风险评估 ### 技术风险 1. **API兼容性**:确保 `saveRisBatch` API能正确处理单个entryId的数组 2. **状态管理**:确保列表刷新后Redux状态正确更新 3. **错误处理**:确保异常情况下的用户体验友好 ### 业务风险 1. **数据一致性**:确保保存后的数据状态正确显示 2. **用户体验**:确保操作反馈及时且明确 ## 实施计划 1. **开发阶段**: - 创建 `risSaveLogic.ts` 文件 - 修改 `worklist.tsx` 文件 - 本地测试验证 2. **测试阶段**: - 功能测试 - 异常测试 - 回归测试 3. **部署阶段**: - 代码审查 - 生产环境部署 - 监控验证 ## 验收标准 - [ ] 双击RIS数据行能正确触发保存功能 - [ ] 双击本地数据行能正常进入检查 - [ ] 保存成功/失败有适当的用户反馈 - [ ] 列表在保存成功后自动刷新 - [ ] 所有原有功能正常工作 - [ ] 代码通过ESLint检查 - [ ] 单元测试覆盖核心逻辑