useMultiSelection.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { useCallback } from 'react';
  2. import { Task } from '@/domain/work';
  3. interface UseMultiSelectionOptions {
  4. selectedIds: string[];
  5. selectedSecondaryIds?: string[]; // 可选
  6. onSelectionChange: ((ids: string[], secondaryIds?: string[]) => void);
  7. enableMultiSelect?: boolean;
  8. }
  9. /**
  10. * 自定义 Hook,处理表格多选逻辑
  11. * 支持桌面环境(Ctrl+点击)和触摸屏环境(单击选择/取消选择)
  12. */
  13. export const useMultiSelection = ({
  14. selectedIds,
  15. selectedSecondaryIds,
  16. onSelectionChange,
  17. enableMultiSelect = true,
  18. }: UseMultiSelectionOptions) => {
  19. const useDualIdMode = selectedSecondaryIds !== undefined;
  20. /**
  21. * 处理桌面环境的行点击事件
  22. * @param record - 点击的行数据
  23. * @param event - 鼠标事件对象
  24. */
  25. const handleRowClick = useCallback((record: Task, event: React.MouseEvent) => {
  26. if (!enableMultiSelect) {
  27. // 如果禁用多选,只选中当前项
  28. onSelectionChange([record.StudyID], useDualIdMode ? [record.entry_id ?? ''] : undefined);
  29. return;
  30. }
  31. const studyId = record.StudyID;
  32. const entryId = record.entry_id;
  33. if (event.ctrlKey || event.metaKey) {
  34. // 桌面环境:Ctrl+点击进行多选/取消多选
  35. let newSelectedIds;
  36. let newSelectedSecondaryIds;
  37. if (useDualIdMode) {
  38. if (studyId) {//本地task
  39. const index = selectedIds.indexOf(studyId);
  40. if (index > -1) {//说明已经在选中数组中了,需要取消选择
  41. newSelectedIds = selectedIds.splice(index, 1);
  42. newSelectedSecondaryIds = selectedSecondaryIds?.splice(index, 1);
  43. } else {
  44. newSelectedIds = [...selectedIds, studyId];
  45. newSelectedSecondaryIds = [...(selectedSecondaryIds ?? []), entryId ?? ''];
  46. }
  47. } else if (entryId) {//ris task
  48. const index = selectedSecondaryIds.indexOf(entryId);
  49. if (index > -1) {//说明已经在选中数组中了,需要取消选择
  50. newSelectedIds = selectedIds.splice(index, 1);
  51. newSelectedSecondaryIds = selectedSecondaryIds?.splice(index, 1);
  52. } else {
  53. newSelectedIds = [...selectedIds, studyId];
  54. newSelectedSecondaryIds = [...(selectedSecondaryIds ?? []), entryId ?? ''];
  55. }
  56. }
  57. } else {
  58. newSelectedIds = selectedIds.includes(studyId)
  59. ? selectedIds.filter(id => id !== studyId) // 取消选择
  60. : [...selectedIds, studyId]; // 添加选择
  61. }
  62. onSelectionChange(newSelectedIds, newSelectedSecondaryIds);
  63. } else {
  64. // 普通点击:清空其他选择,只选中当前项
  65. onSelectionChange([studyId], useDualIdMode ? [record.entry_id ?? ''] : undefined);
  66. }
  67. }, [selectedIds, onSelectionChange, enableMultiSelect]);
  68. /**
  69. * 处理触摸屏环境的行点击事件
  70. * @param record - 点击的行数据
  71. */
  72. const handleTouchClick = useCallback((record: Task) => {
  73. const studyId = record.StudyID;
  74. // 触摸屏环境:单击选中,再次单击取消选中
  75. const newSelectedIds = selectedIds.includes(studyId)
  76. ? selectedIds.filter(id => id !== studyId) // 取消选择
  77. : [studyId]; // 添加选择
  78. onSelectionChange(newSelectedIds, useDualIdMode ? [record.entry_id ?? ''] : undefined);
  79. }, [selectedIds, onSelectionChange]);
  80. /**
  81. * 处理行选择(通用方法,可根据设备类型选择具体实现)
  82. * @param record - 点击的行数据
  83. * @param event - 鼠标事件对象(可选)
  84. * @param isTouch - 是否为触摸设备
  85. */
  86. const handleRowSelect = useCallback((record: Task, event?: React.MouseEvent, isTouch = false) => {
  87. if (isTouch && !event) {
  88. // 触摸屏设备
  89. handleTouchClick(record);
  90. } else if (event) {
  91. // 桌面设备
  92. handleRowClick(record, event);
  93. } else {
  94. // 默认行为:只选中当前项
  95. onSelectionChange([record.StudyID], useDualIdMode ? [record.entry_id ?? ''] : undefined);
  96. }
  97. }, [handleRowClick, handleTouchClick, onSelectionChange]);
  98. return {
  99. handleRowClick,
  100. handleTouchClick,
  101. handleRowSelect,
  102. };
  103. };