Ctrl + 鼠标点击
进行多选/取消多选组件 | 职责 | 文件位置 |
---|---|---|
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 |
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 |
数据结构 | 职责 | 文件位置 |
---|---|---|
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 |
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
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[更新操作面板]
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: 更新操作按钮状态
// 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,
};
};
// 修改 WorklistTable 组件
const WorklistTable: React.FC<WorklistTableProps> = ({
// ... 其他 props
selectedIds,
handleRowClick,
handleRowDoubleClick,
}) => {
const { handleTouchClick } = useMultiSelection({
selectedIds,
onSelectionChange: handleRowClick,
});
const { handleTouchStart } = useTouchDoubleClick({
onDoubleClick: handleRowDoubleClick,
delay: 300,
});
return (
<Table<DataType>
// ... 其他配置
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'
: ''
}
/>
);
};
现有的 Redux slices 已经包含了 selectionSlice
,它提供了 setSelectedIds
和 clearSelection
方法。我们需要确保这些方法在多选场景下正常工作。
// 在各个页面组件中使用
const handleRowClick = (record: Task, event: React.MouseEvent) => {
const { handleRowClick } = useMultiSelection({
selectedIds,
onSelectionChange: (newIds) => {
dispatch(workSelectionSlice.actions.setSelectedIds(newIds));
dispatch(updateThumbnailsFromWorkSelection(newIds));
},
});
handleRowClick(record, event);
};
文件 | 修改类型 | 描述 |
---|---|---|
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 |
修改 | 确保支持多选缩略图更新 |
创建多选 Hook
useMultiSelection
Hook修改表格组件
WorklistTable
组件以支持多选更新页面组件
worklist.tsx
、HistoryList.tsx
和 Bin.tsx
测试和优化
测试场景 | 预期结果 | 测试方法 |
---|---|---|
桌面环境单击表格行 | 只选中当前行,清空其他选择 | 使用鼠标单击表格行 |
桌面环境Ctrl+单击表格行 | 多选/取消多选当前行 | 按住Ctrl键单击表格行 |
触摸屏单击表格行 | 选中/取消选中当前行 | 使用触摸屏单击表格行 |
双击表格行 | 触发双击事件(如进入检查) | 双击表格行 |
选中行后切换页面 | 保持选中状态 | 在不同页面间切换 |
清空选择 | 所有选择被清空 | 点击清空按钮 |
测试项目 | 测试内容 | 预期结果 |
---|---|---|
浏览器兼容性 | Chrome, Firefox, Safari, Edge | 功能正常 |
设备兼容性 | 桌面、平板、手机 | 交互方式适配 |
屏幕分辨率 | 不同分辨率下显示 | 界面布局正常 |
性能测试 | 大量数据下的多选 | 响应速度可接受 |
测试场景 | 预期结果 |
---|---|
空数据表格 | 无操作响应 |
选中所有行后删除 | 删除后选择状态正确 |
网络中断时操作 | 操作被正确缓存 |
快速连续点击 | 正确处理点击事件 |
性能问题
交互冲突
状态同步
性能优化
交互优化
状态管理
本设计文档详细描述了 worklist、historylist 和 bin 表格多选功能的实现方案。通过使用自定义 Hook 和修改现有组件,我们可以在保持现有功能不变的前提下,添加多选功能。该方案支持桌面和触摸屏两种交互方式,并提供了清晰的视觉反馈。
主要特点:
该方案可以有效地满足用户的多选需求,同时保持代码的可维护性和扩展性。