feat: Telegram Mini App integration and UX improvements
- Добавлена полная интеграция с Telegram Mini App (динамическая загрузка SDK) - Отдельный компактный дизайн для Telegram Mini App - Добавлен loader при инициализации (предотвращает мелькание SMS-авторизации) - Улучшена навигация: кнопки "Назад" и "К списку заявок" теперь сохраняют авторизацию - Telegram Mini App: кнопка "Выход" просто закрывает приложение - Telegram Mini App: заявки "В работе" скрыты из списка - Веб-версия: для заявок "В работе" добавлена кнопка "Просмотреть в Telegram" (ссылка на @klientprav_bot) - Telegram Mini App: кнопки действий в черновиках расположены вертикально - Веб-версия: убрано отображение номера телефона в приветствии - Исправлена проблема с возвратом к списку черновиков (не требует повторной SMS-авторизации) - Заблокировано удаление и редактирование заявок со статусом "В работе" - Добавлена документация по Telegram Mini App интеграции
This commit is contained in:
320
docs/N8N_FLIGHTS_WORKFLOW_EXAMPLE.md
Normal file
320
docs/N8N_FLIGHTS_WORKFLOW_EXAMPLE.md
Normal file
@@ -0,0 +1,320 @@
|
||||
# Пример Workflow для обработки рейсов с Base64 PDF
|
||||
|
||||
## Структура Workflow
|
||||
|
||||
```
|
||||
HTTP Request (FlightAware)
|
||||
↓
|
||||
HTTP Request (FlightRadar24)
|
||||
↓
|
||||
Code: Process Flights Data ← N8N_CODE_PROCESS_FLIGHTS_DATA.js
|
||||
↓
|
||||
Code: Prepare PDF Request ← N8N_FLIGHTS_PDF_BASE64_COMPLETE.js
|
||||
↓
|
||||
HTTP Request (Convert to PDF) ← Внешний сервис конвертации
|
||||
↓
|
||||
Code: Extract Base64 PDF ← N8N_FLIGHTS_PDF_BASE64_FULL.js
|
||||
↓
|
||||
[Использование base64 PDF]
|
||||
├─→ Save File
|
||||
├─→ Send Email
|
||||
├─→ Upload to S3
|
||||
└─→ Return in API Response
|
||||
```
|
||||
|
||||
## Детальная настройка нод
|
||||
|
||||
### 1. HTTP Request: FlightAware
|
||||
- **Method:** GET/POST (в зависимости от API)
|
||||
- **URL:** `https://flightaware.com/api/...`
|
||||
- **Authentication:** По необходимости
|
||||
|
||||
### 2. HTTP Request: FlightRadar24
|
||||
- **Method:** GET/POST (в зависимости от API)
|
||||
- **URL:** `https://flightradar24.com/api/...`
|
||||
- **Authentication:** По необходимости
|
||||
|
||||
### 3. Code: Process Flights Data
|
||||
**Код:** Скопируйте из `N8N_CODE_PROCESS_FLIGHTS_DATA.js`
|
||||
|
||||
**Входные данные:**
|
||||
- Два элемента из предыдущих HTTP Request нод
|
||||
|
||||
**Выходные данные:**
|
||||
```json
|
||||
{
|
||||
"html": "<!DOCTYPE html>...",
|
||||
"flights": [...],
|
||||
"flights_count": 2,
|
||||
"sources": {...},
|
||||
"generated_at": "2026-01-14T..."
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Code: Prepare PDF Request
|
||||
**Код:** Скопируйте из `N8N_FLIGHTS_PDF_BASE64_COMPLETE.js`
|
||||
|
||||
**Настройка:**
|
||||
- Замените `PDF_SERVICE_URL` на URL вашего сервиса
|
||||
- Замените `PDF_API_KEY` на ваш API ключ
|
||||
|
||||
**Выходные данные:**
|
||||
```json
|
||||
{
|
||||
"http_method": "POST",
|
||||
"http_url": "https://api.htmlpdfapi.com/v1/pdf",
|
||||
"http_headers": {...},
|
||||
"http_body": "{...}",
|
||||
"html_length": 12345,
|
||||
"flights_count": 2
|
||||
}
|
||||
```
|
||||
|
||||
### 5. HTTP Request: Convert to PDF
|
||||
**Настройка:**
|
||||
- **Method:** `{{ $json.http_method }}`
|
||||
- **URL:** `{{ $json.http_url }}`
|
||||
- **Authentication:** По необходимости (через Headers)
|
||||
- **Headers:**
|
||||
```json
|
||||
{{ $json.http_headers }}
|
||||
```
|
||||
- **Body:**
|
||||
```json
|
||||
{{ $json.http_body }}
|
||||
```
|
||||
- **Response Format:** `JSON` или `Binary` (зависит от сервиса)
|
||||
|
||||
**Пример для htmlpdfapi.com:**
|
||||
```json
|
||||
{
|
||||
"method": "POST",
|
||||
"url": "https://api.htmlpdfapi.com/v1/pdf",
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer YOUR_API_KEY"
|
||||
},
|
||||
"body": {
|
||||
"html": "{{ $('Code: Process Flights Data').first().json.html }}",
|
||||
"options": {
|
||||
"format": "A4",
|
||||
"printBackground": true
|
||||
},
|
||||
"base64": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Code: Extract Base64 PDF
|
||||
**Код:** Скопируйте из `N8N_FLIGHTS_PDF_BASE64_FULL.js`
|
||||
|
||||
**Входные данные:**
|
||||
- Ответ от HTTP Request ноды (JSON или Binary)
|
||||
|
||||
**Выходные данные:**
|
||||
```json
|
||||
{
|
||||
"pdf_base64": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9MZW5ndGg...",
|
||||
"pdf_size_bytes": 123456,
|
||||
"pdf_size_mb": "0.12",
|
||||
"success": true,
|
||||
"source": "json_response"
|
||||
}
|
||||
```
|
||||
|
||||
## Использование base64 PDF
|
||||
|
||||
### Вариант A: Сохранение в файл
|
||||
|
||||
**Code Node:**
|
||||
```javascript
|
||||
const base64 = $('Code: Extract Base64 PDF').first().json.pdf_base64;
|
||||
const filename = `flights-report-${new Date().toISOString().split('T')[0]}.pdf`;
|
||||
|
||||
// Конвертируем base64 в binary
|
||||
const pdfBuffer = Buffer.from(base64, 'base64');
|
||||
|
||||
return [{
|
||||
binary: {
|
||||
data: pdfBuffer,
|
||||
fileName: filename,
|
||||
mimeType: 'application/pdf'
|
||||
},
|
||||
json: {
|
||||
filename: filename,
|
||||
size_bytes: pdfBuffer.length
|
||||
}
|
||||
}];
|
||||
```
|
||||
|
||||
Затем используйте ноду **Write Binary File** или **Save to S3**.
|
||||
|
||||
### Вариант B: Отправка по Email
|
||||
|
||||
**Code Node:**
|
||||
```javascript
|
||||
const base64 = $('Code: Extract Base64 PDF').first().json.pdf_base64;
|
||||
const pdfBuffer = Buffer.from(base64, 'base64');
|
||||
|
||||
return [{
|
||||
json: {
|
||||
to: 'recipient@example.com',
|
||||
subject: 'Отчёт о рейсах',
|
||||
text: 'Во вложении отчёт о рейсах.',
|
||||
attachments: [{
|
||||
filename: 'flights-report.pdf',
|
||||
content: pdfBuffer,
|
||||
contentType: 'application/pdf'
|
||||
}]
|
||||
}
|
||||
}];
|
||||
```
|
||||
|
||||
Затем используйте ноду **Email Send**.
|
||||
|
||||
### Вариант C: Возврат в API Response
|
||||
|
||||
**Code Node (перед Response нодой):**
|
||||
```javascript
|
||||
const base64 = $('Code: Extract Base64 PDF').first().json.pdf_base64;
|
||||
const processedData = $('Code: Process Flights Data').first().json;
|
||||
|
||||
return [{
|
||||
json: {
|
||||
success: true,
|
||||
flights_count: processedData.flights_count,
|
||||
pdf_base64: base64,
|
||||
pdf_size_mb: $('Code: Extract Base64 PDF').first().json.pdf_size_mb,
|
||||
generated_at: processedData.generated_at
|
||||
}
|
||||
}];
|
||||
```
|
||||
|
||||
### Вариант D: Загрузка в S3/Nextcloud
|
||||
|
||||
**Code Node:**
|
||||
```javascript
|
||||
const base64 = $('Code: Extract Base64 PDF').first().json.pdf_base64;
|
||||
const pdfBuffer = Buffer.from(base64, 'base64');
|
||||
const filename = `flights-report-${new Date().toISOString().split('T')[0]}.pdf`;
|
||||
|
||||
return [{
|
||||
binary: {
|
||||
data: pdfBuffer,
|
||||
fileName: filename,
|
||||
mimeType: 'application/pdf'
|
||||
},
|
||||
json: {
|
||||
bucket: 'your-bucket',
|
||||
key: `reports/${filename}`,
|
||||
contentType: 'application/pdf'
|
||||
}
|
||||
}];
|
||||
```
|
||||
|
||||
Затем используйте ноду **S3 Upload** или **Nextcloud Upload**.
|
||||
|
||||
## Альтернативные сервисы конвертации
|
||||
|
||||
### 1. htmlpdfapi.com
|
||||
```javascript
|
||||
{
|
||||
"url": "https://api.htmlpdfapi.com/v1/pdf",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer YOUR_API_KEY"
|
||||
},
|
||||
"body": {
|
||||
"html": "{{ HTML }}",
|
||||
"base64": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. pdfshift.io
|
||||
```javascript
|
||||
{
|
||||
"url": "https://api.pdfshift.io/v3/convert/pdf",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Basic " + Buffer.from("api:YOUR_API_KEY").toString("base64")
|
||||
},
|
||||
"body": {
|
||||
"source": "{{ HTML }}",
|
||||
"format": "A4"
|
||||
}
|
||||
}
|
||||
// Ответ содержит base64 в поле "pdf"
|
||||
```
|
||||
|
||||
### 3. api2pdf.com
|
||||
```javascript
|
||||
{
|
||||
"url": "https://v2.api2pdf.com/chrome/html",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Authorization": "YOUR_API_KEY",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"html": "{{ HTML }}",
|
||||
"inlinePdf": true,
|
||||
"fileName": "flights-report.pdf"
|
||||
}
|
||||
}
|
||||
// Ответ содержит base64 в поле "pdf"
|
||||
```
|
||||
|
||||
### 4. Self-hosted: Gotenberg
|
||||
```javascript
|
||||
{
|
||||
"url": "http://your-gotenberg-server:3000/forms/chromium/convert/html",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "multipart/form-data"
|
||||
},
|
||||
"body": {
|
||||
"files": [{
|
||||
"name": "index.html",
|
||||
"content": "{{ HTML }}"
|
||||
}]
|
||||
}
|
||||
}
|
||||
// Ответ - binary PDF, конвертируем в base64
|
||||
```
|
||||
|
||||
## Отладка
|
||||
|
||||
### Проверка HTML
|
||||
```javascript
|
||||
const html = $('Code: Process Flights Data').first().json.html;
|
||||
console.log('HTML length:', html.length);
|
||||
console.log('HTML preview:', html.substring(0, 500));
|
||||
```
|
||||
|
||||
### Проверка base64
|
||||
```javascript
|
||||
const base64 = $('Code: Extract Base64 PDF').first().json.pdf_base64;
|
||||
console.log('Base64 length:', base64.length);
|
||||
console.log('Base64 preview:', base64.substring(0, 100));
|
||||
```
|
||||
|
||||
### Проверка размера PDF
|
||||
```javascript
|
||||
const data = $('Code: Extract Base64 PDF').first().json;
|
||||
console.log('PDF size:', data.pdf_size_mb, 'MB');
|
||||
console.log('PDF size bytes:', data.pdf_size_bytes);
|
||||
```
|
||||
|
||||
## Обработка ошибок
|
||||
|
||||
Добавьте IF Node после HTTP Request для проверки успешности:
|
||||
|
||||
```javascript
|
||||
// IF Node: Check PDF Conversion Success
|
||||
{{ $json.success === true }}
|
||||
```
|
||||
|
||||
Если ошибка - отправьте уведомление или сохраните HTML для ручной конвертации.
|
||||
Reference in New Issue
Block a user