From dc621a1223d6e86838de9940ad42b6073908849c Mon Sep 17 00:00:00 2001 From: PotapovaA Date: Fri, 17 Jul 2026 17:18:26 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20sort-order=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B8/=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RealtimeTable/utils/cellUtils.js | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/web/src/components/RealtimeTable/utils/cellUtils.js b/web/src/components/RealtimeTable/utils/cellUtils.js index 8236b09..304a8ab 100644 --- a/web/src/components/RealtimeTable/utils/cellUtils.js +++ b/web/src/components/RealtimeTable/utils/cellUtils.js @@ -84,7 +84,6 @@ export function updateCells(data, newRows) { Object.keys(newData).forEach((key) => { if (row.data && row.data[key]) { if (typeof row.data[key] === "object") { - console.log(newData[key], row.data[key], key, newData); row.data[key] = deepMerge(row.data[key], newData[key]); } else { row.data[key] = newData[key]; @@ -132,24 +131,30 @@ export function insertCell(data, newRow, expense_item_id) { return updatedRows; } + let adding = false; function findAndUpdate(rows) { for (let i = 0; i < rows.length; i++) { const row = rows[i]; - if (row.data.header.expense_item_id === expense_item_id) { + if ( + (row.sort_order >= newRowObject.sort_order) & + (row.data.line_id != newRowObject.data.line_id) + ) { + row.sort_order = row.sort_order + 1; + } + + if (!adding & (row.data.header.expense_item_id === expense_item_id)) { if (!("subRows" in row)) { row.subRows = []; } row.subRows.push(newRowObject); - return true; + adding = true; } if (row.subRows && Array.isArray(row.subRows) && row.subRows.length > 0) { const found = findAndUpdate(row.subRows); - if (found) return true; } } - return false; } findAndUpdate(updatedRows); return updatedRows; @@ -158,21 +163,25 @@ export function insertCell(data, newRow, expense_item_id) { export function deleteRow(data, lineId) { const updatedRows = JSON.parse(JSON.stringify(data)); + let rowDeleteSortOrder = false; function findAndDelete(rows) { for (let i = 0; i < rows.length; i++) { const row = rows[i]; if (row.data.line_id == lineId) { + rowDeleteSortOrder = row.sort_order; rows.splice(i, 1); - return true; + i--; + } + + if ((rowDeleteSortOrder > 0) & (row.sort_order >= rowDeleteSortOrder)) { + row.sort_order = row.sort_order - 1; } if (row.subRows && Array.isArray(row.subRows) && row.subRows.length > 0) { const found = findAndDelete(row.subRows); - if (found) return true; } } - return false; } findAndDelete(updatedRows); return updatedRows; From 096a8b817fd04cb754e6c0bf2c34cadcb4f41be6 Mon Sep 17 00:00:00 2001 From: PotapovaA Date: Mon, 20 Jul 2026 11:30:51 +0300 Subject: [PATCH 2/3] =?UTF-8?q?=D0=BE=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=BC=D1=8F=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RealtimeTable/RealtimeTable.jsx | 256 +++++++++++------- 1 file changed, 152 insertions(+), 104 deletions(-) diff --git a/web/src/components/RealtimeTable/RealtimeTable.jsx b/web/src/components/RealtimeTable/RealtimeTable.jsx index c40ca7e..c3bdbac 100644 --- a/web/src/components/RealtimeTable/RealtimeTable.jsx +++ b/web/src/components/RealtimeTable/RealtimeTable.jsx @@ -134,6 +134,11 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => { return () => document.removeEventListener('mousedown', handleDocumentClick); }, [selectedColumnId]); + const handleCellUpdateError = useCallback((rowId, columnId, error) => { + console.error(`Error updating cell ${rowId}_${columnId}:`, error); + toast.error('Ошибка обновления ячейки'); + }, []); + const columns = useMemo(() => { if (!columnsConfig || !columnsConfig.columns) return []; try { @@ -143,128 +148,160 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => { columnsConfig, onCellUpdate: handleUpdateCell, onCellNumberClick: handleClickRowCell, - onCellUpdateError: (rowId, columnId, error) => { - console.error(`Error updating cell ${rowId}_${columnId}:`, error); - toast.error('Ошибка обновления ячейки') - } + onCellUpdateError: handleCellUpdateError, }); } catch (error) { console.error('Error creating columns:', error); return []; } - }, [columnsConfig, handleUpdateCell, handleClickRowCell]); + }, [columnsConfig, handleUpdateCell, handleClickRowCell, handleCellUpdateError]); + + const selectedColumnIdRef = useRef(selectedColumnId); + + useEffect(() => { + selectedColumnIdRef.current = selectedColumnId; + }, [selectedColumnId]); const tableMeta = useMemo(() => ({ updateCell: handleUpdateCell, - selectedColumnId, - }), [handleUpdateCell, selectedColumnId]); + getSelectedColumnId: () => selectedColumnIdRef.current, + }), [handleUpdateCell]); - // Конфигурация таблицы - const tableConfig = useMemo( - () => ({ - ...BASE_TABLE_CONFIG, - columns, - data: data, - enableRowVirtualization: true, - enableColumnVirtualization: true, - rowVirtualizerInstanceRef: rowVirtualizerRef, - rowVirtualizerOptions: { - overscan: 30, - scrollPaddingStart: 0, - scrollPaddingEnd: 0, - estimateSize: () => TABLE_ROW_HEIGHT, - measureElement: (el) => el?.offsetHeight || TABLE_ROW_HEIGHT, - }, - onEditingCellChange: (cell) => { - if (cell) { - if (editingCell) return; - contextStartEditing?.(cell.row, cell.column); + const ROW_VIRTUALIZER_OPTIONS = { + overscan: 30, + scrollPaddingStart: 0, + scrollPaddingEnd: 0, + estimateSize: () => TABLE_ROW_HEIGHT, + measureElement: (el) => el?.offsetHeight || TABLE_ROW_HEIGHT, + }; + + const createTableConfig = ({ + columns, + data, + columnSizing, + columnPinning, + columnVisibility, + globalFilter, + showColumnFilters, + rowSelection, + containerRef, + tableMeta, + setColumnSizing, + setColumnPinning, + editingCell, + contextStartEditing, + }) => ({ + ...BASE_TABLE_CONFIG, + columns, + data, + enableRowVirtualization: true, + enableColumnVirtualization: true, + rowVirtualizerInstanceRef: rowVirtualizerRef, + rowVirtualizerOptions: ROW_VIRTUALIZER_OPTIONS, + onEditingCellChange: (cell) => { + if (cell && !editingCell) { + contextStartEditing?.(cell.row, cell.column); + } + }, + columnVirtualizerOptions: ({ table }) => ({ + overscan: 10, + measureElement: (el) => { + if (!el) return 150; + const index = Number(el?.getAttribute?.('data-index')); + const isPinned = Boolean(el?.getAttribute?.('data-pinned')); + if (isPinned) { + const colId = table.getState().columnPinning.left[index]; + const column = table.getColumn(colId); + return column?.getSize() ?? 150; } - }, - columnVirtualizerOptions: ({ table }) => ({ - overscan: 10, - measureElement: (el) => { - if (!el) return 150; - const index = Number(el?.getAttribute?.('data-index')); - const isPinned = Boolean(el?.getAttribute?.('data-pinned')); - if (isPinned) { - const colId = table.getState().columnPinning.left[index]; - const column = table.getColumn(colId); - return column?.getSize() ?? 150; - } - const allCols = [...table.getLeftVisibleLeafColumns(), ...table.getCenterVisibleLeafColumns()] - return allCols[index]?.getSize() ?? 150; - - }, - }), - enableRowSelection: true, - onRowSelectionChange: setRowSelection, - onColumnSizingChange: setColumnSizing, - onColumnPinningChange: setColumnPinning, - onGlobalFilterChange: handleGlobalFilterChange, - state: { - columnSizing, - columnPinning, - columnVisibility, - globalFilter, - showColumnFilters, - rowSelection, - editingCell, - }, - initialState: { - expanded: true, - }, - meta: tableMeta, - muiTableHeadCellProps: { - sx: { boxSizing: 'border-box' }, - }, - muiTableBodyCellProps: getTableBodyCellProps, - muiTableHeadProps: { - sx: { - display: 'table-header-group', - height: '1px', - minHeight: '1px', - maxHeight: '1px', - visibility: 'hidden', - '& svg': { - height: '1px', - minHeight: '1px', - maxHeight: '1px', - visibility: 'hidden', - } - }, - }, - muiTablePaperProps: getTablePaperStyles(), - muiTableContainerProps: { - ref: containerRef, - sx: { - position: 'relative', - contain: 'layout', - minHeight: '100%', - '& .MuiTable-root': { position: 'relative' }, - }, - }, - muiTableHeadCellFilterTextFieldProps: { - placeholder: 'Поиск...', - size: 'small', + const allCols = [...table.getLeftVisibleLeafColumns(), ...table.getCenterVisibleLeafColumns()] + return allCols[index]?.getSize() ?? 150; }, }), - [ - columns, - data, - setColumnSizing, - setColumnPinning, + enableRowSelection: true, + onRowSelectionChange: setRowSelection, + onColumnSizingChange: setColumnSizing, + onColumnPinningChange: setColumnPinning, + onGlobalFilterChange: handleGlobalFilterChange, + state: { columnSizing, columnPinning, columnVisibility, globalFilter, showColumnFilters, - containerRef, - tableMeta, rowSelection, - editingCell - ], - ); + editingCell, + }, + initialState: { + expanded: true, + }, + meta: tableMeta, + muiTableHeadCellProps: { + sx: { boxSizing: 'border-box' }, + }, + muiTableBodyCellProps: getTableBodyCellProps, + muiTableHeadProps: { + sx: { + display: 'table-header-group', + height: '1px', + minHeight: '1px', + maxHeight: '1px', + visibility: 'hidden', + '& svg': { + height: '1px', + minHeight: '1px', + maxHeight: '1px', + visibility: 'hidden', + } + }, + }, + muiTablePaperProps: getTablePaperStyles(), + muiTableContainerProps: { + ref: containerRef, + sx: { + position: 'relative', + contain: 'layout', + minHeight: '100%', + '& .MuiTable-root': { position: 'relative' }, + }, + }, + muiTableHeadCellFilterTextFieldProps: { + placeholder: 'Поиск...', + size: 'small', + }, + }); + + // Конфигурация таблицы + const tableConfig = useMemo(() => createTableConfig({ + columns, + data, + columnSizing, + columnPinning, + columnVisibility, + globalFilter, + showColumnFilters, + rowSelection, + containerRef, + tableMeta, + setColumnSizing, + setColumnPinning, + editingCell, + contextStartEditing, + }), [ + columns, + data, + columnSizing, + columnPinning, + columnVisibility, + globalFilter, + showColumnFilters, + rowSelection, + containerRef, + tableMeta, + setColumnSizing, + setColumnPinning, + editingCell, + ]); const table = useMaterialReactTable(tableConfig); @@ -342,6 +379,17 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => { setRowSelection({}); }, [rowSelection, table]) + useEffect(() => { + return () => { + setData([]); + setRowSelection({}); + setEditingCell(null); + if (rowVirtualizerRef.current) { + rowVirtualizerRef.current = null; + } + }; + }, []); + return ( <> Date: Mon, 20 Jul 2026 12:06:26 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=B4=D0=B0=D1=82=D0=B0=20=D0=B2=20=D1=84?= =?UTF-8?q?=D0=B8=D0=BB=D1=8C=D1=82=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20audit?= =?UTF-8?q?=20logs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx b/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx index ea369e3..cc4a9ec 100644 --- a/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx +++ b/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx @@ -71,8 +71,8 @@ const AuditLogsPage = () => { user_id: selectedUser?.id, org_unit_id: selectedSsp?.id, event: selectedEventType?.id, - date_from: dateFrom ? dateFrom.toISOString() : undefined, - date_to: dateTo ? dateTo.toISOString() : undefined, + date_from: dateFrom ? dateFrom.toISOString().slice(0, 10) : undefined, + date_to: dateTo ? dateTo.toISOString().slice(0, 10) : undefined, task_id: taskId ? taskId : undefined, form_id: formId ? formId : undefined, };