hooks.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import {
  2. createColumnHelper,
  3. useReactTable,
  4. getCoreRowModel,
  5. Header,
  6. } from '@tanstack/react-table';
  7. import {ColumnType} from 'antd/es/table';
  8. import {useEffect, useMemo, useState} from 'react';
  9. import {DragStartEvent, DragEndEvent} from '@dnd-kit/core';
  10. import {arrayMove} from '@dnd-kit/sortable';
  11. import {
  12. createSearchContext,
  13. usePreloadSettingData,
  14. useTableSearchDispatch,
  15. } from '@hooks';
  16. function parseColumn<T>(columns: ColumnType<T>[]) {
  17. const hepler = createColumnHelper<Record<string, any>>();
  18. const tableColumns = columns.map(function (val) {
  19. const {dataIndex, title, render, align, fixed} = val;
  20. const meta = {
  21. align,
  22. fixed: Boolean(fixed),
  23. disabledSort: Boolean(fixed) || dataIndex === 'no',
  24. };
  25. if (render) {
  26. return hepler.display({
  27. id: dataIndex!.toString(),
  28. header: title?.toString(),
  29. cell(props) {
  30. return render(
  31. props.getValue(),
  32. props.row.original as T,
  33. props.row.index,
  34. );
  35. },
  36. meta,
  37. });
  38. }
  39. return hepler.accessor(dataIndex!.toString(), {
  40. header: title?.toString(),
  41. cell: props => props.getValue(),
  42. minSize: 0,
  43. meta,
  44. });
  45. });
  46. tableColumns.unshift(
  47. hepler.display({
  48. header: '序号',
  49. id: 'no',
  50. cell({row}) {
  51. return row.index + 1;
  52. },
  53. meta: {
  54. align: 'center',
  55. fixed: false,
  56. disabledSort: true,
  57. },
  58. }),
  59. );
  60. return tableColumns;
  61. }
  62. export function useTable<T extends Record<string, any>>(
  63. columns: ColumnType<T>[],
  64. data: T[],
  65. options: {
  66. pageSize: number;
  67. preloadKey?: string;
  68. searchContext: ReturnType<typeof createSearchContext>;
  69. },
  70. ) {
  71. const columnList = useMemo(
  72. function () {
  73. return parseColumn(columns);
  74. },
  75. [columns],
  76. );
  77. const preload = usePreloadSettingData(options.preloadKey);
  78. const [columnSizing, setColumnSizing] = useState(function () {
  79. if (preload?.tableWidth)
  80. return JSON.parse(preload.tableWidth) as Record<string, number>;
  81. const obj: Record<string, number> = {no: 64};
  82. columns.forEach(function ({dataIndex, width}) {
  83. if (dataIndex && width) {
  84. obj[dataIndex.toString()] = Number(width);
  85. }
  86. });
  87. return obj;
  88. });
  89. const [columnOrder, setColumnOrder] = useState(function () {
  90. if (preload?.tableOrder) return JSON.parse(preload?.tableOrder) as string[];
  91. const nextList = columns.map(val => val.dataIndex!.toString());
  92. return ['no', ...nextList];
  93. });
  94. const dispatch = useTableSearchDispatch(options.searchContext);
  95. useEffect(
  96. function () {
  97. dispatch({
  98. type: 'CHANGE_VALUE',
  99. payload: {key: 'tableWidth', value: JSON.stringify(columnSizing)},
  100. });
  101. dispatch({
  102. type: 'CHANGE_VALUE',
  103. payload: {key: 'tableOrder', value: JSON.stringify(columnOrder)},
  104. });
  105. },
  106. [columnOrder, columnSizing, dispatch],
  107. );
  108. const table = useReactTable({
  109. data,
  110. columns: columnList,
  111. state: {
  112. columnSizing,
  113. columnOrder,
  114. },
  115. getCoreRowModel: getCoreRowModel(),
  116. onColumnSizingChange: setColumnSizing,
  117. columnResizeMode: 'onChange',
  118. onColumnOrderChange: setColumnOrder,
  119. });
  120. const [active, setActive] = useState<Header<
  121. Record<string, any>,
  122. unknown
  123. > | null>(null);
  124. function onDragStart(event: DragStartEvent) {
  125. setActive(event.active.data.current?.header);
  126. }
  127. function onDragEnd({active, over}: DragEndEvent) {
  128. setActive(null);
  129. if (!over) return;
  130. const {id: activeId} = active,
  131. {id: overId} = over;
  132. const {disabledSort} = (over.data.current as any).header.column.columnDef
  133. .meta;
  134. if (disabledSort) return;
  135. if (activeId === overId) return;
  136. const {setColumnOrder} = table;
  137. setColumnOrder(function (prev) {
  138. const fromIdx = prev.findIndex(val => val === activeId),
  139. toIdx = prev.findIndex(val => val === overId);
  140. return arrayMove(prev, fromIdx, toIdx);
  141. });
  142. }
  143. return [
  144. {...table, active},
  145. {onDragStart, onDragEnd},
  146. ] as const;
  147. }