This commit is contained in:
PotapovaA 2026-08-19 18:26:29 +03:00
parent 336e4123e5
commit d347023211
4 changed files with 86 additions and 22 deletions

View File

@ -163,6 +163,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
handleUnpinColumn, handleUnpinColumn,
handleSetColumnWidth, handleSetColumnWidth,
handleToggleColumnVisibility, handleToggleColumnVisibility,
handleSetColumnsVisibility,
} = useColumnSettings(`${formId}_${formType}_${sheetName}_${direction}`); } = useColumnSettings(`${formId}_${formType}_${sheetName}_${direction}`);
const { headerPortalRef, containerRef } = useHeaderPortal(); const { headerPortalRef, containerRef } = useHeaderPortal();
@ -174,6 +175,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
useEffect(() => { useEffect(() => {
rowVirtualizerRef.current?.measure?.(); rowVirtualizerRef.current?.measure?.();
columnVirtualizerRef.current?.measure?.();
}, [sizeMult]); }, [sizeMult]);
useEffect(() => { useEffect(() => {
@ -300,10 +302,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
}, [columns, columnPinning, columnSizing, columnVisibility]); }, [columns, columnPinning, columnSizing, columnVisibility]);
const selectedColumnIdRef = useRef(selectedColumnId); const selectedColumnIdRef = useRef(selectedColumnId);
useEffect(() => {
selectedColumnIdRef.current = selectedColumnId; selectedColumnIdRef.current = selectedColumnId;
}, [selectedColumnId]);
const tableMeta = useMemo(() => ({ const tableMeta = useMemo(() => ({
updateCell: handleUpdateCell, updateCell: handleUpdateCell,
@ -612,11 +611,11 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
<SettingsPanel <SettingsPanel
selectedColumnId={selectedColumnId} selectedColumnId={selectedColumnId}
columnPinning={columnPinning} columnPinning={columnPinning}
table={table}
columns={columns} columns={columns}
onPinColumn={handlePinColumn} onPinColumn={handlePinColumn}
onUnpinColumn={handleUnpinColumn} onUnpinColumn={handleUnpinColumn}
onToggleColumnVisibility={handleToggleColumnVisibility} onToggleColumnVisibility={handleToggleColumnVisibility}
onSetColumnsVisibility={handleSetColumnsVisibility}
columnVisibility={columnVisibility} columnVisibility={columnVisibility}
columnsCurStage={columnsCurStage} columnsCurStage={columnsCurStage}
onChangeSizeMult={setSizeMult} onChangeSizeMult={setSizeMult}
@ -628,7 +627,6 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
onAddProgram={addProgram} onAddProgram={addProgram}
onAddProject={addProject} onAddProject={addProject}
onDeleteRow={handleDeleteRow} onDeleteRow={handleDeleteRow}
isLoadingData={isLoadingData}
formId={formId} formId={formId}
sheetName={sheetName} sheetName={sheetName}
direction={direction} direction={direction}

View File

@ -37,11 +37,11 @@ const exportButtonSx = { height: '2.5rem', minHeight: '2.5rem' };
const SettingPanel = ({ const SettingPanel = ({
selectedColumnId, selectedColumnId,
columnPinning, columnPinning,
table,
columns, columns,
onPinColumn, onPinColumn,
onUnpinColumn, onUnpinColumn,
onToggleColumnVisibility, onToggleColumnVisibility,
onSetColumnsVisibility,
columnVisibility, columnVisibility,
columnsCurStage, columnsCurStage,
onChangeSizeMult, onChangeSizeMult,
@ -53,7 +53,6 @@ const SettingPanel = ({
onAddProgram, onAddProgram,
onAddProject, onAddProject,
onDeleteRow, onDeleteRow,
isLoadingData,
formId, formId,
sheetName, sheetName,
direction, direction,
@ -119,10 +118,12 @@ const SettingPanel = ({
console.warn('Нет столбцов для текущего этапа'); console.warn('Нет столбцов для текущего этапа');
return; return;
} }
const visibilityByColumnId = {};
for (const column of leafColumns) { for (const column of leafColumns) {
onToggleColumnVisibility(column, showOnlyCurrentStageColumns || stageColumnIds.has(column.id)); visibilityByColumnId[column.id] = showOnlyCurrentStageColumns || stageColumnIds.has(column.id);
} }
}, [columnsCurStage, leafColumns, onToggleColumnVisibility, showOnlyCurrentStageColumns, stageColumnIds]); onSetColumnsVisibility(visibilityByColumnId);
}, [columnsCurStage, leafColumns, onSetColumnsVisibility, showOnlyCurrentStageColumns, stageColumnIds]);
return ( return (
<> <>

View File

@ -3,21 +3,79 @@ import {
useCallback, useCallback,
useContext, useContext,
useEffect, useEffect,
useMemo,
useRef, useRef,
useState, useState,
useSyncExternalStore,
} from "react"; } from "react";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import { useWebSocket } from "../hooks/useWebSocket"; import { useWebSocket } from "../hooks/useWebSocket";
import { getRowId } from "../utils/rowUtils"; import { getRowId } from "../utils/rowUtils";
const RealtimeContext = createContext(null); const RealtimeActionsContext = createContext(null);
const RealtimeConnectionContext = createContext(null);
const RealtimeVspOptionsContext = createContext(null);
const LockedCellsStoreContext = createContext(null);
const useRequiredContext = (context, hookName) => {
const value = useContext(context);
if (value === null) {
throw new Error(`${hookName} must be used within RealtimeProvider`);
}
return value;
};
const createLockedCellsStore = () => {
let cells = new Set();
const listeners = new Set();
const subscribe = (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
};
const setCells = (nextValue) => {
const currentCells = [...cells];
const resolvedValue = typeof nextValue === "function" ? nextValue(currentCells) : nextValue;
const nextCells = new Set(resolvedValue || []);
const hasChanges =
nextCells.size !== cells.size || [...nextCells].some((cellKey) => !cells.has(cellKey));
if (!hasChanges) return;
cells = nextCells;
listeners.forEach((listener) => listener());
};
return {
subscribe,
setCells,
hasCell: (cellKey) => cells.has(cellKey),
getCells: () => [...cells],
};
};
export const useRealtimeActions = () =>
useRequiredContext(RealtimeActionsContext, "useRealtimeActions");
export const useRealtimeConnection = () =>
useRequiredContext(RealtimeConnectionContext, "useRealtimeConnection");
export const useVspOptions = () =>
useRequiredContext(RealtimeVspOptionsContext, "useVspOptions");
export const useCellLock = (cellKey) => {
const store = useRequiredContext(LockedCellsStoreContext, "useCellLock");
const getSnapshot = useCallback(() => store.hasCell(cellKey), [cellKey, store]);
return useSyncExternalStore(store.subscribe, getSnapshot, () => false);
};
export const useRealtime = () => { export const useRealtime = () => {
const context = useContext(RealtimeContext); const actions = useRealtimeActions();
if (!context) { const connection = useRealtimeConnection();
throw new Error("useRealtime must be used within RealtimeProvider"); const vspOptions = useVspOptions();
}
return context; return { ...actions, ...connection, vspOptions };
}; };
export const RealtimeProvider = ({ export const RealtimeProvider = ({
@ -41,9 +99,11 @@ export const RealtimeProvider = ({
: `/api/v1/ws/projects/${formId}/report/${year}/${sheetName}` : `/api/v1/ws/projects/${formId}/report/${year}/${sheetName}`
}`; }`;
//для ячеек которые редактируются другими пользователями
const [lockedCells, setLockedCells] = useState([]);
const [vspOptions, setVspOptions] = useState([]); const [vspOptions, setVspOptions] = useState([]);
const lockedCellsStoreRef = useRef(null);
if (lockedCellsStoreRef.current === null) {
lockedCellsStoreRef.current = createLockedCellsStore();
}
const handleMessage = useCallback((data) => { const handleMessage = useCallback((data) => {
// Обработка ошибок // Обработка ошибок

View File

@ -66,6 +66,10 @@ export const useColumnSettings = (tableKey) => {
setColumnVisibility((prev) => ({ ...prev, ...leafCols })); setColumnVisibility((prev) => ({ ...prev, ...leafCols }));
}, []); }, []);
const handleSetColumnsVisibility = useCallback((visibilityByColumnId) => {
setColumnVisibility((prev) => ({ ...prev, ...visibilityByColumnId }));
}, []);
// Опционально: функция для сброса всех настроек // Опционально: функция для сброса всех настроек
const resetAllSettings = useCallback(() => { const resetAllSettings = useCallback(() => {
setColumnSizing({}); setColumnSizing({});
@ -84,6 +88,7 @@ export const useColumnSettings = (tableKey) => {
handleUnpinColumn, handleUnpinColumn,
handleSetColumnWidth, handleSetColumnWidth,
handleToggleColumnVisibility, handleToggleColumnVisibility,
handleSetColumnsVisibility,
resetAllSettings, // добавляем функцию сброса resetAllSettings, // добавляем функцию сброса
tableKey, // опционально возвращаем tableKey tableKey, // опционально возвращаем tableKey
}; };