// ============================================================================ // n8n Code Node: Обработка данных о рейсах из FlightAware и FlightRadar24 // ============================================================================ // Объединяет данные из двух источников и формирует красивый HTML для PDF // ============================================================================ // ==== ПОЛУЧЕНИЕ ВХОДНЫХ ДАННЫХ ==== // Ожидаемая структура: массив с двумя элементами // [0] - данные из FlightAware (body.flights[]) // [1] - данные из FlightRadar24 (body.data[]) const inputItems = $input.all(); if (!inputItems || inputItems.length === 0) { return [{ json: { error: 'Нет входных данных', html: '

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

', flights: [], sources: { flightaware: false, flightradar24: false } } }]; } // ==== ИЗВЛЕЧЕНИЕ ДАННЫХ ИЗ ИСТОЧНИКОВ ==== let flightAwareData = []; let flightRadar24Data = []; try { // Первый элемент - FlightAware const faItem = inputItems[0]; if (faItem && faItem.json && faItem.json.body && faItem.json.body.flights) { flightAwareData = Array.isArray(faItem.json.body.flights) ? faItem.json.body.flights : []; } } catch (e) { console.log('⚠️ Ошибка извлечения FlightAware:', e.message); } try { // Второй элемент - FlightRadar24 const fr24Item = inputItems[1]; if (fr24Item && fr24Item.json && fr24Item.json.body && fr24Item.json.body.data) { flightRadar24Data = Array.isArray(fr24Item.json.body.data) ? fr24Item.json.body.data : []; } } 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 d.toLocaleString('ru-RU', { timeZone: 'UTC', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } catch { return v; } }; const formatDuration = (seconds) => { if (!seconds) return '—'; const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); return `${hours}ч ${minutes}м`; }; const formatDistance = (km) => { if (!km) return '—'; return `${Number(km).toFixed(2)} км`; }; // ==== ОБЪЕДИНЕНИЕ ДАННЫХ ПО REGISTRATION ==== // Создаём карту для быстрого поиска const flightsMap = new Map(); // Добавляем данные из FlightAware flightAwareData.forEach(flight => { const reg = safeStr(flight.registration).trim(); if (!reg) return; if (!flightsMap.has(reg)) { flightsMap.set(reg, { registration: reg, flightNumber: safeStr(flight.flight_number), ident: safeStr(flight.ident), identIata: safeStr(flight.ident_iata), aircraftType: safeStr(flight.aircraft_type), flightAware: flight, flightRadar24: null }); } else { flightsMap.get(reg).flightAware = flight; } }); // Добавляем данные из FlightRadar24 flightRadar24Data.forEach(flight => { const reg = safeStr(flight.reg).trim(); if (!reg) return; if (!flightsMap.has(reg)) { flightsMap.set(reg, { registration: reg, flightNumber: safeStr(flight.flight), ident: safeStr(flight.callsign), identIata: safeStr(flight.flight), aircraftType: safeStr(flight.type), flightAware: null, flightRadar24: flight }); } else { flightsMap.get(reg).flightRadar24 = flight; } }); // Преобразуем Map в массив const mergedFlights = Array.from(flightsMap.values()); // ==== ГЕНЕРАЦИЯ HTML ==== const generateFlightCard = (flight) => { const fa = flight.flightAware; const fr24 = flight.flightRadar24; let html = `

Рейс ${flight.flightNumber || flight.ident || 'N/A'}

