// ============================================================================ // n8n Code Node: Отчёт о рейсах (HTML → Binary + Base64 PDF) // ============================================================================ // Упрощённая версия с возвратом binary HTML и подготовкой для PDF конвертации // ============================================================================ const inputItems = $input.all(); // ================== FALLBACK ================== if (!inputItems || inputItems.length === 0) { const html = '

Ошибка: данные не получены

'; return [{ binary: { data: Buffer.from(html, 'utf8'), mimeType: 'text/html', fileName: 'flights-report.html' }, json: { html: html, flights_count: 0, error: 'Нет входных данных' } }]; } // ================== ИЗВЛЕЧЕНИЕ ДАННЫХ ================== let flightAwareData = []; let flightRadar24Data = []; try { const fa = inputItems[0]?.json?.body?.flights; if (Array.isArray(fa)) flightAwareData = fa; } catch (e) { console.log('⚠️ Ошибка извлечения FlightAware:', e.message); } try { const fr = inputItems[1]?.json?.body?.data; if (Array.isArray(fr)) flightRadar24Data = fr; } catch (e) { console.log('⚠️ Ошибка извлечения FlightRadar24:', e.message); } // ================== УТИЛИТЫ ================== const safeStr = v => (v == null ? '' : String(v)); const safeDate = v => { if (!v) return '—'; try { const d = new Date(v); return isNaN(d.getTime()) ? '—' : d.toLocaleString('ru-RU', { timeZone: 'UTC', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } catch { return '—'; } }; const formatDuration = s => !s ? '—' : `${Math.floor(s / 3600)}ч ${Math.floor((s % 3600) / 60)}м`; const formatDistance = km => !km ? '—' : `${Number(km).toFixed(2)} км`; // ================== MERGE ПО REGISTRATION ================== const flightsMap = new Map(); flightAwareData.forEach(f => { const reg = safeStr(f.registration).trim(); if (!reg) return; if (!flightsMap.has(reg)) { flightsMap.set(reg, { registration: reg, flightNumber: safeStr(f.flight_number), ident: safeStr(f.ident), identIata: safeStr(f.ident_iata), aircraftType: safeStr(f.aircraft_type), fa: f, fr: null }); } else { flightsMap.get(reg).fa = f; } }); flightRadar24Data.forEach(f => { const reg = safeStr(f.reg).trim(); if (!reg) return; if (!flightsMap.has(reg)) { flightsMap.set(reg, { registration: reg, flightNumber: safeStr(f.flight), ident: safeStr(f.callsign), identIata: safeStr(f.flight), aircraftType: safeStr(f.type), fa: null, fr: f }); } else { flightsMap.get(reg).fr = f; } }); const flights = Array.from(flightsMap.values()); // ================== HTML GENERATION ================== const generateFlightCard = f => { const fa = f.fa; const fr = f.fr; let card = `

Рейс ${f.flightNumber || f.ident || '—'}

${f.registration}
Тип самолёта: ${f.aircraftType || '—'}
Идентификатор: ${f.ident || '—'} (${f.identIata || '—'})
`; if (fa) { card += `
FlightAware
Откуда: ${safeStr(fa.origin?.name || fa.origin?.code_iata || '—')} (${safeStr(fa.origin?.code_iata || '—')})
Куда: ${safeStr(fa.destination?.name || fa.destination?.code_iata || '—')} (${safeStr(fa.destination?.code_iata || '—')})
Вылет: ${safeDate(fa.actual_out)}
Прилёт: ${safeDate(fa.actual_in)}
Статус: ${safeStr(fa.status || '—')}
`; } else { card += `
FlightAware Данные не получены
`; } if (fr) { card += `
FlightRadar24
Откуда: ${safeStr(fr.orig_iata || '—')} (${safeStr(fr.orig_icao || '—')})
Куда: ${safeStr(fr.dest_iata || '—')} (${safeStr(fr.dest_icao || '—')})
Время полёта: ${formatDuration(fr.flight_time)}
Расстояние: ${formatDistance(fr.actual_distance)}
`; } else { card += `
FlightRadar24 Данные не получены
`; } card += `
`; return card; }; const now = new Date(); const reportDate = now.toLocaleString('ru-RU', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }); const html = ` Отчёт о рейсах

Отчёт о рейсах

Дата формирования: ${reportDate}
FlightAware: ${flightAwareData.length > 0 ? '✓ Данные получены' : '✗ Данные отсутствуют'} FlightRadar24: ${flightRadar24Data.length > 0 ? '✓ Данные получены' : '✗ Данные отсутствуют'}
${flights.length ? flights.map(generateFlightCard).join('') : '
Данные о рейсах не найдены
'}
`; // ================== ПОДГОТОВКА ДАННЫХ ДЛЯ PDF КОНВЕРТАЦИИ ================== // Настройки сервиса (замените на ваши) const PDF_SERVICE_URL = 'https://api.htmlpdfapi.com/v1/pdf'; const PDF_API_KEY = 'YOUR_API_KEY'; // ⚠️ ЗАМЕНИТЕ на ваш API ключ // ================== RETURN ================== return [{ // Binary HTML файл (для использования в Convert to File ноде или сохранения) binary: { data: Buffer.from(html, 'utf8'), mimeType: 'text/html', fileName: `flights-report-${now.toISOString().split('T')[0]}.html` }, // JSON данные json: { // HTML строка (для конвертации в PDF через HTTP Request) html: html, // Метаданные flights_count: flights.length, generated_at: now.toISOString(), sources: { flightaware: { available: flightAwareData.length > 0, count: flightAwareData.length }, flightradar24: { available: flightRadar24Data.length > 0, count: flightRadar24Data.length } }, // Данные для конвертации в base64 PDF (используйте в следующей HTTP Request ноде) pdf_request: { method: 'POST', url: PDF_SERVICE_URL, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${PDF_API_KEY}` }, body: JSON.stringify({ html: html, options: { format: 'A4', printBackground: true, margin: { top: '20mm', right: '15mm', bottom: '20mm', left: '15mm' } }, base64: true }) }, // Удобные поля для HTTP Request ноды pdf_request_method: 'POST', pdf_request_url: PDF_SERVICE_URL, pdf_request_headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${PDF_API_KEY}` }, pdf_request_body: JSON.stringify({ html: html, options: { format: 'A4', printBackground: true, margin: { top: '20mm', right: '15mm', bottom: '20mm', left: '15mm' } }, base64: true }) } }]; // ============================================================================ // ИСПОЛЬЗОВАНИЕ: // ============================================================================ // 1. Binary HTML можно использовать в ноде "Convert to File" или сохранить // 2. JSON.html можно использовать для конвертации в PDF через HTTP Request // 3. JSON.pdf_request_* поля готовы для использования в HTTP Request ноде // 4. После HTTP Request используйте N8N_EXTRACT_BASE64_FROM_RESPONSE.js // для извлечения base64 PDF из ответа // ============================================================================