# Руководство по API для фронтенда: Генерация и история отчётов ## Базовый URL ``` /api/parser/report ``` ## 1. Генерация отчёта ### POST /api/parser/report/generate Создаёт новый отчёт и возвращает файл для скачивания. **Заголовки:** ``` Content-Type: application/json ``` **Тело запроса:** ```json { "reportTitle": "Еженедельный анализ новостного фона", "authorName": "Имя Аналитика", "companyName": "Название Компании Клиента", "startDate": "2025-09-10T00:00:00", "endDate": "2025-09-17T23:59:59", "format": "PDF" } ``` **Параметры:** - `reportTitle` (string, обязательный) - заголовок отчёта - `authorName` (string, обязательный) - имя автора - `companyName` (string, обязательный) - название компании - `startDate` (string, обязательный) - дата начала периода в формате ISO 8601 - `endDate` (string, обязательный) - дата окончания периода в формате ISO 8601 - `format` (string, обязательный) - формат файла: "PDF" или "DOCX" **Успешный ответ (200 OK):** ``` Content-Type: application/pdf (или application/vnd.openxmlformats-officedocument.wordprocessingml.document) Content-Disposition: attachment; filename="report_2025-09-17-1234567890.pdf" [бинарные данные файла] ``` **Пример на JavaScript:** ```javascript async function generateReport(reportData) { try { const response = await fetch('/api/parser/report/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(reportData) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } // Получаем имя файла из заголовка const contentDisposition = response.headers.get('Content-Disposition'); const filename = contentDisposition ? contentDisposition.split('filename=')[1].replace(/"/g, '') : 'report.pdf'; // Создаём blob и скачиваем файл const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (error) { console.error('Ошибка при генерации отчёта:', error); } } // Использование const reportData = { reportTitle: 'Еженедельный анализ новостного фона', authorName: 'Иван Петров', companyName: 'ООО Рога и Копыта', startDate: '2025-01-01T00:00:00', endDate: '2025-01-07T23:59:59', format: 'PDF' }; generateReport(reportData); ``` ## 2. Получение истории отчётов ### GET /api/parser/report/history Возвращает пагинированный список всех сгенерированных отчётов. **Параметры запроса:** - `page` (int, опциональный, по умолчанию: 0) - номер страницы (начиная с 0) - `size` (int, опциональный, по умолчанию: 20) - количество элементов на странице - `sort` (string, опциональный, по умолчанию: "createdAt,desc") - поле и направление сортировки **Пример запроса:** ``` GET /api/parser/report/history?page=0&size=10&sort=createdAt,desc ``` **Успешный ответ (200 OK):** ```json { "content": [ { "id": "507f1f77bcf86cd799439011", "reportTitle": "Еженедельный анализ новостного фона", "authorName": "Имя Аналитика", "companyName": "Название Компании Клиента", "startDate": "2025-09-10T00:00:00", "endDate": "2025-09-17T23:59:59", "format": "PDF", "filename": "report_2025-09-17-1234567890.pdf", "fileSize": 1234567, "createdAt": "2025-09-17T21:11:58" } ], "pageable": { "sort": { "sorted": true, "unsorted": false, "empty": false }, "pageNumber": 0, "pageSize": 20, "offset": 0, "paged": true, "unpaged": false }, "totalElements": 1, "totalPages": 1, "last": true, "first": true, "numberOfElements": 1, "size": 20, "number": 0, "sort": { "sorted": true, "unsorted": false, "empty": false }, "empty": false } ``` **Пример на JavaScript:** ```javascript async function getReportHistory(page = 0, size = 20, sort = 'createdAt,desc') { try { const params = new URLSearchParams({ page: page.toString(), size: size.toString(), sort: sort }); const response = await fetch(`/api/parser/report/history?${params}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error('Ошибка при получении истории отчётов:', error); throw error; } } // Использование getReportHistory(0, 10, 'createdAt,desc') .then((data) => { console.log('Отчёты:', data.content); console.log('Всего элементов:', data.totalElements); console.log('Всего страниц:', data.totalPages); }) .catch((error) => { console.error('Ошибка:', error); }); ``` ## 3. Скачивание отчёта из истории ### GET /api/parser/report/history/{id} Скачивает конкретный отчёт по его ID. **Параметры:** - `id` (string, обязательный) - ID отчёта из истории **Успешный ответ (200 OK):** ``` Content-Type: application/pdf (или application/vnd.openxmlformats-officedocument.wordprocessingml.document) Content-Disposition: attachment; filename="report_2025-09-17-1234567890.pdf" [бинарные данные файла] ``` **Ошибки:** - `404 Not Found` - отчёт с указанным ID не найден - `500 Internal Server Error` - ошибка при чтении файла **Пример на JavaScript:** ```javascript async function downloadReport(reportId) { try { const response = await fetch(`/api/parser/report/history/${reportId}`); if (response.status === 404) { throw new Error('Отчёт не найден'); } if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } // Получаем имя файла из заголовка const contentDisposition = response.headers.get('Content-Disposition'); const filename = contentDisposition ? contentDisposition.split('filename=')[1].replace(/"/g, '') : 'report.pdf'; // Создаём blob и скачиваем файл const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (error) { console.error('Ошибка при скачивании отчёта:', error); throw error; } } // Использование downloadReport('507f1f77bcf86cd799439011') .then(() => console.log('Отчёт скачан')) .catch((error) => console.error('Ошибка:', error)); ``` ## 4. Полный пример React компонента ```jsx import React, { useState, useEffect } from 'react'; const ReportManager = () => { const [reports, setReports] = useState([]); const [loading, setLoading] = useState(false); const [currentPage, setCurrentPage] = useState(0); const [totalPages, setTotalPages] = useState(0); const [formData, setFormData] = useState({ reportTitle: '', authorName: '', companyName: '', startDate: '', endDate: '', format: 'PDF' }); // Загрузка истории отчётов const loadReports = async (page = 0) => { setLoading(true); try { const data = await getReportHistory(page, 10); setReports(data.content); setTotalPages(data.totalPages); setCurrentPage(page); } catch (error) { console.error('Ошибка загрузки истории:', error); } finally { setLoading(false); } }; // Генерация нового отчёта const handleGenerate = async (e) => { e.preventDefault(); setLoading(true); try { await generateReport(formData); // Перезагружаем историю после генерации await loadReports(currentPage); } catch (error) { console.error('Ошибка генерации:', error); } finally { setLoading(false); } }; // Скачивание отчёта const handleDownload = async (reportId) => { try { await downloadReport(reportId); } catch (error) { console.error('Ошибка скачивания:', error); } }; useEffect(() => { loadReports(); }, []); return (
Автор: {report.authorName}
Компания: {report.companyName}
Период: {new Date(report.startDate).toLocaleDateString()} - {new Date(report.endDate).toLocaleDateString()}
Формат: {report.format}
Размер: {(report.fileSize / 1024).toFixed(1)} KB
Создан: {new Date(report.createdAt).toLocaleString()}