import React, { useState, useEffect } from "react"; import { Modal, Button, message } from "antd"; import { ZoomInOutlined, ZoomOutOutlined, UndoOutlined, } from "@ant-design/icons"; import * as XLSX from "xlsx"; import { apiClient } from "../api"; interface ExcelPreviewModalProps { visible: boolean; onCancel: () => void; fileUrl: string; } /** * Компонент для предпросмотра Excel файлов * Позволяет просматривать содержимое Excel файлов с возможностью масштабирования */ const ExcelPreviewModal: React.FC = ({ visible, onCancel, fileUrl, }) => { // Данные таблицы из Excel файла const [data, setData] = useState< (string | number | boolean | null | undefined)[][] >([]); // Масштаб отображения таблицы const [scale, setScale] = useState(1); /** * Загрузка и парсинг Excel файла при изменении видимости или URL файла */ useEffect(() => { const loadExcelFile = async () => { if (!visible || !fileUrl) { return; } console.log("ExcelPreviewModal: Start loading", fileUrl); try { // Загрузка файла через apiClient с авторизацией const response = await apiClient.get(fileUrl, { responseType: "arraybuffer", }); console.log( "ExcelPreviewModal: Got response", response.status, response.data.byteLength ); const arrayBuffer = response.data; // Чтение Excel файла const workbook = XLSX.read(arrayBuffer, { type: "array" }); console.log("ExcelPreviewModal: Workbook parsed", workbook.SheetNames); // Получение первого листа const firstSheetName = workbook.SheetNames[0]; const sheet = workbook.Sheets[firstSheetName]; // Преобразование листа в JSON-массив массивов const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1, }) as (string | number | boolean | null | undefined)[][]; setData(jsonData); console.log("ExcelPreviewModal: Data set, rows:", jsonData.length); // Сброс масштаба при загрузке нового файла setScale(1); } catch (error) { console.error("ExcelPreviewModal Error:", error); // Обработка ошибок авторизации (401) обрабатывается в интерсепторе apiClient if (error && typeof error === "object" && "response" in error) { const axiosError = error as { response?: { status?: number } }; if (axiosError.response?.status === 401) { message.error( "Ошибка авторизации. Необходима повторная авторизация." ); } else { message.error("Не удалось загрузить Excel файл"); } } else { message.error("Не удалось загрузить Excel файл"); } setData([]); } }; loadExcelFile(); }, [visible, fileUrl]); /** * Увеличение масштаба */ const handleZoomIn = () => { setScale((prev) => Math.min(prev + 0.1, 3)); }; /** * Уменьшение масштаба */ const handleZoomOut = () => { setScale((prev) => Math.max(prev - 0.1, 0.5)); }; /** * Сброс масштаба до исходного значения */ const handleReset = () => { setScale(1); }; /** * Обработчик закрытия модалки */ const handleCancel = () => { setData([]); onCancel(); }; return ( {/* Панель инструментов для управления масштабом */}
Масштаб: {Math.round(scale * 100)}%
{/* Контейнер с прокруткой для таблицы */}
{/* Таблица с данными Excel */} {data.map((row, rowIndex) => ( {row.map((cell, cellIndex) => ( ))} ))}
{cell !== undefined && cell !== null ? String(cell) : ""}
); }; export default ExcelPreviewModal;