${flight.registration}
Тип самолёта: ${flight.aircraftType || '—'}
Идентификатор: ${flight.ident || '—'} (${flight.identIata || '—'})
`; // Данные из FlightAware if (fa) { html += `
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.scheduled_out)}
Фактический вылет: ${safeDate(fa.actual_out)}
Взлёт: ${safeDate(fa.actual_off)} ${fa.actual_runway_off ? `(ВПП ${fa.actual_runway_off})` : ''}
Посадка: ${safeDate(fa.actual_on)} ${fa.actual_runway_on ? `(ВПП ${fa.actual_runway_on})` : ''}
Фактический прилёт: ${safeDate(fa.actual_in)}
Статус: ${safeStr(fa.status || '—')}
${fa.departure_delay !== null && fa.departure_delay !== undefined ? `
Задержка вылета: ${fa.departure_delay > 0 ? '+' : ''}${Math.floor(fa.departure_delay / 60)} мин
` : ''} ${fa.arrival_delay !== null && fa.arrival_delay !== undefined ? `
Задержка прилёта: ${fa.arrival_delay > 0 ? '+' : ''}${Math.floor(fa.arrival_delay / 60)} мин
` : ''} ${fa.gate_origin ? `
Гейт вылета: ${fa.gate_origin}
` : ''} ${fa.gate_destination ? `
Гейт прилёта: ${fa.gate_destination}
` : ''} ${fa.baggage_claim ? `
Выдача багажа: ${fa.baggage_claim}
` : ''}
`; } else { html += `
FlightAware Данные не получены
`; } // Данные из FlightRadar24 if (fr24) { html += `
FlightRadar24
Откуда: ${safeStr(fr24.orig_iata || '—')} (${safeStr(fr24.orig_icao || '—')})
Куда: ${safeStr(fr24.dest_iata || '—')} (${safeStr(fr24.dest_icao || '—')})
Взлёт: ${safeDate(fr24.datetime_takeoff)} ${fr24.runway_takeoff ? `(ВПП ${fr24.runway_takeoff})` : ''}
Посадка: ${safeDate(fr24.datetime_landed)} ${fr24.runway_landed ? `(ВПП ${fr24.runway_landed})` : ''}
Время полёта: ${formatDuration(fr24.flight_time)}
Фактическое расстояние: ${formatDistance(fr24.actual_distance)}
Кратчайшее расстояние: ${formatDistance(fr24.circle_distance)}
Статус полёта: ${fr24.flight_ended ? 'Завершён' : 'В процессе'}
`; } else { html += `
FlightRadar24 Данные не получены
`; } html += `
`; return html; }; // ==== ГЕНЕРАЦИЯ ПОЛНОГО HTML ДОКУМЕНТА ==== const generateFullHTML = (flights) => { const now = new Date(); const reportDate = now.toLocaleString('ru-RU', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }); let flightsHTML = ''; if (flights.length === 0) { flightsHTML = '
Данные о рейсах не найдены
'; } else { flightsHTML = flights.map(flight => generateFlightCard(flight)).join(''); } return ` Отчёт о рейсах

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

Дата формирования: ${reportDate}
FlightAware: ${flightAwareData.length > 0 ? '✓ Данные получены' : '✗ Данные отсутствуют'} FlightRadar24: ${flightRadar24Data.length > 0 ? '✓ Данные получены' : '✗ Данные отсутствуют'}
${flightsHTML}
`; }; // ==== ФОРМИРОВАНИЕ РЕЗУЛЬТАТА ==== const html = generateFullHTML(mergedFlights); // ==== ПОДГОТОВКА ДАННЫХ ДЛЯ КОНВЕРТАЦИИ В BASE64 PDF ==== // Эти данные будут использованы в следующей HTTP Request ноде // для конвертации HTML в PDF и получения base64 // Настройки сервиса конвертации (замените на ваши) const PDF_SERVICE_URL = 'https://api.htmlpdfapi.com/v1/pdf'; // Или другой сервис const PDF_API_KEY = 'YOUR_API_KEY'; // ⚠️ ЗАМЕНИТЕ на ваш API ключ // Подготовка запроса для HTTP Request ноды const pdfRequestData = { 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 // Запрашиваем base64 напрямую }) }; return [{ json: { html: html, flights: mergedFlights, flights_count: mergedFlights.length, sources: { flightaware: { available: flightAwareData.length > 0, count: flightAwareData.length }, flightradar24: { available: flightRadar24Data.length > 0, count: flightRadar24Data.length } }, generated_at: new Date().toISOString(), // Данные для конвертации в PDF (используйте в следующей HTTP Request ноде) pdf_request: pdfRequestData, pdf_request_method: pdfRequestData.method, pdf_request_url: pdfRequestData.url, pdf_request_headers: pdfRequestData.headers, pdf_request_body: pdfRequestData.body } }];