| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- import {
- createColumnHelper,
- useReactTable,
- getCoreRowModel,
- Header,
- RowSelectionState,
- SortingState,
- getSortedRowModel,
- ColumnSort,
- getExpandedRowModel,
- ExpandedState,
- } from '@tanstack/react-table';
- import {
- CSSProperties,
- Dispatch,
- SetStateAction,
- useEffect,
- useMemo,
- useRef,
- useState,
- } from 'react';
- import {DragStartEvent, DragEndEvent} from '@dnd-kit/core';
- import {arrayMove} from '@dnd-kit/sortable';
- import {createTableSettingContext, useContextSection} from '@hooks';
- import TableCheck from './Check';
- import {LDColumnsType} from '.';
- import {TABLE_CELL_WIDTH} from '@utils';
- import {useLatest} from 'ahooks';
- function parseColumn<T extends Record<string, unknown>>(
- columns: LDColumnsType<T>[],
- enableSelect?: boolean,
- enableNo?: boolean,
- ) {
- const helper = createColumnHelper<Record<string, any>>();
- let hasSort = false, hasGroup = false;
- const parseColumns: LDColumnsType<T>[] = [...columns];
- if (enableNo) {
- parseColumns.unshift({
- title: '序号',
- dataIndex: 'no',
- align: 'center',
- width: TABLE_CELL_WIDTH.no,
- render(_, index, row) {
- return row.depth > 0 ? null : index + 1;
- },
- });
- }
- let leftPosition = enableSelect ? TABLE_CELL_WIDTH.checkbox : 0;
- let rightPosition = parseColumns.reduce(function(prev, next) {
- if (next.fixed !== 'right') return prev;
- return prev + next.width;
- }, 0);
- const columnList = parseColumns.map(function(val) {
- const {dataIndex, title, render, align, fixed, width, sort, children} = val;
- let fixedStyle: CSSProperties = {};
- if (fixed === 'left') {
- fixedStyle = {left: leftPosition};
- leftPosition += width;
- }
- if (fixed === 'right') {
- rightPosition -= width;
- fixedStyle = {right: rightPosition};
- }
- const meta = {
- align,
- fixed,
- fixedStyle,
- disabledSort: Boolean(fixed) || dataIndex === 'no',
- sort,
- };
- if (children && children.length) {
- if (!hasGroup) hasGroup = true;
- const {columnList: columns} = parseColumn(
- children,
- false,
- false,
- );
- const group = helper.group({
- header: title,
- columns,
- minSize: 0,
- size: width,
- meta,
- });
- return group;
- }
- if (!hasSort && sort) hasSort = true;
- if (render) {
- return helper.display({
- id: dataIndex.toString(),
- header: title.toString(),
- size: width,
- minSize: 0,
- cell({row}) {
- return render(
- row.original as T,
- row.index,
- row,
- );
- },
- meta,
- });
- }
- return helper.accessor(dataIndex.toString(), {
- header: title?.toString(),
- cell: props => props.getValue(),
- size: width,
- meta,
- });
- });
- enableSelect && columnList.unshift(
- helper.accessor('select', {
- header({table}) {
- return (
- <TableCheck
- checked={table.getIsAllRowsSelected()}
- indeterminate={table.getIsSomeRowsSelected()}
- onChange={table.getToggleAllRowsSelectedHandler()}
- />
- );
- },
- cell({row}) {
- return (
- <TableCheck
- checked={row.getIsSelected()}
- indeterminate={row.getIsSomeSelected()}
- onChange={row.getToggleSelectedHandler()}
- enabled={row.getCanSelect()}
- />
- );
- },
- size: TABLE_CELL_WIDTH.checkbox,
- meta: {
- align: 'center',
- fixed: 'left',
- disabledSort: true,
- fixedStyle: {left: 0},
- },
- }),
- );
- return {
- columnList,
- hasSort,
- hasGroup,
- };
- }
- export function useTable<T extends Record<string, any>>(
- columns: LDColumnsType<T>[],
- data: T[],
- options: {
- settingContext: ReturnType<typeof createTableSettingContext>;
- rowSelection?: RowSelectionState;
- setRowSelection?: Dispatch<SetStateAction<RowSelectionState>>;
- rawKey?: keyof T;
- onSortingChange?: (state: ColumnSort | null) => void;
- subRowKey?: keyof T;
- hasRenderSubComponent: boolean;
- },
- ) {
- const {
- settingContext,
- rowSelection,
- setRowSelection,
- rawKey,
- onSortingChange,
- subRowKey,
- hasRenderSubComponent,
- } = options;
- const {columnList, hasSort, hasGroup} = useMemo(
- function() {
- return parseColumn(
- columns,
- Boolean(setRowSelection),
- true,
- );
- },
- [columns, setRowSelection],
- );
- const preloadData = useContextSection(settingContext, state => state[0]);
- const [columnSizing, setColumnSizing] = useState(function() {
- if (preloadData?.tableWidth)
- return JSON.parse(preloadData.tableWidth) as Record<string, number>;
- return {};
- });
- const [columnOrder, setColumnOrder] = useState(function() {
- if (preloadData?.tableOrder)
- return JSON.parse(preloadData?.tableOrder) as string[];
- const nextList = columns.map(val => val.dataIndex.toString());
- return hasGroup ? [] : ['select', 'no', ...nextList];
- });
- const [sorting, setSorting] = useState<SortingState>([]);
- const onSortingChangeFn = useLatest(onSortingChange);
- useEffect(function() {
- onSortingChangeFn.current?.(sorting.length ? sorting[0] : null);
- }, [onSortingChangeFn, sorting]);
- const [expanded, setExpanded] = useState<ExpandedState>({});
- const table = useReactTable({
- data,
- columns: columnList,
- state: {
- columnSizing,
- columnOrder,
- rowSelection,
- sorting,
- expanded,
- },
- getSortedRowModel: onSortingChange ? void 0 : getSortedRowModel(),
- getCoreRowModel: getCoreRowModel(),
- onColumnSizingChange: setColumnSizing,
- columnResizeMode: 'onChange',
- onColumnOrderChange: setColumnOrder,
- onRowSelectionChange: setRowSelection,
- getRowId: row => row[rawKey as string | undefined ?? 'id'],
- onSortingChange: setSorting,
- getSubRows: subRowKey ? row => row[subRowKey as string] : void 0,
- getExpandedRowModel: subRowKey && !hasRenderSubComponent
- ? getExpandedRowModel()
- : void 0,
- onExpandedChange: setExpanded,
- });
- type ActiveState = Header<Record<string, any>, unknown> | null;
- const [active, setActive] = useState<ActiveState>(null);
- function onDragStart(event: DragStartEvent) {
- setActive(event.active.data.current?.header);
- }
- function onDragEnd({active, over}: DragEndEvent) {
- setActive(null);
- if (!over)
- return;
- const {id: activeId} = active,
- {id: overId} = over;
- const {disabledSort} = (over.data.current as any).header.column.columnDef
- .meta;
- if (disabledSort)
- return;
- if (activeId === overId)
- return;
- const {setColumnOrder} = table;
- setColumnOrder(function(prev) {
- const fromIdx = prev.findIndex(val => val === activeId),
- toIdx = prev.findIndex(val => val === overId);
- return arrayMove(prev, fromIdx, toIdx);
- });
- }
- return [
- {...table, active, hasSort, hasGroup},
- {onDragStart, onDragEnd},
- ] as const;
- }
- export function useTableShadow(tableSize: number) {
- const [scrollProgess, setScrollProgess] = useState<'start' | 'process' | 'end'>(
- 'start',
- );
- const scrollTableRef = useRef<HTMLTableElement>(null);
- const headerTableRef = useRef<HTMLDivElement>(null);
- useEffect(
- function() {
- const el = scrollTableRef.current;
- function listener() {
- const elWidth = el?.getBoundingClientRect().width ?? 0,
- scrollWidth = el?.scrollWidth ?? 0,
- scrollLeft = el?.scrollLeft ?? 0;
- headerTableRef.current && (
- headerTableRef.current.scrollLeft = el?.scrollLeft ?? 0
- );
- setScrollProgess(function() {
- if (scrollLeft + elWidth === scrollWidth) return 'end';
- if (scrollLeft === 0) return 'start';
- return 'process';
- });
- }
- listener();
- window.addEventListener('resize', listener);
- el?.addEventListener('scroll', listener);
- return function() {
- window.addEventListener('resize', listener);
- el?.removeEventListener('scroll', listener);
- };
- },
- [tableSize],
- );
- return {scrollProgess, scrollTableRef, headerTableRef};
- }
|