From 1b17638565cda5f0cef44a725de507866818507c Mon Sep 17 00:00:00 2001 From: tlartem Date: Tue, 22 Jul 2025 05:55:43 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=8B=D0=B4=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=8F=D1=87=D0=B5=D0=B5=D0=BA=20=D0=BF=D0=BE=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B8=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DualSpreadsheet/DualSpreadsheet.tsx | 88 ++++++++++++++++++- .../DualSpreadsheet/components/Cell.tsx | 79 ++++++++++++++++- .../components/CellRenderer.tsx | 4 + .../components/Spreadsheet.tsx | 13 +++ src/component/DualSpreadsheet/types.ts | 24 ++++- src/component/DualSpreadsheet/utils.ts | 16 ++++ 6 files changed, 215 insertions(+), 9 deletions(-) diff --git a/src/component/DualSpreadsheet/DualSpreadsheet.tsx b/src/component/DualSpreadsheet/DualSpreadsheet.tsx index cde3440..0e9e192 100644 --- a/src/component/DualSpreadsheet/DualSpreadsheet.tsx +++ b/src/component/DualSpreadsheet/DualSpreadsheet.tsx @@ -19,6 +19,8 @@ import { } from './types' import { convertReferencesToHighlights, + createCellAddress, + createQualifiedCellReference, extractCellReferences, getColumnLabel, } from './utils' @@ -67,6 +69,8 @@ const DualSpreadsheet: FC = ({ } | null>(null) const [isEditing, setIsEditing] = useState(false) const [editingValue, setEditingValue] = useState('') // Локальное значение во время редактирования + // Источник ввода: 'cell' (редактирование внутри ячейки) или 'formula' + const [editingSource, setEditingSource] = useState<'cell' | 'formula'>('cell') const [isInitialized, setIsInitialized] = useState(false) const [baseFileData, setBaseFileData] = useState< Record> @@ -427,6 +431,7 @@ const DualSpreadsheet: FC = ({ } setIsEditing(false) setEditingValue('') + setEditingSource('cell') containerRefs.current[activeSheet]?.focus({ preventScroll: true }) }, [activeSheet, selectedCell, editingValue, multiSheetEngine, updateRevision] @@ -497,8 +502,14 @@ const DualSpreadsheet: FC = ({ ArrowDown: () => moveSelection(1, 0), ArrowLeft: () => moveSelection(0, -1), ArrowRight: () => moveSelection(0, 1), - Enter: () => startEditing(), - F2: () => startEditing(), + Enter: () => { + setEditingSource('cell') + startEditing() + }, + F2: () => { + setEditingSource('cell') + startEditing() + }, Delete: handleClearCell, Backspace: handleClearCell, } @@ -508,6 +519,7 @@ const DualSpreadsheet: FC = ({ keyHandlers[e.key]() } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) { e.preventDefault() + setEditingSource('cell') setEditingValue(e.key) setIsEditing(true) } @@ -517,6 +529,13 @@ const DualSpreadsheet: FC = ({ const handleCellClick = useCallback( (row: number, col: number) => { + console.log('🖱️ Обычный клик по ячейке:', { + row, + col, + isEditing, + activeSheet, + }) + if (isEditing) { stopEditing(true) } @@ -526,9 +545,71 @@ const DualSpreadsheet: FC = ({ [isEditing, stopEditing, activeSheet] ) + // Новый обработчик для кликов в режиме редактирования - вставляет ссылку + const handleCellReferenceClick = useCallback( + (targetSheetType: SheetType, row: number, col: number) => { + console.log('🔗 Клик для вставки ссылки:', { + targetSheetType, + row, + col, + isEditing, + selectedCell, + editingValue, + }) + + // Проверяем, что мы в режиме редактирования + if (!isEditing || !selectedCell) { + console.log( + '⚠️ Игнорируем клик ссылки: не в режиме редактирования или нет выбранной ячейки' + ) + return + } + + // Создаем ссылку на ячейку + let cellReference: string + + // Если это другой лист, делаем квалифицированную ссылку + if (targetSheetType !== activeSheet) { + cellReference = createQualifiedCellReference(targetSheetType, row, col) + console.log('📋 Создана межлистовая ссылка:', cellReference) + } else { + // Если это тот же лист, делаем локальную ссылку + cellReference = createCellAddress(row, col) + console.log('📋 Создана локальная ссылка:', cellReference) + } + + // Добавляем ссылку к текущему значению редактирования + const newValue = editingValue + cellReference + console.log('✏️ Новое значение формулы:', { + oldValue: editingValue, + newValue, + }) + + setEditingValue(newValue) + + if (editingSource === 'formula') { + if (formulaBarRef.current) { + formulaBarRef.current.value = newValue + formulaBarRef.current.focus() + const length = newValue.length + formulaBarRef.current.setSelectionRange(length, length) + } + } else { + if (activeCellInputRef.current) { + activeCellInputRef.current.value = newValue + activeCellInputRef.current.focus({ preventScroll: true }) + const length = newValue.length + activeCellInputRef.current.setSelectionRange(length, length) + } + } + }, + [isEditing, selectedCell, editingValue, activeSheet, editingSource] + ) + const handleCellDoubleClick = useCallback( (row: number, col: number) => { setSelectedCell({ row, col }) + setEditingSource('cell') startEditing() }, [startEditing] @@ -563,6 +644,7 @@ const DualSpreadsheet: FC = ({ const handleFormulaBarFocus = useCallback(() => { if (selectedCell && !isEditing) { + setEditingSource('formula') startEditing() } }, [selectedCell, isEditing, startEditing]) @@ -864,6 +946,8 @@ const DualSpreadsheet: FC = ({ handleCellClick={handleCellClick} handleCellDoubleClick={handleCellDoubleClick} handleCellChange={handleCellChange} + handleCellReferenceClick={handleCellReferenceClick} + isInEditMode={isEditing} stopEditing={stopEditing} setActiveSheet={setActiveSheet} activeCellInputRef={activeCellInputRef} diff --git a/src/component/DualSpreadsheet/components/Cell.tsx b/src/component/DualSpreadsheet/components/Cell.tsx index 853f878..b69c3a3 100644 --- a/src/component/DualSpreadsheet/components/Cell.tsx +++ b/src/component/DualSpreadsheet/components/Cell.tsx @@ -18,6 +18,8 @@ export const Cell = memo( onCellClick, onCellDoubleClick, onCellValueChange, + onCellReferenceClick, + isInEditMode, stopEditing, setActiveSheet, activeCellRef, @@ -105,20 +107,89 @@ export const Cell = memo( // Используем обычное значение displayValue для всех ячеек, включая объединенные const cellDisplayValue = displayValue - const handleClick = useCallback(() => { - setActiveSheet(sheetType) - onCellClick(rowIndex, colIndex) - }, [setActiveSheet, sheetType, onCellClick, rowIndex, colIndex]) + const handleClick = useCallback( + (e: React.MouseEvent) => { + console.log('🖱️ Cell клик:', { + rowIndex, + colIndex, + sheetType, + isInEditMode, + isSelected, + hasReferenceHandler: !!onCellReferenceClick, + }) + + // Если мы в режиме редактирования, вставка была обработана на mousedown. + // Останавливаем всплытие, чтобы родительский Spreadsheet не сменил активный лист. + if (isInEditMode) { + e.preventDefault() + e.stopPropagation() + return + } + + // Обычная логика клика (выделение ячейки) + console.log('📍 Обычный клик - выбираем ячейку:', { + rowIndex, + colIndex, + sheetType, + }) + + // Подсказка для пользователя + if (!isInEditMode) { + console.log( + '💡 Чтобы вставить ссылку на ячейку: 1) Выберите ячейку 2) Нажмите F2 или Enter для редактирования 3) Кликните на нужную ячейку' + ) + } + + setActiveSheet(sheetType) + onCellClick(rowIndex, colIndex) + }, + [ + setActiveSheet, + sheetType, + onCellClick, + onCellReferenceClick, + rowIndex, + colIndex, + isInEditMode, + isSelected, + ] + ) const handleDoubleClick = useCallback( () => onCellDoubleClick(rowIndex, colIndex), [onCellDoubleClick, rowIndex, colIndex] ) + const handleMouseDown = useCallback( + (e: React.MouseEvent) => { + // Используем mousedown, чтобы сработать раньше blur FormulaBar + if (isInEditMode && onCellReferenceClick && !isSelected) { + e.preventDefault() + e.stopPropagation() + console.log('🖱️ mousedown – вставка ссылки до blur:', { + rowIndex, + colIndex, + sheetType, + }) + onCellReferenceClick(sheetType, rowIndex, colIndex) + return + } + }, + [ + isInEditMode, + onCellReferenceClick, + isSelected, + sheetType, + rowIndex, + colIndex, + ] + ) + return (
diff --git a/src/component/DualSpreadsheet/components/CellRenderer.tsx b/src/component/DualSpreadsheet/components/CellRenderer.tsx index b9cbf23..28dc32d 100644 --- a/src/component/DualSpreadsheet/components/CellRenderer.tsx +++ b/src/component/DualSpreadsheet/components/CellRenderer.tsx @@ -22,6 +22,8 @@ export const CellRenderer = ({ handleCellClick, handleCellDoubleClick, handleCellChange, + handleCellReferenceClick, + isInEditMode, stopEditing, setActiveSheet, activeCellInputRef, @@ -99,6 +101,8 @@ export const CellRenderer = ({ onCellClick={handleCellClick} onCellDoubleClick={handleCellDoubleClick} onCellValueChange={handleCellChange} + onCellReferenceClick={handleCellReferenceClick} + isInEditMode={isEditing} stopEditing={stopEditing} setActiveSheet={setActiveSheet} activeCellRef={activeCellInputRef} diff --git a/src/component/DualSpreadsheet/components/Spreadsheet.tsx b/src/component/DualSpreadsheet/components/Spreadsheet.tsx index bbc9157..1e2ed60 100644 --- a/src/component/DualSpreadsheet/components/Spreadsheet.tsx +++ b/src/component/DualSpreadsheet/components/Spreadsheet.tsx @@ -18,6 +18,8 @@ export const Spreadsheet = ({ handleCellClick, handleCellDoubleClick, handleCellChange, + handleCellReferenceClick, + isInEditMode, stopEditing, setActiveSheet, activeCellInputRef, @@ -46,11 +48,22 @@ export const Spreadsheet = ({ handleCellClick, handleCellDoubleClick, handleCellChange, + handleCellReferenceClick, + isInEditMode, stopEditing, setActiveSheet, activeCellInputRef, } + // Отладочное логирование для проверки состояния + console.log(`📊 Spreadsheet ${sheetType} состояние:`, { + isEditing, + isInEditMode, + selectedCell, + activeSheet, + isActiveSheet: activeSheet === sheetType, + }) + const parentRef = useRef(null) const [gridSize, setGridSize] = useState({ width: 0, height: 0 }) diff --git a/src/component/DualSpreadsheet/types.ts b/src/component/DualSpreadsheet/types.ts index 979f811..cb85b46 100644 --- a/src/component/DualSpreadsheet/types.ts +++ b/src/component/DualSpreadsheet/types.ts @@ -56,9 +56,15 @@ export interface CellProps { onCellClick: (row: number, col: number) => void onCellDoubleClick: (row: number, col: number) => void onCellValueChange: (newValue: string) => void // Изменение значения во время редактирования + onCellReferenceClick?: ( + sheetType: SheetType, + row: number, + col: number + ) => void // Клик для вставки ссылки + isInEditMode: boolean // Глобальный режим редактирования stopEditing: (save: boolean) => void setActiveSheet: (type: SheetType) => void - activeCellRef: React.RefObject + activeCellRef: React.RefObject style: CSSProperties // Добавляем style для react-window mergedCellInfo?: { // Информация об объединенных ячейках @@ -104,9 +110,15 @@ export interface CellRendererData { handleCellClick: (row: number, col: number) => void handleCellDoubleClick: (row: number, col: number) => void handleCellChange: (newValue: string) => void + handleCellReferenceClick?: ( + sheetType: SheetType, + row: number, + col: number + ) => void // Клик для вставки ссылки + isInEditMode: boolean // Глобальный режим редактирования stopEditing: (save: boolean) => void setActiveSheet: (type: SheetType) => void - activeCellInputRef: React.RefObject + activeCellInputRef: React.RefObject } export interface CellRendererProps { @@ -129,9 +141,15 @@ export interface SpreadsheetProps { handleCellClick: (row: number, col: number) => void handleCellDoubleClick: (row: number, col: number) => void handleCellChange: (newValue: string) => void + handleCellReferenceClick?: ( + sheetType: SheetType, + row: number, + col: number + ) => void // Клик для вставки ссылки + isInEditMode: boolean // Глобальный режим редактирования stopEditing: (save: boolean) => void setActiveSheet: (type: SheetType) => void - activeCellInputRef: React.RefObject + activeCellInputRef: React.RefObject containerRefs: React.MutableRefObject< Record > diff --git a/src/component/DualSpreadsheet/utils.ts b/src/component/DualSpreadsheet/utils.ts index 25da080..7ae8f6f 100644 --- a/src/component/DualSpreadsheet/utils.ts +++ b/src/component/DualSpreadsheet/utils.ts @@ -11,6 +11,22 @@ export function getColumnLabel(index: number): string { return label } +// Создает адрес ячейки из координат (например, A1, B2) +export function createCellAddress(row: number, col: number): string { + return getColumnLabel(col) + (row + 1) +} + +// Создает квалифицированную ссылку на ячейку с указанием листа +export function createQualifiedCellReference( + sheetType: 'report' | 'calculations', + row: number, + col: number +): string { + const sheetName = sheetType === 'report' ? 'L' : 'R' + const cellAddress = createCellAddress(row, col) + return `${sheetName}!${cellAddress}` +} + export function findMergedCellInfo( row: number, col: number,