import React from 'react'; import ColumnResizer from './ColumnResizer'; const getSortedColumns = (table) => { const allLeafColumns = table.getAllLeafColumns(); const pinnedColumns = table.getState().columnPinning.left || []; return [...allLeafColumns].sort((a, b) => { const aIsPinned = pinnedColumns.includes(a.id); const bIsPinned = pinnedColumns.includes(b.id); if (aIsPinned && bIsPinned) { return pinnedColumns.indexOf(a.id) - pinnedColumns.indexOf(b.id); } if (aIsPinned) return -1; if (bIsPinned) return 1; return 0; }); }; const calculateLeftOffset = (table, columnOrHeader) => { const columnId = columnOrHeader.id.match(/data\..*$/)?.[0] || columnOrHeader.id; const pinnedColumns = table.getState().columnPinning.left || []; const currentPinnedIndex = pinnedColumns.indexOf(columnId); let leftOffset = 0; if (currentPinnedIndex > 0) { for (let i = 0; i < currentPinnedIndex; i++) { const prevColumn = table.getColumn(pinnedColumns[i]); if (prevColumn) { leftOffset += prevColumn.getSize(); } } } return leftOffset; }; const isColumnPin = (table, header) => { const pinningColumn = table.getState().columnPinning.left; //в header.id содержаться колонки по типу depth_idColParent_idChild, а в pinningColumn только idCol, которые закреплены //header.id.split('_').at(-1) - получение самой нижней колонки const columnId = header.id.match(/data\..*$/)?.[0] || header.id; const isPinned = pinningColumn.includes(columnId); return isPinned; }; const ColumnNumbersRow = ({ table }) => { const sortedColumns = getSortedColumns(table); const tableState = table.getState(); const filteredColumns = sortedColumns.filter( (col) => !(col.id in tableState.columnVisibility) || (col.id in tableState.columnVisibility && tableState.columnVisibility[col.id]), ); return (
theme.zIndex.table + 1, backgroundColor: 'white', }} > {filteredColumns.map((column) => ( ))}
); }; const ColumnNumberCell = ({ column, table }) => { const isPinned = isColumnPin(table, column); const allLeafColumns = table.getAllLeafColumns(); const originalIndex = allLeafColumns.findIndex((col) => col.id === column.id); const leftOffset = calculateLeftOffset(table, column); return (
{originalIndex}
); }; const HeaderCell = ({ header, table, onClick, hightlight, onChangeWidth }) => { const column = header.column; const isPinned = isColumnPin(table, header); const leftOffset = calculateLeftOffset(table, header); const customBgColor = column.columnDef?.muiTableHeadCellProps?.sx?.backgroundColor; const color = column.columnDef?.muiTableHeadCellProps?.sx?.color || '#000000'; const backgroundColor = customBgColor ? customBgColor : (hightlight ? '#cbccce' : 'rgba(243, 244, 246, 1)'); const handleChangeWidth = (deltaWidth) => { const size = header.getSize(); onChangeWidth(header, size + deltaWidth); }; // Вычисляем отступ для текста внутри ячейки // Если колонка закреплена, текст должен быть привязан к левому краю ячейки // Если колонка не закреплена, текст должен начинаться после всех закрепленных колонок const getTextLeftOffset = () => { if (isPinned) { return '0'; } // Для незакрепленных колонок текст должен начинаться после всех закрепленных // Получаем общую ширину всех закрепленных колонок const pinnedColumns = table.getState().columnPinning.left || []; let totalPinnedWidth = 0; for (const pinnedId of pinnedColumns) { const pinnedCol = table.getColumn(pinnedId); if (pinnedCol) { totalPinnedWidth += pinnedCol.getSize(); } } return `${totalPinnedWidth}px`; }; return (
onClick(header)} style={{ width: header.getSize() + 'px', minWidth: header.getSize() + 'px', maxWidth: header.getSize() + 'px', position: 'relative', padding: '4px 6px', textAlign: 'center', fontWeight: 600, fontSize: '12px', backgroundColor: backgroundColor, color: '#424242', boxSizing: 'border-box', display: 'flex', alignItems: 'center', justifyContent: 'center', height: '3rem', border: '.063rem solid rgba(209, 213, 220, 1)', }} >
{header.isPlaceholder ? null : column.columnDef.header}
); }; const FilterRow = ({ table }) => { const sortedColumns = getSortedColumns(table); const tableState = table.getState(); const filteredColumns = sortedColumns.filter( (col) => !(col.id in tableState.columnVisibility) || (col.id in tableState.columnVisibility && tableState.columnVisibility[col.id]), ); return (
{filteredColumns.map((column) => ( ))}
); }; // Компонент ячейки фильтра const FilterCell = ({ column, table }) => { const isPinned = isColumnPin(table, column); const leftOffset = calculateLeftOffset(table, column); // Определяем тип фильтра на основе колонки const filterVariant = column.columnDef.filterVariant || 'text'; // Для select фильтра const selectOptions = column.columnDef.filterSelectOptions || []; const handleFilterChange = (value) => { column.setFilterValue(value); }; // Рендер разных типов фильтров const renderFilterInput = () => { switch (filterVariant) { case 'select': return ( ); case 'range': { // Для диапазона можно реализовать два поля const [min, max] = column.getFilterValue() || ['', '']; return (
column.setFilterValue([e.target.value, max])} style={{ width: '50%', padding: '4px', fontSize: '11px' }} /> column.setFilterValue([min, e.target.value])} style={{ width: '50%', padding: '4px', fontSize: '11px' }} />
); } default: // 'text' return ( handleFilterChange(e.target.value)} placeholder="Поиск..." style={{ width: '100%', padding: '4px 6px', fontSize: '11px', border: '1px solid #ddd', borderRadius: '4px', boxSizing: 'border-box', }} /> ); } }; return (
{renderFilterInput()}
); }; export const TableHead = ({ table, onHeaderSelect, selectHeader, onChangeWidth, isLoadingData, }) => { const handleHeaderClick = (header) => { onHeaderSelect(header); }; if (!isLoadingData) { return
} return ( <>
theme.zIndex.table, position: 'relative', width: 'max-content', }} > {/* Строка с номерами колонок */} {table.getState().showColumnFilters && } {/* Существующие строки заголовков */} {table.getHeaderGroups().map((headerGroup) => (
{headerGroup.headers.map((header) => ( ))}
))}
); };