Merge pull request '[AURORA-1148] - стили для таблицы' (#12) from AURORA-1148 into test
Reviewed-on: #12 Reviewed-by: PotapovaA <potapovaanna113@mail.ru>
This commit is contained in:
commit
905fa98ca5
@ -59,13 +59,29 @@ const highlightText = (text, searchQuery) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const INTEGER_COLUMN_IDS = new Set([
|
||||||
|
'data.header.num_group',
|
||||||
|
'data.nomenclature_group_id',
|
||||||
|
'data.header.item_id',
|
||||||
|
'data.article_id',
|
||||||
|
'data.code_razdela',
|
||||||
|
]);
|
||||||
|
|
||||||
// Функция для форматирования числа в финансовый формат
|
// Функция для форматирования числа в финансовый формат
|
||||||
const formatNumber = (value) => {
|
const formatNumber = (value, asInteger = false) => {
|
||||||
if (value === null || value === undefined || value === '') return String(value || '');
|
if (value === null || value === undefined || value === '') return String(value || '');
|
||||||
|
|
||||||
const num = Number(value);
|
const num = Number(value);
|
||||||
if (isNaN(num)) return String(value);
|
if (isNaN(num)) return String(value);
|
||||||
|
|
||||||
|
if (asInteger) {
|
||||||
|
return num.toLocaleString('ru-RU', {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
useGrouping: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return num.toLocaleString('ru-RU', {
|
return num.toLocaleString('ru-RU', {
|
||||||
minimumFractionDigits: 1,
|
minimumFractionDigits: 1,
|
||||||
maximumFractionDigits: 1,
|
maximumFractionDigits: 1,
|
||||||
@ -84,7 +100,8 @@ const Cell = React.memo(({ cell, row, column, onClick, globalFilter, backgroundC
|
|||||||
|
|
||||||
const isNumeric = !isNaN(Number(cellValue)) && cellValue !== null && cellValue !== undefined && cellValue !== '';
|
const isNumeric = !isNaN(Number(cellValue)) && cellValue !== null && cellValue !== undefined && cellValue !== '';
|
||||||
if (isNumeric) {
|
if (isNumeric) {
|
||||||
textValue = formatNumber(cellValue);
|
const asInteger = INTEGER_COLUMN_IDS.has(column.id);
|
||||||
|
textValue = formatNumber(cellValue, asInteger);
|
||||||
}
|
}
|
||||||
|
|
||||||
const highlightedContent = useMemo(() => {
|
const highlightedContent = useMemo(() => {
|
||||||
|
|||||||
@ -0,0 +1,148 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
|
const toLocalCoord = (value, scale) => value / scale;
|
||||||
|
|
||||||
|
const getPinnedClipLeft = (container, overlayParent, columnPinning, scale) => {
|
||||||
|
const pinnedIds = (columnPinning?.left || []).filter(Boolean);
|
||||||
|
if (!pinnedIds.length) return 0;
|
||||||
|
|
||||||
|
const parentRect = overlayParent.getBoundingClientRect();
|
||||||
|
let maxRight = 0;
|
||||||
|
|
||||||
|
for (const id of pinnedIds) {
|
||||||
|
const el = container.querySelector(`[data-col-select-id="${id}"]`);
|
||||||
|
if (!el) continue;
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
maxRight = Math.max(maxRight, rect.right - parentRect.left);
|
||||||
|
}
|
||||||
|
|
||||||
|
return toLocalCoord(maxRight, scale);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOverlayRect = (container, overlayParent, selectedColumnId, columnPinning, scale) => {
|
||||||
|
const columnEl = container.querySelector(
|
||||||
|
`[data-col-select-id="${selectedColumnId}"]`,
|
||||||
|
);
|
||||||
|
if (!columnEl || !overlayParent) return null;
|
||||||
|
|
||||||
|
const bodyCell = container.querySelector(
|
||||||
|
`td[data-col-id="${selectedColumnId}"]`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const parentRect = overlayParent.getBoundingClientRect();
|
||||||
|
const containerRect = container.getBoundingClientRect();
|
||||||
|
const columnRect = columnEl.getBoundingClientRect();
|
||||||
|
const alignRect = bodyCell?.getBoundingClientRect() ?? columnRect;
|
||||||
|
|
||||||
|
let top = toLocalCoord(columnRect.top - parentRect.top, scale);
|
||||||
|
let left = toLocalCoord(alignRect.left - parentRect.left, scale);
|
||||||
|
let width = toLocalCoord(alignRect.width, scale);
|
||||||
|
const height = toLocalCoord(containerRect.bottom - columnRect.top, scale);
|
||||||
|
|
||||||
|
const pinnedIds = (columnPinning?.left || []).filter(Boolean);
|
||||||
|
const isSelectedPinned = pinnedIds.includes(selectedColumnId);
|
||||||
|
|
||||||
|
if (!isSelectedPinned && pinnedIds.length) {
|
||||||
|
const clipLeft = getPinnedClipLeft(container, overlayParent, columnPinning, scale);
|
||||||
|
const overlayRight = left + width;
|
||||||
|
if (overlayRight <= clipLeft) return null;
|
||||||
|
if (left < clipLeft) {
|
||||||
|
width = overlayRight - clipLeft;
|
||||||
|
left = clipLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width <= 0 || height <= 0) return null;
|
||||||
|
|
||||||
|
return { top, left, width, height };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ColumnSelectionOverlay = ({
|
||||||
|
selectedColumnId,
|
||||||
|
containerRef,
|
||||||
|
scale = 1,
|
||||||
|
columnSizing,
|
||||||
|
columnPinning,
|
||||||
|
showColumnFilters,
|
||||||
|
}) => {
|
||||||
|
const [rect, setRect] = useState(null);
|
||||||
|
const [portalTarget, setPortalTarget] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const container = containerRef.current;
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
const overlayParent = container.parentElement;
|
||||||
|
setPortalTarget(overlayParent);
|
||||||
|
}, [containerRef, selectedColumnId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const container = containerRef.current;
|
||||||
|
const overlayParent = container?.parentElement;
|
||||||
|
if (!selectedColumnId || !container || !overlayParent) {
|
||||||
|
setRect(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateRect = () => {
|
||||||
|
setRect(getOverlayRect(container, overlayParent, selectedColumnId, columnPinning, scale));
|
||||||
|
};
|
||||||
|
|
||||||
|
updateRect();
|
||||||
|
|
||||||
|
const scrollTargets = new Set([container]);
|
||||||
|
let scrollParent = container.parentElement;
|
||||||
|
for (let i = 0; i < 3 && scrollParent; i += 1) {
|
||||||
|
scrollTargets.add(scrollParent);
|
||||||
|
scrollParent = scrollParent.parentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollTargets.forEach((target) => {
|
||||||
|
target.addEventListener('scroll', updateRect, { passive: true });
|
||||||
|
});
|
||||||
|
window.addEventListener('resize', updateRect);
|
||||||
|
|
||||||
|
const resizeObserver = new ResizeObserver(updateRect);
|
||||||
|
resizeObserver.observe(container);
|
||||||
|
resizeObserver.observe(overlayParent);
|
||||||
|
|
||||||
|
const header = container.querySelector('.custom-table-header');
|
||||||
|
if (header) {
|
||||||
|
resizeObserver.observe(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableBody = container.querySelector('.MuiTableBody-root');
|
||||||
|
if (tableBody) {
|
||||||
|
resizeObserver.observe(tableBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
scrollTargets.forEach((target) => {
|
||||||
|
target.removeEventListener('scroll', updateRect);
|
||||||
|
});
|
||||||
|
window.removeEventListener('resize', updateRect);
|
||||||
|
resizeObserver.disconnect();
|
||||||
|
};
|
||||||
|
}, [selectedColumnId, containerRef, scale, columnSizing, columnPinning, showColumnFilters]);
|
||||||
|
|
||||||
|
if (!rect || !portalTarget) return null;
|
||||||
|
|
||||||
|
return createPortal(
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: rect.top,
|
||||||
|
left: rect.left,
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
backgroundColor: 'rgba(88, 154, 47, 0.2)',
|
||||||
|
border: '1px solid #589A2F',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
zIndex: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
portalTarget,
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -11,13 +11,14 @@ import { getTableColumns } from './tableColumns';
|
|||||||
import { Cell, EditCell } from './index';
|
import { Cell, EditCell } from './index';
|
||||||
import { TableHead } from './TableHead/TableHead';
|
import { TableHead } from './TableHead/TableHead';
|
||||||
import SettingsPanel from './SettingPanel/SettingPanel';
|
import SettingsPanel from './SettingPanel/SettingPanel';
|
||||||
|
import { ColumnSelectionOverlay } from './ColumnSelectionOverlay/ColumnSelectionOverlay';
|
||||||
|
|
||||||
import { useColumnSettings } from './hooks/useColumnSettings';
|
import { useColumnSettings } from './hooks/useColumnSettings';
|
||||||
import { useTableScale } from './hooks/useTableScale';
|
import { useTableScale } from './hooks/useTableScale';
|
||||||
import { useHeaderPortal } from './hooks/useHeaderPortal';
|
import { useHeaderPortal } from './hooks/useHeaderPortal';
|
||||||
import {
|
import {
|
||||||
BASE_TABLE_CONFIG,
|
BASE_TABLE_CONFIG,
|
||||||
getTableHeadCellStyles,
|
getTableBodyCellProps,
|
||||||
getTablePaperStyles,
|
getTablePaperStyles,
|
||||||
TABLE_ROW_HEIGHT,
|
TABLE_ROW_HEIGHT,
|
||||||
} from './constants/tableConfig';
|
} from './constants/tableConfig';
|
||||||
@ -29,7 +30,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
const { data, setData, isLoading: isTableLoading, editingCells: dataEditingCells } = useRealtimeData(formId, sheetName, direction);
|
const { data, setData, isLoading: isTableLoading, editingCells: dataEditingCells } = useRealtimeData(formId, sheetName, direction);
|
||||||
const [globalFilter, setGlobalFilter] = useState('');
|
const [globalFilter, setGlobalFilter] = useState('');
|
||||||
const [showColumnFilters, setShowColumnFilters] = useState(false);
|
const [showColumnFilters, setShowColumnFilters] = useState(false);
|
||||||
const [selectedColumn, setSelectedColumn] = useState();
|
const [selectedColumnId, setSelectedColumnId] = useState();
|
||||||
const [rowSelection, setRowSelection] = useState({});
|
const [rowSelection, setRowSelection] = useState({});
|
||||||
const [isLoadingData, setIsLoadingData] = useState(false);
|
const [isLoadingData, setIsLoadingData] = useState(false);
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
@ -102,6 +103,26 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
}));
|
}));
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const handleColumnSelect = useCallback((columnId) => {
|
||||||
|
setSelectedColumnId((prev) => {
|
||||||
|
const next = prev === columnId ? undefined : columnId;
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedColumnId) return;
|
||||||
|
|
||||||
|
const handleDocumentClick = (e) => {
|
||||||
|
if (e.target.closest('[data-col-select-id]')) return;
|
||||||
|
if (e.target.closest('[data-pin-panel]')) return;
|
||||||
|
|
||||||
|
setSelectedColumnId(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('mousedown', handleDocumentClick);
|
||||||
|
return () => document.removeEventListener('mousedown', handleDocumentClick);
|
||||||
|
}, [selectedColumnId]);
|
||||||
|
|
||||||
const columns = useMemo(() => {
|
const columns = useMemo(() => {
|
||||||
if (!columnsConfig || !columnsConfig.columns) return [];
|
if (!columnsConfig || !columnsConfig.columns) return [];
|
||||||
@ -121,11 +142,12 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
console.error('Error creating columns:', error);
|
console.error('Error creating columns:', error);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}, [columnsConfig, handleUpdateCell]);
|
}, [columnsConfig, handleUpdateCell, handleClickRowCell]);
|
||||||
|
|
||||||
const tableMeta = useMemo(() => ({
|
const tableMeta = useMemo(() => ({
|
||||||
updateCell: handleUpdateCell,
|
updateCell: handleUpdateCell,
|
||||||
}), [handleUpdateCell]);
|
selectedColumnId,
|
||||||
|
}), [handleUpdateCell, selectedColumnId]);
|
||||||
|
|
||||||
// Конфигурация таблицы
|
// Конфигурация таблицы
|
||||||
const tableConfig = useMemo(
|
const tableConfig = useMemo(
|
||||||
@ -188,7 +210,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
muiTableHeadCellProps: {
|
muiTableHeadCellProps: {
|
||||||
sx: { boxSizing: 'border-box' },
|
sx: { boxSizing: 'border-box' },
|
||||||
},
|
},
|
||||||
muiTableBodyCellProps: getTableHeadCellStyles,
|
muiTableBodyCellProps: getTableBodyCellProps,
|
||||||
muiTableHeadProps: {
|
muiTableHeadProps: {
|
||||||
sx: {
|
sx: {
|
||||||
display: 'table-header-group',
|
display: 'table-header-group',
|
||||||
@ -301,7 +323,8 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsPanel
|
<SettingsPanel
|
||||||
selectedColumn={selectedColumn}
|
selectedColumnId={selectedColumnId}
|
||||||
|
columnPinning={columnPinning}
|
||||||
table={table}
|
table={table}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
onPinColumn={handlePinColumn}
|
onPinColumn={handlePinColumn}
|
||||||
@ -333,6 +356,15 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
>
|
>
|
||||||
<MaterialReactTable table={table} />
|
<MaterialReactTable table={table} />
|
||||||
|
|
||||||
|
<ColumnSelectionOverlay
|
||||||
|
selectedColumnId={selectedColumnId}
|
||||||
|
containerRef={containerRef}
|
||||||
|
scale={sizeMult}
|
||||||
|
columnSizing={columnSizing}
|
||||||
|
columnPinning={columnPinning}
|
||||||
|
showColumnFilters={showColumnFilters}
|
||||||
|
/>
|
||||||
|
|
||||||
{isTableLoading && (
|
{isTableLoading && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -354,8 +386,8 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
<TableHead
|
<TableHead
|
||||||
table={table}
|
table={table}
|
||||||
style={{ zIndex: (theme) => theme.zIndex.modal - 1 }}
|
style={{ zIndex: (theme) => theme.zIndex.modal - 1 }}
|
||||||
onHeaderSelect={setSelectedColumn}
|
selectedColumnId={selectedColumnId}
|
||||||
selectHeader={selectedColumn}
|
onColumnSelect={handleColumnSelect}
|
||||||
onChangeWidth={handleSetColumnWidth}
|
onChangeWidth={handleSetColumnWidth}
|
||||||
isLoadingData={isLoadingData}
|
isLoadingData={isLoadingData}
|
||||||
/>,
|
/>,
|
||||||
|
|||||||
@ -21,7 +21,8 @@ import { ExportDefaultButton } from '../../common/Buttons/ButtonsActions';
|
|||||||
import { exportSheet } from '../../../utils/exportForm';
|
import { exportSheet } from '../../../utils/exportForm';
|
||||||
|
|
||||||
const SettingPanel = ({
|
const SettingPanel = ({
|
||||||
selectedColumn,
|
selectedColumnId,
|
||||||
|
columnPinning,
|
||||||
table,
|
table,
|
||||||
columns,
|
columns,
|
||||||
onPinColumn,
|
onPinColumn,
|
||||||
@ -44,12 +45,16 @@ const SettingPanel = ({
|
|||||||
const [selectedColumnIds, setSelectedColumnIds] = useState();
|
const [selectedColumnIds, setSelectedColumnIds] = useState();
|
||||||
const [showColumnFilters, setShowColumnFilters] = useState(false);
|
const [showColumnFilters, setShowColumnFilters] = useState(false);
|
||||||
|
|
||||||
|
// TODO: console.log(!!!) везде посомтреть
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedColumn) return;
|
if (!selectedColumnId) {
|
||||||
const pinningColumn = table.getState().columnPinning.left;
|
setIsPinned(false);
|
||||||
const isPinned = pinningColumn.includes(selectedColumn.id);
|
return;
|
||||||
setIsPinned(isPinned);
|
}
|
||||||
}, [selectedColumn, table]);
|
const pinningColumn = columnPinning?.left || table.getState().columnPinning.left || [];
|
||||||
|
const pinned = pinningColumn.includes(selectedColumnId);
|
||||||
|
setIsPinned(pinned);
|
||||||
|
}, [selectedColumnId, columnPinning, table]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedColumnIds(
|
setSelectedColumnIds(
|
||||||
@ -79,7 +84,7 @@ const SettingPanel = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Panel>
|
<Panel data-pin-panel>
|
||||||
<Stack direction="row" sx={{ gap: '1.25rem' }}>
|
<Stack direction="row" sx={{ gap: '1.25rem' }}>
|
||||||
<GroupByObject title="Отображение">
|
<GroupByObject title="Отображение">
|
||||||
{/* <ColorPickerButton onColorApply={addColorForCells} /> */}
|
{/* <ColorPickerButton onColorApply={addColorForCells} /> */}
|
||||||
@ -88,11 +93,22 @@ const SettingPanel = ({
|
|||||||
<IconButton
|
<IconButton
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
data-active={isPinned}
|
data-active={isPinned}
|
||||||
onClick={() =>
|
disabled={!selectedColumnId}
|
||||||
|
onMouseDown={(e) => e.stopPropagation()}
|
||||||
|
onClick={() => {
|
||||||
|
if (!selectedColumnId) {
|
||||||
|
console.warn('[ColumnPin] клик Pin: selectedColumnId пустой');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('[ColumnPin] клик Pin:', {
|
||||||
|
selectedColumnId,
|
||||||
|
isPinned,
|
||||||
|
action: isPinned ? 'unpin' : 'pin',
|
||||||
|
});
|
||||||
isPinned
|
isPinned
|
||||||
? onUnpinColumn?.(selectedColumn.id)
|
? onUnpinColumn?.(selectedColumnId)
|
||||||
: onPinColumn?.(selectedColumn.id)
|
: onPinColumn?.(selectedColumnId);
|
||||||
}
|
}}
|
||||||
>
|
>
|
||||||
<Pin />
|
<Pin />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|||||||
@ -2,9 +2,12 @@ import React from 'react';
|
|||||||
import ColumnResizer from './ColumnResizer';
|
import ColumnResizer from './ColumnResizer';
|
||||||
import { columnPinningDefault } from '../constants/columnConfig';
|
import { columnPinningDefault } from '../constants/columnConfig';
|
||||||
|
|
||||||
|
const getPinnedColumnIds = (table) =>
|
||||||
|
(table.getState().columnPinning.left || []).filter(Boolean);
|
||||||
|
|
||||||
const getSortedColumns = (table) => {
|
const getSortedColumns = (table) => {
|
||||||
const allLeafColumns = table.getAllLeafColumns();
|
const allLeafColumns = table.getAllLeafColumns();
|
||||||
const pinnedColumns = table.getState().columnPinning.left || [];
|
const pinnedColumns = getPinnedColumnIds(table);
|
||||||
|
|
||||||
return [...allLeafColumns].sort((a, b) => {
|
return [...allLeafColumns].sort((a, b) => {
|
||||||
const aIsPinned = pinnedColumns.includes(a.id);
|
const aIsPinned = pinnedColumns.includes(a.id);
|
||||||
@ -46,7 +49,7 @@ const getPinnedColumnsWidth = (header, pinningColumn) => {
|
|||||||
|
|
||||||
const calculateLeftOffset = (table, columnOrHeader) => {
|
const calculateLeftOffset = (table, columnOrHeader) => {
|
||||||
const columnId = getColumnId(columnOrHeader);
|
const columnId = getColumnId(columnOrHeader);
|
||||||
const pinnedColumns = table.getState().columnPinning.left || [];
|
const pinnedColumns = getPinnedColumnIds(table);
|
||||||
const currentPinnedIndex = pinnedColumns.indexOf(columnId);
|
const currentPinnedIndex = pinnedColumns.indexOf(columnId);
|
||||||
|
|
||||||
let leftOffset = 0;
|
let leftOffset = 0;
|
||||||
@ -64,13 +67,13 @@ const calculateLeftOffset = (table, columnOrHeader) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isColumnPin = (table, header) => {
|
const isColumnPin = (table, header) => {
|
||||||
const pinningColumn = table.getState().columnPinning.left;
|
const pinningColumn = getPinnedColumnIds(table);
|
||||||
const columnId = getColumnId(header);
|
const columnId = getColumnId(header);
|
||||||
const isPinned = pinningColumn.includes(columnId);
|
const isPinned = pinningColumn.includes(columnId);
|
||||||
return isPinned;
|
return isPinned;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ColumnNumbersRow = ({ table }) => {
|
const ColumnNumbersRow = ({ table, selectedColumnId, onColumnSelect }) => {
|
||||||
const sortedColumns = getSortedColumns(table);
|
const sortedColumns = getSortedColumns(table);
|
||||||
const tableState = table.getState();
|
const tableState = table.getState();
|
||||||
const filteredColumns = sortedColumns.filter(
|
const filteredColumns = sortedColumns.filter(
|
||||||
@ -95,27 +98,38 @@ const ColumnNumbersRow = ({ table }) => {
|
|||||||
key={`col-number-${column.id}`}
|
key={`col-number-${column.id}`}
|
||||||
column={column}
|
column={column}
|
||||||
table={table}
|
table={table}
|
||||||
|
selectedColumnId={selectedColumnId}
|
||||||
|
onColumnSelect={onColumnSelect}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ColumnNumberCell = ({ column, table }) => {
|
const ColumnNumberCell = ({ column, table, selectedColumnId, onColumnSelect }) => {
|
||||||
const isPinned = isColumnPin(table, column);
|
const isPinned = isColumnPin(table, column);
|
||||||
const allLeafColumns = table.getAllLeafColumns();
|
const allLeafColumns = table.getAllLeafColumns();
|
||||||
const originalIndex = allLeafColumns.findIndex((col) => col.id === column.id);
|
const originalIndex = allLeafColumns.findIndex((col) => col.id === column.id);
|
||||||
const leftOffset = calculateLeftOffset(table, column);
|
const leftOffset = calculateLeftOffset(table, column);
|
||||||
|
const selected = selectedColumnId === column.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`col-number-${column.id}`}
|
key={`col-number-${column.id}`}
|
||||||
|
data-col-select-id={column.id}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onColumnSelect?.(column.id);
|
||||||
|
}}
|
||||||
|
onMouseDown={(e) => e.stopPropagation()}
|
||||||
style={{
|
style={{
|
||||||
width: column.getSize(),
|
width: column.getSize(),
|
||||||
minWidth: column.getSize(),
|
minWidth: column.getSize(),
|
||||||
maxWidth: column.getSize(),
|
maxWidth: column.getSize(),
|
||||||
padding: '2px 6px',
|
padding: '2px 6px',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
backgroundColor: '#e5e5e5',
|
backgroundColor: selected ? '#589A2F' : '#FBFBFB',
|
||||||
|
color: selected ? '#ffffff' : '#5E5E5E',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@ -125,7 +139,9 @@ const ColumnNumberCell = ({ column, table }) => {
|
|||||||
borderBottom: 'none',
|
borderBottom: 'none',
|
||||||
position: isPinned ? 'sticky' : 'relative',
|
position: isPinned ? 'sticky' : 'relative',
|
||||||
left: isPinned ? leftOffset : 'auto',
|
left: isPinned ? leftOffset : 'auto',
|
||||||
zIndex: isPinned ? 20 : 'auto',
|
zIndex: selected ? 16 : isPinned ? 20 : 'auto',
|
||||||
|
cursor: 'pointer',
|
||||||
|
userSelect: 'none',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{originalIndex}
|
{originalIndex}
|
||||||
@ -133,9 +149,9 @@ const ColumnNumberCell = ({ column, table }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const HeaderCell = ({ header, table, onClick, hightlight, onChangeWidth }) => {
|
const HeaderCell = ({ header, table, onClick, onChangeWidth }) => {
|
||||||
const column = header.column;
|
const column = header.column;
|
||||||
const pinningColumn = table.getState().columnPinning.left || [];
|
const pinningColumn = getPinnedColumnIds(table);
|
||||||
const isGroup = header.subHeaders?.length > 0;
|
const isGroup = header.subHeaders?.length > 0;
|
||||||
const isPinned = isColumnPin(table, header);
|
const isPinned = isColumnPin(table, header);
|
||||||
const leftOffset = calculateLeftOffset(table, header);
|
const leftOffset = calculateLeftOffset(table, header);
|
||||||
@ -148,7 +164,7 @@ const HeaderCell = ({ header, table, onClick, hightlight, onChangeWidth }) => {
|
|||||||
|
|
||||||
const backgroundColor = customBgColor
|
const backgroundColor = customBgColor
|
||||||
? customBgColor
|
? customBgColor
|
||||||
: (hightlight ? '#cbccce' : 'rgba(243, 244, 246, 1)');
|
: 'rgba(243, 244, 246, 1)';
|
||||||
|
|
||||||
const handleChangeWidth = (deltaWidth) => {
|
const handleChangeWidth = (deltaWidth) => {
|
||||||
const size = header.getSize();
|
const size = header.getSize();
|
||||||
@ -164,7 +180,7 @@ const HeaderCell = ({ header, table, onClick, hightlight, onChangeWidth }) => {
|
|||||||
}
|
}
|
||||||
// Для незакрепленных колонок текст должен начинаться после всех закрепленных
|
// Для незакрепленных колонок текст должен начинаться после всех закрепленных
|
||||||
// Получаем общую ширину всех закрепленных колонок
|
// Получаем общую ширину всех закрепленных колонок
|
||||||
const pinnedColumns = table.getState().columnPinning.left || [];
|
const pinnedColumns = getPinnedColumnIds(table);
|
||||||
let totalPinnedWidth = 0;
|
let totalPinnedWidth = 0;
|
||||||
for (const pinnedId of pinnedColumns) {
|
for (const pinnedId of pinnedColumns) {
|
||||||
const pinnedCol = table.getColumn(pinnedId);
|
const pinnedCol = table.getColumn(pinnedId);
|
||||||
@ -188,6 +204,7 @@ const HeaderCell = ({ header, table, onClick, hightlight, onChangeWidth }) => {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
fontSize: '12px',
|
fontSize: '12px',
|
||||||
|
lineHeight: 1,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
color: '#424242',
|
color: '#424242',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
@ -379,13 +396,15 @@ const FilterCell = ({ column, table }) => {
|
|||||||
|
|
||||||
export const TableHead = ({
|
export const TableHead = ({
|
||||||
table,
|
table,
|
||||||
onHeaderSelect,
|
selectedColumnId,
|
||||||
selectHeader,
|
onColumnSelect,
|
||||||
onChangeWidth,
|
onChangeWidth,
|
||||||
isLoadingData,
|
isLoadingData,
|
||||||
}) => {
|
}) => {
|
||||||
const handleHeaderClick = (header) => {
|
const handleHeaderClick = (header) => {
|
||||||
onHeaderSelect(header);
|
if (!header.subHeaders?.length && header.column?.id) {
|
||||||
|
onColumnSelect?.(header.column.id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isLoadingData) {
|
if (!isLoadingData) {
|
||||||
@ -402,9 +421,15 @@ export const TableHead = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Строка с номерами колонок */}
|
{/* Строка с номерами колонок */}
|
||||||
<ColumnNumbersRow table={table} />
|
<ColumnNumbersRow
|
||||||
|
table={table}
|
||||||
|
selectedColumnId={selectedColumnId}
|
||||||
|
onColumnSelect={onColumnSelect}
|
||||||
|
/>
|
||||||
|
|
||||||
{table.getState().showColumnFilters && <FilterRow table={table} />}
|
{table.getState().showColumnFilters && (
|
||||||
|
<FilterRow table={table} />
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Существующие строки заголовков */}
|
{/* Существующие строки заголовков */}
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
@ -413,9 +438,6 @@ export const TableHead = ({
|
|||||||
<React.Fragment key={header.id}>
|
<React.Fragment key={header.id}>
|
||||||
<HeaderCell
|
<HeaderCell
|
||||||
header={header}
|
header={header}
|
||||||
hightlight={
|
|
||||||
selectHeader ? header.id == selectHeader.id : false
|
|
||||||
}
|
|
||||||
table={table}
|
table={table}
|
||||||
onClick={handleHeaderClick}
|
onClick={handleHeaderClick}
|
||||||
onChangeWidth={onChangeWidth}
|
onChangeWidth={onChangeWidth}
|
||||||
|
|||||||
@ -45,6 +45,18 @@ export const getTableHeadCellStyles = () => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const getTableBodyCellProps = ({ column, table }) => {
|
||||||
|
const isPinned = (table.getState().columnPinning?.left || []).includes(column.id);
|
||||||
|
|
||||||
|
return {
|
||||||
|
'data-col-id': column.id,
|
||||||
|
sx: {
|
||||||
|
...getTableHeadCellStyles().sx,
|
||||||
|
...(isPinned && { zIndex: 5 }),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const getTablePaperStyles = () => ({
|
export const getTablePaperStyles = () => ({
|
||||||
sx: {
|
sx: {
|
||||||
boxShadow: "none",
|
boxShadow: "none",
|
||||||
|
|||||||
@ -41,6 +41,7 @@ export const useColumnSettings = (tableKey) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleUnpinColumn = useCallback((colId) => {
|
const handleUnpinColumn = useCallback((colId) => {
|
||||||
|
if (!colId) return;
|
||||||
if (columnPinningDefault.left.includes(colId)) return;
|
if (columnPinningDefault.left.includes(colId)) return;
|
||||||
setColumnPinning((prev) => ({
|
setColumnPinning((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user