загрузка excel

This commit is contained in:
2025-07-18 10:52:48 +03:00
parent 021368f173
commit 8b67db832c
3 changed files with 171 additions and 84 deletions

View File

@@ -23,6 +23,8 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
const [excelData, setExcelData] = useState<Record<string, any>>(
template.excelData || {},
)
const [isLoading, setIsLoading] = useState(false)
const [dataVersion, setDataVersion] = useState(0) // Для принудительного обновления
const fileInputRef = useRef<HTMLInputElement>(null)
const navigate = useNavigate()
@@ -30,7 +32,9 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
const file = event.target.files?.[0]
if (!file) return
setIsLoading(true)
const reader = new FileReader()
reader.onload = (e) => {
try {
const data = new Uint8Array(e.target?.result as ArrayBuffer)
@@ -39,38 +43,94 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
// Читаем первый лист
const firstSheetName = workbook.SheetNames[0]
const worksheet = workbook.Sheets[firstSheetName]
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 })
// Получаем диапазон ячеек
const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1:A1')
// Преобразуем в формат для нашей системы
const formattedData: Record<string, any> = {}
const mergedCells: Array<{ from: string; to: string; value: any }> = []
;(jsonData as any[][]).forEach((row, rowIndex) => {
row.forEach((cell, colIndex) => {
if (cell !== undefined && cell !== null && cell !== '') {
const cellName =
String.fromCharCode(65 + colIndex) + (rowIndex + 1)
formattedData[cellName] = cell
// Обрабатываем объединенные ячейки
const merges = worksheet['!merges'] || []
// Сначала читаем обычные ячейки
for (let R = range.s.r; R <= range.e.r; ++R) {
for (let C = range.s.c; C <= range.e.c; ++C) {
const cellAddress = XLSX.utils.encode_cell({ r: R, c: C })
const cell = worksheet[cellAddress]
if (
cell &&
cell.v !== undefined &&
cell.v !== null &&
cell.v !== ''
) {
formattedData[cellAddress] = cell.v
}
}
}
// Обрабатываем объединенные ячейки
merges.forEach((merge) => {
const startCell = XLSX.utils.encode_cell({
r: merge.s.r,
c: merge.s.c,
})
const endCell = XLSX.utils.encode_cell({ r: merge.e.r, c: merge.e.c })
const startCellData = worksheet[startCell]
if (startCellData && startCellData.v !== undefined) {
// Записываем значение в первую ячейку объединенного диапазона
formattedData[startCell] = startCellData.v
// Сохраняем информацию об объединении для UI
mergedCells.push({
from: startCell,
to: endCell,
value: startCellData.v,
})
// Заполняем остальные ячейки в объединенном диапазоне пустыми значениями
// но помечаем их как часть объединения
for (let R = merge.s.r; R <= merge.e.r; ++R) {
for (let C = merge.s.c; C <= merge.e.c; ++C) {
const cellAddr = XLSX.utils.encode_cell({ r: R, c: C })
if (cellAddr !== startCell) {
formattedData[cellAddr] = '' // Пустое значение для объединенных ячеек
}
}
}
}
})
setExcelData(formattedData)
// Обновляем состояние
const newData = { ...formattedData }
setExcelData(newData)
setEditedTemplate((prev) => ({
...prev,
excelFile: file,
excelData: formattedData,
excelData: newData,
mergedCells: mergedCells, // Сохраняем информацию об объединенных ячейках
updatedAt: new Date(),
}))
// Принудительно обновляем данные в таблице
setTimeout(() => {
setExcelData({ ...formattedData })
}, 100)
// Принудительно обновляем версию данных для перерендера
setDataVersion((prev) => prev + 1)
setIsLoading(false)
} catch (error) {
console.error('Ошибка при чтении Excel файла:', error)
alert('Ошибка при чтении Excel файла')
setIsLoading(false)
}
}
reader.onerror = () => {
alert('Ошибка при загрузке файла')
setIsLoading(false)
}
reader.readAsArrayBuffer(file)
}
@@ -156,11 +216,23 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
size="sm"
onClick={() => fileInputRef.current?.click()}
className="flex h-7 items-center gap-2"
disabled={isLoading}
>
<Upload className="h-3 w-3" />
<span className="text-xs">
{editedTemplate.excelFile ? 'Заменить файл' : 'Загрузить Excel'}
</span>
{isLoading ? (
<>
<div className="h-3 w-3 animate-spin rounded-full border-2 border-current border-t-transparent" />
<span className="text-xs">Загрузка...</span>
</>
) : (
<>
<Upload className="h-3 w-3" />
<span className="text-xs">
{editedTemplate.excelFile
? 'Заменить файл'
: 'Загрузить Excel'}
</span>
</>
)}
</Button>
</div>
</div>
@@ -168,7 +240,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
{/* Таблицы - теперь занимают всё оставшееся пространство */}
<div className="min-h-0 flex-1">
<DualSpreadsheet templateData={{ Report: excelData }} />
<DualSpreadsheet key={dataVersion} templateData={{ L: excelData }} />
</div>
</div>
)