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) => (
))}
))}
>
);
};