подстветка ячеек
This commit is contained in:
@@ -11,12 +11,17 @@ import {
|
||||
CachedCellData,
|
||||
COL_COUNT,
|
||||
DualSpreadsheetProps,
|
||||
HighlightedCell,
|
||||
ROW_COUNT,
|
||||
SHEET_NAMES,
|
||||
SHEET_TYPES,
|
||||
SheetType,
|
||||
} from './types'
|
||||
import { getColumnLabel } from './utils'
|
||||
import {
|
||||
convertReferencesToHighlights,
|
||||
extractCellReferences,
|
||||
getColumnLabel,
|
||||
} from './utils'
|
||||
|
||||
const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
|
||||
templateData = {},
|
||||
@@ -66,6 +71,9 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
|
||||
const [baseFileData, setBaseFileData] = useState<
|
||||
Record<string, Record<string, any>>
|
||||
>({}) // Базовые данные файла
|
||||
const [highlightedCells, setHighlightedCells] = useState<HighlightedCell[]>(
|
||||
[]
|
||||
) // Подсвеченные ячейки для формул
|
||||
|
||||
// Мемоизируем начальное состояние ширин колонок
|
||||
const initialColumnWidths = useMemo(
|
||||
@@ -120,7 +128,7 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
|
||||
const rowHeaderRefs =
|
||||
useRef<Record<SheetType, HTMLDivElement | null>>(initialRowHeaderRefs)
|
||||
|
||||
const activeCellInputRef = useRef<HTMLInputElement>(null)
|
||||
const activeCellInputRef = useRef<HTMLInputElement | null>(null)
|
||||
const formulaBarRef = useRef<HTMLInputElement | null>(null)
|
||||
const initialTemplateValues = useRef<Record<string, string>>({})
|
||||
|
||||
@@ -294,6 +302,38 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
|
||||
[revision, multiSheetEngine, initialTemplateValues, columnWidths]
|
||||
)
|
||||
|
||||
// Функция для обновления подсветки ячеек при вводе формулы
|
||||
const updateCellHighlights = useCallback(
|
||||
(formula: string) => {
|
||||
if (!formula.startsWith('=')) {
|
||||
setHighlightedCells([])
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// Извлекаем ссылки на ячейки из формулы
|
||||
const references = extractCellReferences(formula)
|
||||
|
||||
// Конвертируем ссылки в подсвеченные ячейки
|
||||
const highlights = convertReferencesToHighlights(
|
||||
references,
|
||||
activeSheet
|
||||
)
|
||||
|
||||
setHighlightedCells(highlights)
|
||||
|
||||
console.log('🎨 Подсветка ячеек для формулы:', formula, {
|
||||
references,
|
||||
highlights,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Ошибка при обновлении подсветки ячеек:', error)
|
||||
setHighlightedCells([])
|
||||
}
|
||||
},
|
||||
[activeSheet]
|
||||
)
|
||||
|
||||
const formulaBarValue = useMemo(() => {
|
||||
if (isEditing) {
|
||||
return editingValue
|
||||
@@ -332,6 +372,16 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
|
||||
}
|
||||
}, [editingValue, isEditing])
|
||||
|
||||
// Обновление подсветки ячеек при вводе формулы
|
||||
useEffect(() => {
|
||||
if (isEditing) {
|
||||
updateCellHighlights(editingValue)
|
||||
} else {
|
||||
// Очищаем подсветку когда не редактируем
|
||||
setHighlightedCells([])
|
||||
}
|
||||
}, [isEditing, editingValue, updateCellHighlights])
|
||||
|
||||
const startEditing = useCallback(() => {
|
||||
if (!selectedCell) return
|
||||
const sheetName = SHEET_NAMES[activeSheet]
|
||||
@@ -642,10 +692,7 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
|
||||
try {
|
||||
const latestFile = await getLatestFileForTemplate(templateId)
|
||||
if (latestFile) {
|
||||
console.log(
|
||||
'📁 Найден последний файл для шаблона:',
|
||||
latestFile.filename
|
||||
)
|
||||
console.log('📁 Найден последний файл для шаблона:', latestFile.name)
|
||||
const fileData = await getFileData(latestFile.id)
|
||||
|
||||
// TODO: Пока getFileData возвращает пустые данные, используем templateData
|
||||
@@ -813,6 +860,7 @@ const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
|
||||
activeSheet={activeSheet}
|
||||
isEditing={isEditing}
|
||||
editingValue={editingValue}
|
||||
highlightedCells={highlightedCells}
|
||||
handleCellClick={handleCellClick}
|
||||
handleCellDoubleClick={handleCellDoubleClick}
|
||||
handleCellChange={handleCellChange}
|
||||
|
||||
@@ -23,13 +23,22 @@ export const Cell = memo(
|
||||
activeCellRef,
|
||||
style, // Добавляем style для react-window
|
||||
mergedCellInfo,
|
||||
highlightColor, // Цвет подсветки для формул
|
||||
}: CellProps) => {
|
||||
// Если ячейка объединена, но не является основной, не рендерим её
|
||||
if (mergedCellInfo?.isMerged && !mergedCellInfo.isMainCell) {
|
||||
return null
|
||||
}
|
||||
|
||||
const className = `border border-border ${isModified && !mergedCellInfo?.isMerged ? 'bg-yellow-200' : ''}`
|
||||
// Определяем классы CSS для подсветки и обычного состояния
|
||||
let className = 'border border-border'
|
||||
|
||||
// Приоритет стилей: подсветка формул > изменения > обычное состояние
|
||||
if (highlightColor) {
|
||||
className += ` ${highlightColor}`
|
||||
} else if (isModified && !mergedCellInfo?.isMerged) {
|
||||
className += ' bg-yellow-200'
|
||||
}
|
||||
|
||||
// Отладка стилей для измененных ячеек
|
||||
if (isModified) {
|
||||
@@ -38,6 +47,7 @@ export const Cell = memo(
|
||||
isModified,
|
||||
isSelected,
|
||||
displayValue,
|
||||
highlightColor,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -68,16 +78,27 @@ export const Cell = memo(
|
||||
// Рассчитываем общую высоту для объединенной ячейки
|
||||
const totalHeight = ROW_HEIGHT * rowSpan
|
||||
|
||||
// Определяем цвет фона для объединенной ячейки
|
||||
let backgroundColor = 'white'
|
||||
if (highlightColor) {
|
||||
// Если есть подсветка формулы, используем её
|
||||
const bgMatch = highlightColor.match(/bg-(\w+)-(\d+)/)
|
||||
if (bgMatch) {
|
||||
backgroundColor = `var(--${bgMatch[1]}-${bgMatch[2]})`
|
||||
}
|
||||
} else if (isSelected) {
|
||||
backgroundColor = 'hsl(var(--accent))'
|
||||
} else if (isModified) {
|
||||
backgroundColor =
|
||||
'#fef08a' /* тот же жёлтый оттенок, что и bg-yellow-200 */
|
||||
}
|
||||
|
||||
cellStyle = {
|
||||
...cellStyle,
|
||||
width: totalWidth,
|
||||
height: totalHeight,
|
||||
zIndex: 10, // Поднимаем выше обычных ячеек
|
||||
backgroundColor: isSelected
|
||||
? 'hsl(var(--accent))'
|
||||
: isModified
|
||||
? '#fef08a' /* тот же жёлтый оттенок, что и bg-yellow-200 */
|
||||
: 'white',
|
||||
backgroundColor,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ export const CellRenderer = ({
|
||||
editingValue,
|
||||
cachedData,
|
||||
mergedCells,
|
||||
highlightedCells,
|
||||
handleCellClick,
|
||||
handleCellDoubleClick,
|
||||
handleCellChange,
|
||||
@@ -40,6 +41,16 @@ export const CellRenderer = ({
|
||||
? '' // Не показывать вычисленное значение во время редактирования
|
||||
: cellData?.displayValue || ''
|
||||
|
||||
// Проверяем, подсвечена ли эта ячейка
|
||||
const currentSheetName = sheetType === 'report' ? 'L' : 'R'
|
||||
const highlightedCell = highlightedCells.find(
|
||||
highlight =>
|
||||
highlight.sheet === currentSheetName &&
|
||||
highlight.row === rowIndex &&
|
||||
highlight.col === columnIndex
|
||||
)
|
||||
const highlightColor = highlightedCell?.color
|
||||
|
||||
// Отладка для измененных ячеек
|
||||
if (cellData?.isModified) {
|
||||
console.log(
|
||||
@@ -49,6 +60,7 @@ export const CellRenderer = ({
|
||||
isModified: cellData.isModified,
|
||||
displayValue,
|
||||
rawValue,
|
||||
highlightColor,
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -91,6 +103,7 @@ export const CellRenderer = ({
|
||||
setActiveSheet={setActiveSheet}
|
||||
activeCellRef={activeCellInputRef}
|
||||
mergedCellInfo={mergedCellProps}
|
||||
highlightColor={highlightColor}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export const Spreadsheet = ({
|
||||
activeSheet,
|
||||
isEditing,
|
||||
editingValue,
|
||||
highlightedCells,
|
||||
handleCellClick,
|
||||
handleCellDoubleClick,
|
||||
handleCellChange,
|
||||
@@ -41,6 +42,7 @@ export const Spreadsheet = ({
|
||||
editingValue,
|
||||
cachedData,
|
||||
mergedCells,
|
||||
highlightedCells,
|
||||
handleCellClick,
|
||||
handleCellDoubleClick,
|
||||
handleCellChange,
|
||||
@@ -78,7 +80,9 @@ export const Spreadsheet = ({
|
||||
onClick={() => setActiveSheet(sheetType)}
|
||||
>
|
||||
<div
|
||||
ref={el => (containerRefs.current[sheetType] = el)}
|
||||
ref={el => {
|
||||
containerRefs.current[sheetType] = el
|
||||
}}
|
||||
className="flex h-full flex-col overflow-hidden border bg-card shadow-sm"
|
||||
onKeyDown={handleKeyDown}
|
||||
tabIndex={0}
|
||||
@@ -102,7 +106,9 @@ export const Spreadsheet = ({
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
ref={el => (rowHeaderRefs.current[sheetType] = el)}
|
||||
ref={el => {
|
||||
rowHeaderRefs.current[sheetType] = el
|
||||
}}
|
||||
className="overflow-y-hidden"
|
||||
style={{ height: gridSize.height }}
|
||||
>
|
||||
@@ -126,7 +132,9 @@ export const Spreadsheet = ({
|
||||
<div className="flex-1 overflow-hidden">
|
||||
{/* Column Headers */}
|
||||
<div
|
||||
ref={el => (headerRefs.current[sheetType] = el)}
|
||||
ref={el => {
|
||||
headerRefs.current[sheetType] = el
|
||||
}}
|
||||
className="column-headers overflow-x-hidden"
|
||||
>
|
||||
<div className="flex">
|
||||
@@ -171,9 +179,9 @@ export const Spreadsheet = ({
|
||||
{/* Grid */}
|
||||
<div className="min-h-0 flex-1">
|
||||
<VariableSizeGrid
|
||||
ref={(el: VariableSizeGrid | null) =>
|
||||
(gridRefs.current[sheetType] = el)
|
||||
}
|
||||
ref={(el: VariableSizeGrid | null) => {
|
||||
gridRefs.current[sheetType] = el
|
||||
}}
|
||||
columnCount={COL_COUNT}
|
||||
rowCount={ROW_COUNT}
|
||||
columnWidth={(index: number) => widths[index]}
|
||||
|
||||
@@ -16,6 +16,14 @@ export type SheetType = keyof typeof SHEET_NAMES
|
||||
// Добавляем массив типов листов для итерации
|
||||
export const SHEET_TYPES: SheetType[] = ['report', 'calculations']
|
||||
|
||||
// Интерфейс для подсвеченной ячейки
|
||||
export interface HighlightedCell {
|
||||
sheet: string // нормализованное имя листа ('L' или 'R')
|
||||
row: number
|
||||
col: number
|
||||
color: string // класс CSS для цвета подсветки
|
||||
}
|
||||
|
||||
// Кэшированные данные ячеек для оптимизации
|
||||
export interface CachedCellData {
|
||||
displayValue: string
|
||||
@@ -59,6 +67,7 @@ export interface CellProps {
|
||||
rowSpan?: number
|
||||
colSpan?: number
|
||||
}
|
||||
highlightColor?: string // Цвет подсветки для формул
|
||||
}
|
||||
|
||||
export interface FormulaBarProps {
|
||||
@@ -91,6 +100,7 @@ export interface CellRendererData {
|
||||
editingValue: string
|
||||
cachedData: Record<string, CachedCellData>
|
||||
mergedCells?: MergedCell[]
|
||||
highlightedCells: HighlightedCell[] // Добавляем подсвеченные ячейки
|
||||
handleCellClick: (row: number, col: number) => void
|
||||
handleCellDoubleClick: (row: number, col: number) => void
|
||||
handleCellChange: (newValue: string) => void
|
||||
@@ -115,6 +125,7 @@ export interface SpreadsheetProps {
|
||||
activeSheet: SheetType
|
||||
isEditing: boolean
|
||||
editingValue: string
|
||||
highlightedCells: HighlightedCell[] // Добавляем подсвеченные ячейки
|
||||
handleCellClick: (row: number, col: number) => void
|
||||
handleCellDoubleClick: (row: number, col: number) => void
|
||||
handleCellChange: (newValue: string) => void
|
||||
|
||||
@@ -1,42 +1,289 @@
|
||||
import { cellAddressToCoordinates, getColumnLabel } from '@/lib/cell-utils'
|
||||
import { MergedCell } from '@/type/template'
|
||||
import { MergedCellInfo } from './types'
|
||||
|
||||
// --- Helper Functions ---
|
||||
export { getColumnLabel }
|
||||
export function getColumnLabel(index: number): string {
|
||||
let label = ''
|
||||
let col = index
|
||||
while (col >= 0) {
|
||||
label = String.fromCharCode(65 + (col % 26)) + label
|
||||
col = Math.floor(col / 26) - 1
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
// Вспомогательная функция для совместимости с существующим кодом
|
||||
export const cellAddressToCoords = cellAddressToCoordinates
|
||||
|
||||
// Функция для проверки, является ли ячейка частью объединенной группы
|
||||
export const findMergedCellInfo = (
|
||||
export function findMergedCellInfo(
|
||||
row: number,
|
||||
col: number,
|
||||
mergedCells: MergedCell[]
|
||||
): MergedCellInfo => {
|
||||
for (const merged of mergedCells) {
|
||||
const fromCoords = cellAddressToCoordinates(merged.from)
|
||||
const toCoords = cellAddressToCoordinates(merged.to)
|
||||
): MergedCellInfo {
|
||||
for (const mergedCell of mergedCells) {
|
||||
const { startRow, startCol, endRow, endCol } = mergedCell
|
||||
|
||||
// Проверяем, попадает ли текущая ячейка в диапазон объединения
|
||||
if (
|
||||
row >= fromCoords.row &&
|
||||
row <= toCoords.row &&
|
||||
col >= fromCoords.col &&
|
||||
col <= toCoords.col
|
||||
) {
|
||||
const isMainCell = row === fromCoords.row && col === fromCoords.col
|
||||
const rowSpan = toCoords.row - fromCoords.row + 1
|
||||
const colSpan = toCoords.col - fromCoords.col + 1
|
||||
// Проверяем, попадает ли ячейка в диапазон объединенных ячеек
|
||||
if (row >= startRow && row <= endRow && col >= startCol && col <= endCol) {
|
||||
// Это главная ячейка (левая верхняя)
|
||||
const isMainCell = row === startRow && col === startCol
|
||||
|
||||
return {
|
||||
isMerged: true,
|
||||
isMainCell,
|
||||
mergedCell: merged,
|
||||
spans: { rowSpan, colSpan },
|
||||
mergedCell,
|
||||
spans: {
|
||||
rowSpan: endRow - startRow + 1,
|
||||
colSpan: endCol - startCol + 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { isMerged: false, isMainCell: false }
|
||||
}
|
||||
|
||||
// Регулярные выражения для разных типов ссылок на ячейки
|
||||
const QUALIFIED_REF_RE = /\b[A-Za-z0-9_]+![A-Z]+[0-9]+\b/g // SheetName!A1
|
||||
const LOCAL_REF_RE = /\b[A-Z]+[0-9]+\b/g // A1, B2, etc.
|
||||
const RANGE_RE = /\b[A-Z]+[0-9]+:[A-Z]+[0-9]+\b/g // A1:B2, D5:D7, etc.
|
||||
const QUALIFIED_RANGE_RE = /\b[A-Za-z0-9_]+![A-Z]+[0-9]+:[A-Z]+[0-9]+\b/g // SheetName!A1:B2
|
||||
|
||||
// Интерфейс для ссылки на ячейку
|
||||
export interface CellReference {
|
||||
sheet: string | null // null для локальных ссылок
|
||||
address: string // например "A1" или "B2:C3"
|
||||
isRange: boolean
|
||||
startRow: number
|
||||
startCol: number
|
||||
endRow: number
|
||||
endCol: number
|
||||
}
|
||||
|
||||
// Парсит адрес ячейки типа "A1" в координаты
|
||||
export function parseCellAddress(
|
||||
address: string
|
||||
): { row: number; col: number } | null {
|
||||
const match = address.match(/^([A-Z]+)(\d+)$/)
|
||||
if (!match) return null
|
||||
|
||||
const column = match[1]
|
||||
const row = parseInt(match[2], 10)
|
||||
|
||||
// Конвертируем колонку в индекс
|
||||
let colIndex = 0
|
||||
for (let i = 0; i < column.length; i++) {
|
||||
colIndex = colIndex * 26 + (column.charCodeAt(i) - 65 + 1)
|
||||
}
|
||||
colIndex -= 1 // Конвертируем в 0-based индекс
|
||||
|
||||
return { row: row - 1, col: colIndex } // Конвертируем в 0-based индексы
|
||||
}
|
||||
|
||||
// Парсит диапазон ячеек типа "A1:B2"
|
||||
export function parseCellRange(range: string): {
|
||||
startRow: number
|
||||
startCol: number
|
||||
endRow: number
|
||||
endCol: number
|
||||
} | null {
|
||||
const parts = range.split(':')
|
||||
if (parts.length !== 2) return null
|
||||
|
||||
const start = parseCellAddress(parts[0])
|
||||
const end = parseCellAddress(parts[1])
|
||||
|
||||
if (!start || !end) return null
|
||||
|
||||
return {
|
||||
startRow: Math.min(start.row, end.row),
|
||||
startCol: Math.min(start.col, end.col),
|
||||
endRow: Math.max(start.row, end.row),
|
||||
endCol: Math.max(start.col, end.col),
|
||||
}
|
||||
}
|
||||
|
||||
// Извлекает все ссылки на ячейки из формулы
|
||||
export function extractCellReferences(formula: string): CellReference[] {
|
||||
if (!formula.startsWith('=')) return []
|
||||
|
||||
const expr = formula.substring(1) // Убираем знак =
|
||||
const references: CellReference[] = []
|
||||
|
||||
// Функция для проверки, не является ли ссылка частью имени функции
|
||||
const isFunction = (ref: string): boolean => {
|
||||
const commonFunctions = [
|
||||
'SUM',
|
||||
'AVERAGE',
|
||||
'COUNT',
|
||||
'MAX',
|
||||
'MIN',
|
||||
'IF',
|
||||
'AND',
|
||||
'OR',
|
||||
'NOT',
|
||||
'СУММ',
|
||||
'СРЕДНЕЕ',
|
||||
'СЧЁТ',
|
||||
'МАКС',
|
||||
'МИН',
|
||||
'ЕСЛИ',
|
||||
]
|
||||
return commonFunctions.includes(ref.toUpperCase())
|
||||
}
|
||||
|
||||
// 1. Обрабатываем квалифицированные диапазоны (SheetName!A1:B2)
|
||||
const qualifiedRangeMatches = expr.match(QUALIFIED_RANGE_RE)
|
||||
if (qualifiedRangeMatches) {
|
||||
for (const match of qualifiedRangeMatches) {
|
||||
const [sheetPart, rangePart] = match.split('!')
|
||||
const rangeCoords = parseCellRange(rangePart)
|
||||
|
||||
if (rangeCoords) {
|
||||
references.push({
|
||||
sheet: sheetPart,
|
||||
address: rangePart,
|
||||
isRange: true,
|
||||
...rangeCoords,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Обрабатываем локальные диапазоны (A1:B2)
|
||||
let cleanExpr = expr
|
||||
// Удаляем уже обработанные квалифицированные диапазоны
|
||||
cleanExpr = cleanExpr.replace(QUALIFIED_RANGE_RE, '')
|
||||
|
||||
const rangeMatches = cleanExpr.match(RANGE_RE)
|
||||
if (rangeMatches) {
|
||||
for (const match of rangeMatches) {
|
||||
const rangeCoords = parseCellRange(match)
|
||||
|
||||
if (rangeCoords) {
|
||||
references.push({
|
||||
sheet: null,
|
||||
address: match,
|
||||
isRange: true,
|
||||
...rangeCoords,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Обрабатываем квалифицированные одиночные ссылки (SheetName!A1)
|
||||
const qualifiedMatches = expr.match(QUALIFIED_REF_RE)
|
||||
if (qualifiedMatches) {
|
||||
for (const match of qualifiedMatches) {
|
||||
const [sheetPart, cellPart] = match.split('!')
|
||||
const cellCoords = parseCellAddress(cellPart)
|
||||
|
||||
if (cellCoords) {
|
||||
references.push({
|
||||
sheet: sheetPart,
|
||||
address: cellPart,
|
||||
isRange: false,
|
||||
startRow: cellCoords.row,
|
||||
startCol: cellCoords.col,
|
||||
endRow: cellCoords.row,
|
||||
endCol: cellCoords.col,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Обрабатываем локальные одиночные ссылки (A1, B2)
|
||||
// Удаляем уже обработанные квалифицированные ссылки и диапазоны
|
||||
cleanExpr = expr
|
||||
.replace(QUALIFIED_RANGE_RE, '')
|
||||
.replace(QUALIFIED_REF_RE, '')
|
||||
.replace(RANGE_RE, '')
|
||||
|
||||
const localMatches = cleanExpr.match(LOCAL_REF_RE)
|
||||
if (localMatches) {
|
||||
for (const match of localMatches) {
|
||||
// Пропускаем функции
|
||||
if (isFunction(match)) continue
|
||||
|
||||
const cellCoords = parseCellAddress(match)
|
||||
|
||||
if (cellCoords) {
|
||||
references.push({
|
||||
sheet: null,
|
||||
address: match,
|
||||
isRange: false,
|
||||
startRow: cellCoords.row,
|
||||
startCol: cellCoords.col,
|
||||
endRow: cellCoords.row,
|
||||
endCol: cellCoords.col,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return references
|
||||
}
|
||||
|
||||
// Интерфейс для подсвеченной ячейки
|
||||
export interface HighlightedCell {
|
||||
sheet: string // нормализованное имя листа ('L' или 'R')
|
||||
row: number
|
||||
col: number
|
||||
color: string // класс CSS для цвета подсветки
|
||||
}
|
||||
|
||||
// Конвертирует ссылки на ячейки в подсвеченные ячейки
|
||||
export function convertReferencesToHighlights(
|
||||
references: CellReference[],
|
||||
currentSheetType: 'report' | 'calculations'
|
||||
): HighlightedCell[] {
|
||||
const highlights: HighlightedCell[] = []
|
||||
const colors = [
|
||||
'bg-blue-200 border-blue-400',
|
||||
'bg-green-200 border-green-400',
|
||||
'bg-purple-200 border-purple-400',
|
||||
'bg-red-200 border-red-400',
|
||||
'bg-yellow-200 border-yellow-400',
|
||||
'bg-indigo-200 border-indigo-400',
|
||||
'bg-pink-200 border-pink-400',
|
||||
'bg-orange-200 border-orange-400',
|
||||
]
|
||||
|
||||
let colorIndex = 0
|
||||
|
||||
for (const ref of references) {
|
||||
let sheetName: string
|
||||
|
||||
// Определяем имя листа
|
||||
if (ref.sheet) {
|
||||
// Квалифицированная ссылка
|
||||
if (ref.sheet === 'L' || ref.sheet.toLowerCase() === 'report') {
|
||||
sheetName = 'L'
|
||||
} else if (
|
||||
ref.sheet === 'R' ||
|
||||
ref.sheet.toLowerCase() === 'calculations'
|
||||
) {
|
||||
sheetName = 'R'
|
||||
} else {
|
||||
// Неизвестный лист, пропускаем
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// Локальная ссылка - используем текущий лист
|
||||
sheetName = currentSheetType === 'report' ? 'L' : 'R'
|
||||
}
|
||||
|
||||
const color = colors[colorIndex % colors.length]
|
||||
colorIndex++
|
||||
|
||||
// Добавляем все ячейки в диапазоне
|
||||
for (let row = ref.startRow; row <= ref.endRow; row++) {
|
||||
for (let col = ref.startCol; col <= ref.endCol; col++) {
|
||||
highlights.push({
|
||||
sheet: sheetName,
|
||||
row,
|
||||
col,
|
||||
color,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return highlights
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export const HeaderBar: React.FC<HeaderBarProps> = ({ template, onBack }) => {
|
||||
className="flex items-center gap-1 hover:bg-muted"
|
||||
>
|
||||
<Wrench className="h-4 w-4" />
|
||||
<span className="text-sm">Элементы интерфейса</span>
|
||||
<span className="text-sm">Редактор интерфейса</span>
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ElementConstructor } from '@/component/TemplateManager/ElementConstruct
|
||||
import { Button } from '@/component/ui/button'
|
||||
import { useTemplateContext } from '@/entitiy/template/model/TemplateContext'
|
||||
import { Template, TemplateElement } from '@/type/template'
|
||||
import { ArrowLeft, FileText, Settings, Wrench } from 'lucide-react'
|
||||
import { ArrowLeft, FileText, Wrench } from 'lucide-react'
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
|
||||
@@ -145,8 +145,8 @@ export const ElementsCreation: FC = () => {
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Settings className="h-5 w-5" />
|
||||
<h1 className="text-lg font-semibold">Редактор шаблонов</h1>
|
||||
<Wrench className="h-5 w-5" />
|
||||
<h1 className="text-lg font-semibold">Редактор интерфейса</h1>
|
||||
<span className="text-sm text-muted-foreground">—</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{selectedTemplate.name}
|
||||
|
||||
Reference in New Issue
Block a user