diff --git a/web/src/components/RealtimeTable/TableHead/TableHead.jsx b/web/src/components/RealtimeTable/TableHead/TableHead.jsx index efd1296..43fa587 100644 --- a/web/src/components/RealtimeTable/TableHead/TableHead.jsx +++ b/web/src/components/RealtimeTable/TableHead/TableHead.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import ColumnResizer from './ColumnResizer'; import { columnPinningDefault } from '../constants/columnConfig'; @@ -149,6 +149,24 @@ const ColumnNumberCell = ({ column, table, selectedColumnId, onColumnSelect }) = ); }; +const getColorBrightness = (hexColor) => { + if (!hexColor) return 255; + const color = hexColor.replace('#', ''); + let r, g, b; + if (color.length === 3) { + r = parseInt(color[0] + color[0], 16); + g = parseInt(color[1] + color[1], 16); + b = parseInt(color[2] + color[2], 16); + } else if (color.length === 6) { + r = parseInt(color.substring(0, 2), 16); + g = parseInt(color.substring(2, 4), 16); + b = parseInt(color.substring(4, 6), 16); + } else { + return 255; + } + return (0.299 * r + 0.587 * g + 0.114 * b); +}; + const HeaderCell = ({ header, table, onClick, onChangeWidth }) => { const column = header.column; const pinningColumn = getPinnedColumnIds(table); @@ -160,12 +178,16 @@ const HeaderCell = ({ header, table, onClick, onChangeWidth }) => { const splitGroup = isGroup && isPinned && pinnedBandWidth > 0 && pinnedBandWidth < headerSize; const customBgColor = column.columnDef?.muiTableHeadCellProps?.sx?.backgroundColor; - const color = column.columnDef?.muiTableHeadCellProps?.sx?.color || '#000000'; const backgroundColor = customBgColor ? customBgColor : 'rgba(243, 244, 246, 1)'; + const color = useMemo(() => { + const brightness = getColorBrightness(backgroundColor); + return brightness < 128 ? '#ffffff' : '#000000'; + }, [backgroundColor]); + const handleChangeWidth = (deltaWidth) => { const size = header.getSize(); onChangeWidth(header, size + deltaWidth); @@ -313,8 +335,8 @@ const FilterCell = ({ column, table }) => { onChange={(e) => handleFilterChange(e.target.value)} style={{ width: '100%', - padding: '0.25rem 0.375rem', - fontSize: '0.6875rem', + padding: '0.25rem 0.375rem', + fontSize: '0.6875rem', border: '1px solid #ddd', borderRadius: '0.25rem', backgroundColor: 'white', @@ -340,8 +362,8 @@ const FilterCell = ({ column, table }) => { onChange={(e) => column.setFilterValue([e.target.value, max])} style={{ width: '50%', - padding: '0.25rem', - fontSize: '0.6875rem' + padding: '0.25rem', + fontSize: '0.6875rem' }} /> { onChange={(e) => column.setFilterValue([min, e.target.value])} style={{ width: '50%', - padding: '0.25rem', - fontSize: '0.6875rem' + padding: '0.25rem', + fontSize: '0.6875rem' }} /> @@ -371,7 +393,7 @@ const FilterCell = ({ column, table }) => { padding: '0.25rem 0.375rem', fontSize: '0.6875rem', border: '1px solid #ddd', - borderRadius: '0.25rem', + borderRadius: '0.25rem', boxSizing: 'border-box', }} /> diff --git a/web/src/components/RealtimeTable/constants/FORM_4/CAP.js b/web/src/components/RealtimeTable/constants/FORM_4/CAP.js index ca51b85..2b3b875 100644 --- a/web/src/components/RealtimeTable/constants/FORM_4/CAP.js +++ b/web/src/components/RealtimeTable/constants/FORM_4/CAP.js @@ -768,7 +768,7 @@ export const config = { }, columns: [ { - header: ".", + header: "", accessorKey: "field", columns: [ { @@ -1469,7 +1469,7 @@ export const config = { }, }, { - header: "..", + header: "", accessorKey: "field_4", columns: [ { diff --git a/web/src/components/RealtimeTable/constants/FORM_4/OPER.js b/web/src/components/RealtimeTable/constants/FORM_4/OPER.js index a21fc51..d8d135f 100644 --- a/web/src/components/RealtimeTable/constants/FORM_4/OPER.js +++ b/web/src/components/RealtimeTable/constants/FORM_4/OPER.js @@ -1020,7 +1020,7 @@ export const config = { }, }, { - header: "Платежив 2027 году", + header: "Платежи в 2027 году", accessorKey: "data.contract_summary.future_payments_y1", columnLetter: "Q", size: 190, @@ -1033,7 +1033,7 @@ export const config = { }, }, { - header: "Платежив 2028 году", + header: "Платежи в 2028 году", accessorKey: "data.contract_summary.future_payments_y2", columnLetter: "R", size: 190, @@ -2374,7 +2374,7 @@ export const config = { header: "Сумма (без НДС)", accessorKey: "data.q2.target_change", columnLetter: "DE", - size: 150, + size: 300, filterFn: "contains", muiTableHeadCellProps: { sx: { @@ -2399,7 +2399,7 @@ export const config = { header: "Сумма (без НДС)", accessorKey: "data.q2.base_correction", columnLetter: "DF", - size: 150, + size: 300, filterFn: "contains", }, ], diff --git a/web/src/components/RealtimeTable/constants/FORM_4/SMETA.js b/web/src/components/RealtimeTable/constants/FORM_4/SMETA.js index c59cd72..c3a148d 100644 --- a/web/src/components/RealtimeTable/constants/FORM_4/SMETA.js +++ b/web/src/components/RealtimeTable/constants/FORM_4/SMETA.js @@ -308,7 +308,7 @@ export const config = { }, }, { - header: "ИТОГОПоддержка", + header: "ИТОГО Поддержка", accessorKey: "data.plan.support.year", columnLetter: "H", @@ -386,7 +386,7 @@ export const config = { }, }, { - header: "ИТОГОРазвитие", + header: "ИТОГО Развитие", accessorKey: "data.plan.development.year", columnLetter: "M", size: 150, @@ -477,7 +477,7 @@ export const config = { }, }, { - header: "ИТОГОПоддержка", + header: "ИТОГО Поддержка", accessorKey: "data.approved.support.year", columnLetter: "T", size: 150, @@ -554,7 +554,7 @@ export const config = { }, }, { - header: "ИТОГОРазвитие", + header: "ИТОГО Развитие", accessorKey: "data.approved.development.year", columnLetter: "Y", size: 150, @@ -643,7 +643,7 @@ export const config = { }, }, { - header: "ИТОГОПоддержка", + header: "ИТОГО Поддержка", accessorKey: "data.fact.support.year", columnLetter: "AF", size: 150, @@ -720,7 +720,7 @@ export const config = { }, }, { - header: "ИТОГОРазвитие", + header: "ИТОГО Развитие", accessorKey: "data.fact.development.year", columnLetter: "AK", size: 150, diff --git a/web/src/components/RealtimeTable/constants/FORM_4/STRUCTURE.js b/web/src/components/RealtimeTable/constants/FORM_4/STRUCTURE.js index 4669677..29fa2c5 100644 --- a/web/src/components/RealtimeTable/constants/FORM_4/STRUCTURE.js +++ b/web/src/components/RealtimeTable/constants/FORM_4/STRUCTURE.js @@ -764,7 +764,7 @@ export const config = { }, columns: [ { - header: ".", + header: "", accessorKey: "field", columns: [ { @@ -1487,7 +1487,7 @@ export const config = { }, }, { - header: "..", + header: "", accessorKey: "field_6", columns: [ { @@ -3953,7 +3953,7 @@ export const config = { }, }, { - header: "...", + header: "", accessorKey: "field_40", columns: [ { diff --git a/web/src/components/RealtimeTable/hooks/useRealtimeData.js b/web/src/components/RealtimeTable/hooks/useRealtimeData.js index 31c2dc9..330c2c8 100644 --- a/web/src/components/RealtimeTable/hooks/useRealtimeData.js +++ b/web/src/components/RealtimeTable/hooks/useRealtimeData.js @@ -238,9 +238,13 @@ const useRealtimeData = (formId, sheetName, direction, formType, year) => { }); }); - const unsubscribeProgramAdds = subscribeToProgramAdds((data) => { - const newRow = data.result[1][0]; + const unsubscribeProgramAdds = subscribeToProgramAdds((msg) => { + let newRow = msg.result[1][0]; setData((prevData) => { + const hasRoot = prevData.length > 0 && prevData[0].row_type === "ROOT"; + if (hasRoot) { + newRow = msg.result[1][1]; + } const updateData = structuredClone(prevData); const [row_type, depth, sort_order, dataRow] = newRow; const newRowObject = { @@ -250,8 +254,11 @@ const useRealtimeData = (formId, sheetName, direction, formType, year) => { subRows: [], data: dataRow, }; - const newData = [...updateData, newRowObject]; - return newData; + if (hasRoot) { + updateData[0].subRows.push(newRowObject); + return updateData; + } + return [...updateData, newRowObject]; }); }); diff --git a/web/src/components/common/CollapsibleTree.jsx b/web/src/components/common/CollapsibleTree.jsx index c916265..0a35989 100644 --- a/web/src/components/common/CollapsibleTree.jsx +++ b/web/src/components/common/CollapsibleTree.jsx @@ -25,6 +25,7 @@ const CollapsibleTree = ({ onSelectNode, forStage = false }) => { + const [expandedItems, setExpandedItems] = useState([]); const [anchorEl, setAnchorEl] = useState(null); const [selectedNodes, setSelectedNodes] = useState([]); @@ -160,7 +161,7 @@ const CollapsibleTree = ({ const visibleSelectedCount = selectedNodes.filter((id) => visibleLeafKeys.includes(id), ).length; - const selectedCount = forStage ? visibleSelectedCount : visibleSelectedCount - 1; //1 колонка всегда скрыта + const selectedCount = visibleSelectedCount; const isAllSelected = () => { if (!visibleColumnTree.length) return false;