# Worklist/HistoryList/Bin 多选功能设计文档 ## 1. 需求概述 ### 1.1 功能需求 - **多选功能**:在 worklist、historylist 和 bin 表格中支持多选操作 - **鼠标操作**:在桌面环境下,使用 `Ctrl + 鼠标点击` 进行多选/取消多选 - **触摸屏操作**:在触摸屏环境下,单击选中,再次单击取消选中 - **视觉反馈**:选中的行需要有明显的视觉标识 ### 1.2 技术要求 - 基于 Ant Design Table 组件实现 - 兼容现有的 Redux 状态管理 - 支持不同设备环境(桌面/触摸屏) - 保持现有功能不变 ## 2. 参与者分析 ### 2.1 组件参与者 | 组件 | 职责 | 文件位置 | |------|------|----------| | `WorklistTable` | 表格展示组件,处理行点击事件 | `src/pages/patient/components/WorklistTable.tsx` | | `WorklistPage` | Worklist 页面容器,管理状态和事件处理 | `src/pages/patient/worklist.tsx` | | `HistoryListPage` | HistoryList 页面容器,管理状态和事件处理 | `src/pages/patient/HistoryList.tsx` | | `BinPage` | Bin 页面容器,管理状态和事件处理 | `src/pages/patient/Bin.tsx` | | `useMultiSelection` | 自定义 Hook,处理多选逻辑 | `src/hooks/useMultiSelection.ts` | | `useTouchDoubleClick` | 现有 Hook,处理触摸屏双击事件 | `src/hooks/useTouchDoubleClick.ts` | ### 2.2 状态管理参与者 | Redux Slice | 职责 | 文件位置 | |------------|------|----------| | `workSelectionSlice` | 管理 worklist 的选中状态 | `src/states/patient/worklist/slices/workSlice.ts` | | `historySelectionSlice` | 管理 historylist 的选中状态 | `src/states/patient/worklist/slices/history.ts` | | `binSelectionSlice` | 管理 bin 的选中状态 | `src/states/patient/bin/slices/binSlice.ts` | | `selectedPatientSlice` | 管理选中患者信息 | `src/states/patient/worklist/slices/selectedPatientSlice.ts` | | `thumbnailListSlice` | 管理缩略图列表 | `src/states/patient/worklist/slices/thumbnailListSlice.ts` | ### 2.3 数据结构参与者 | 数据结构 | 职责 | 文件位置 | |----------|------|----------| | `Task` | 任务数据模型 | `src/domain/work.ts` | | `SelectionState` | 选中状态接口 | `src/states/list_template/type.model.ts` | | `WorkFilter` | Worklist 过滤条件 | `src/states/patient/worklist/types/workfilter.ts` | | `BinFilter` | Bin 过滤条件 | `src/states/patient/bin/types/binFilter.ts` | ## 3. 架构设计 ### 3.1 整体架构图 ```mermaid graph TB subgraph "用户界面层" A[WorklistPage] --> B[WorklistTable] C[HistoryListPage] --> D[WorklistTable] E[BinPage] --> F[WorklistTable] end subgraph "逻辑层" B --> G[useMultiSelection Hook] D --> G F --> G G --> H[useTouchDoubleClick Hook] end subgraph "状态管理层" I[workSelectionSlice] --> J[Redux Store] K[historySelectionSlice] --> J L[binSelectionSlice] --> J M[thumbnailListSlice] --> J end subgraph "数据层" N[API Service] --> O[后端服务] end B --> I D --> K F --> L I --> J K --> J L --> J J --> N N --> O ``` ### 3.2 数据流图 ```mermaid flowchart TD A[用户操作] --> B{设备类型} B -->|桌面| C[Ctrl+点击] B -->|触摸屏| D[单击] C --> E[useMultiSelection] D --> E E --> F[判断当前选中状态] F --> G{是否已选中} G -->|是| H[从选中列表移除] G -->|否| I[添加到选中列表] H --> J[更新Redux状态] I --> J J --> K[更新表格行样式] J --> L[更新缩略图] J --> M[更新操作面板] ``` ### 3.3 泳道图 ```mermaid swimlane title 多选功能交互流程 participant "用户" as User participant "WorklistTable" as Table participant "useMultiSelection" as Hook participant "Redux Store" as Store participant "缩略图组件" as Thumbnails participant "操作面板" as Operations User --> Table: 点击表格行 Table --> Hook: 处理点击事件 Hook --> Hook: 判断设备类型 Hook --> Hook: 判断Ctrl键状态 Hook --> Store: 更新选中状态 Store --> Table: 更新行样式 Store --> Thumbnails: 更新选中项 Store --> Operations: 更新操作按钮状态 ``` ## 4. 详细设计 ### 4.1 多选 Hook 设计 ```typescript // src/hooks/useMultiSelection.ts interface UseMultiSelectionOptions { selectedIds: string[]; onSelectionChange: (ids: string[]) => void; enableMultiSelect?: boolean; } export const useMultiSelection = ({ selectedIds, onSelectionChange, enableMultiSelect = true, }: UseMultiSelectionOptions) => { const handleRowClick = (record: Task, event: React.MouseEvent) => { if (!enableMultiSelect) { onSelectionChange([record.StudyID]); return; } const isCtrlPressed = event.ctrlKey || event.metaKey; const studyId = record.StudyID; if (isCtrlPressed) { // 桌面环境:Ctrl+点击进行多选/取消多选 const newSelectedIds = selectedIds.includes(studyId) ? selectedIds.filter(id => id !== studyId) : [...selectedIds, studyId]; onSelectionChange(newSelectedIds); } else { // 普通点击:清空其他选择,只选中当前项 onSelectionChange([studyId]); } }; const handleTouchClick = (record: Task) => { // 触摸屏环境:单击选中,再次单击取消选中 const studyId = record.StudyID; const newSelectedIds = selectedIds.includes(studyId) ? selectedIds.filter(id => id !== studyId) : [studyId]; onSelectionChange(newSelectedIds); }; return { handleRowClick, handleTouchClick, }; }; ``` ### 4.2 表格组件修改 ```typescript // 修改 WorklistTable 组件 const WorklistTable: React.FC = ({ // ... 其他 props selectedIds, handleRowClick, handleRowDoubleClick, }) => { const { handleTouchClick } = useMultiSelection({ selectedIds, onSelectionChange: handleRowClick, }); const { handleTouchStart } = useTouchDoubleClick({ onDoubleClick: handleRowDoubleClick, delay: 300, }); return ( // ... 其他配置 onRow={(record, index) => ({ onClick: (event) => handleRowClick(record, event), onDoubleClick: () => handleRowDoubleClick(record), onTouchStart: (e) => { handleTouchStart(e); handleTouchClick(record); }, style: { cursor: 'pointer', userSelect: 'none', backgroundColor: selectedIds.includes(record.StudyID) ? 'rgba(255, 255, 0, 0.3)' : 'transparent', }, })} rowClassName={(record) => selectedIds.includes(record.StudyID) ? 'bg-yellow-500 hover:bg-yellow-800' : '' } /> ); }; ``` ### 4.3 Redux 状态管理 现有的 Redux slices 已经包含了 `selectionSlice`,它提供了 `setSelectedIds` 和 `clearSelection` 方法。我们需要确保这些方法在多选场景下正常工作。 ```typescript // 在各个页面组件中使用 const handleRowClick = (record: Task, event: React.MouseEvent) => { const { handleRowClick } = useMultiSelection({ selectedIds, onSelectionChange: (newIds) => { dispatch(workSelectionSlice.actions.setSelectedIds(newIds)); dispatch(updateThumbnailsFromWorkSelection(newIds)); }, }); handleRowClick(record, event); }; ``` ## 5. 实现计划 ### 5.1 文件修改清单 | 文件 | 修改类型 | 描述 | |------|----------|------| | `src/hooks/useMultiSelection.ts` | 新增 | 多选逻辑 Hook | | `src/pages/patient/components/WorklistTable.tsx` | 修改 | 添加多选支持 | | `src/pages/patient/worklist.tsx` | 修改 | 更新行点击处理逻辑 | | `src/pages/patient/HistoryList.tsx` | 修改 | 更新行点击处理逻辑 | | `src/pages/patient/Bin.tsx` | 修改 | 更新行点击处理逻辑 | | `src/states/patient/worklist/slices/thumbnailListSlice.ts` | 修改 | 确保支持多选缩略图更新 | ### 5.2 实现步骤 1. **创建多选 Hook** - 实现 `useMultiSelection` Hook - 处理桌面和触摸屏的不同交互逻辑 - 提供清晰的 API 接口 2. **修改表格组件** - 更新 `WorklistTable` 组件以支持多选 - 添加视觉反馈(行样式变化) - 保持现有双击功能不变 3. **更新页面组件** - 修改 `worklist.tsx`、`HistoryList.tsx` 和 `Bin.tsx` - 集成多选 Hook - 更新 Redux 状态管理 4. **测试和优化** - 测试不同设备环境下的交互 - 优化性能和用户体验 - 确保现有功能不受影响 ## 6. 测试方案 ### 6.1 功能测试 | 测试场景 | 预期结果 | 测试方法 | |----------|----------|----------| | 桌面环境单击表格行 | 只选中当前行,清空其他选择 | 使用鼠标单击表格行 | | 桌面环境Ctrl+单击表格行 | 多选/取消多选当前行 | 按住Ctrl键单击表格行 | | 触摸屏单击表格行 | 选中/取消选中当前行 | 使用触摸屏单击表格行 | | 双击表格行 | 触发双击事件(如进入检查) | 双击表格行 | | 选中行后切换页面 | 保持选中状态 | 在不同页面间切换 | | 清空选择 | 所有选择被清空 | 点击清空按钮 | ### 6.2 兼容性测试 | 测试项目 | 测试内容 | 预期结果 | |----------|----------|----------| | 浏览器兼容性 | Chrome, Firefox, Safari, Edge | 功能正常 | | 设备兼容性 | 桌面、平板、手机 | 交互方式适配 | | 屏幕分辨率 | 不同分辨率下显示 | 界面布局正常 | | 性能测试 | 大量数据下的多选 | 响应速度可接受 | ### 6.3 边界情况测试 | 测试场景 | 预期结果 | |----------|----------| | 空数据表格 | 无操作响应 | | 选中所有行后删除 | 删除后选择状态正确 | | 网络中断时操作 | 操作被正确缓存 | | 快速连续点击 | 正确处理点击事件 | ## 7. 潜在问题与解决方案 ### 7.1 潜在问题 1. **性能问题** - 大量数据时多选操作可能导致性能下降 - 频繁的 Redux 状态更新可能影响响应速度 2. **交互冲突** - 现有的双击功能可能与新的多选功能冲突 - 触摸屏的双击检测可能与单击选择冲突 3. **状态同步** - 多个页面之间的选中状态可能不同步 - 缩略图更新可能不及时 ### 7.2 解决方案 1. **性能优化** - 使用虚拟滚动处理大量数据 - 批量更新 Redux 状态 - 优化重渲染逻辑 2. **交互优化** - 明确区分单击和双击事件 - 在触摸屏上使用不同的交互方式 - 添加视觉提示帮助用户理解交互方式 3. **状态管理** - 确保每个页面独立管理自己的选中状态 - 使用 Redux 中间件处理状态同步 - 添加加载状态处理异步操作 ## 8. 总结 本设计文档详细描述了 worklist、historylist 和 bin 表格多选功能的实现方案。通过使用自定义 Hook 和修改现有组件,我们可以在保持现有功能不变的前提下,添加多选功能。该方案支持桌面和触摸屏两种交互方式,并提供了清晰的视觉反馈。 主要特点: - 统一的多选逻辑,支持不同设备环境 - 基于 Redux 的状态管理,确保数据一致性 - 良好的用户体验和视觉反馈 - 完善的测试方案和问题处理机制 该方案可以有效地满足用户的多选需求,同时保持代码的可维护性和扩展性。