125 lines
4.8 KiB
Markdown
125 lines
4.8 KiB
Markdown
# dev-2026-04-21-schedule-ui.md
|
||
|
||
**Дата:** 2026-04-21
|
||
**Статус:** DONE
|
||
**ТЗ:** TZ-schedule-ui-enrichment.md
|
||
|
||
---
|
||
|
||
## Задача
|
||
|
||
Обогащение UI расписания данными из `flight_actual` и `mart.flights`:
|
||
- Новые колонки: ВПП, тип ВС, регистрация, длительность, взлёт/посадка факт
|
||
- Source badge для FR24-источников
|
||
- Track badge для RTL-SDR/FA треков
|
||
- Убрать дублирующийся столбец Трек и столбец Статус
|
||
|
||
---
|
||
|
||
## Выполненные изменения
|
||
|
||
### `main.py` — функция `schedule_data()`
|
||
|
||
1. **SQL переписан** с bare `FROM fr24_ext.schedule` на `FROM fr24_ext.schedule s`
|
||
с двумя LEFT JOIN:
|
||
- `LEFT JOIN fr24_ext.flight_actual fa ON fa.fr24_id = s.fr24_id AND s.fr24_id IS NOT NULL`
|
||
- `LEFT JOIN fr24_mart.flights mf ON mf.flight_number = s.flight_number AND mf.flight_date = s.flight_date`
|
||
|
||
2. **Добавлены новые SELECT поля:**
|
||
- `fa.runway_takeoff`, `fa.runway_landed`
|
||
- `fa.actual_distance`
|
||
- `fa.flight_time AS fa_flight_time`
|
||
- `fa.reg AS registration`
|
||
- `fa.operated_as`
|
||
- `fa.category AS fa_category`
|
||
- `mf.aircraft_type`
|
||
- `mf.track_source`, `mf.track_points`
|
||
- `s.source AS sched_source`
|
||
|
||
3. **Фикс ambiguity**: `_schedule_where()` генерирует WHERE без table-alias.
|
||
После JOIN столбцы `flight_date` и `flight_number` становятся неоднозначными
|
||
(есть в `flight_actual` и `mart.flights`).
|
||
Решение: в `schedule_data()` применяется `re.sub()` для подстановки `s.` prefix
|
||
перед этими колонками в safe_where строке.
|
||
|
||
4. **Новые поля в JSON-ответе:**
|
||
- `runway_takeoff`, `runway_landed`
|
||
- `actual_distance`
|
||
- `flight_time_min` (из fa_flight_time)
|
||
- `registration`
|
||
- `aircraft_type`
|
||
- `track_source`, `track_points`
|
||
- `sched_source`
|
||
- `duration_eff` = `fa_flight_time or duration_min`
|
||
|
||
---
|
||
|
||
### `schedule.html` — полная перепись
|
||
|
||
**Было:** 12 колонок, Трек дублировался в col 2 и col 12, был столбец Статус
|
||
**Стало:** 13 колонок согласно ТЗ:
|
||
|
||
| # | Колонка | Данные |
|
||
|---|---------|--------|
|
||
| 1 | Дата | flight_date |
|
||
| 2 | Рейс | flight_number + cat badge + source badge |
|
||
| 3 | Авиакомпания | airline + registration (мелко) |
|
||
| 4 | ↑↓ | direction icon |
|
||
| 5 | Маршрут | thread_title или origin → destination |
|
||
| 6 | Аэропорт | airport_iata |
|
||
| 7 | По расп. | scheduled_at (MSK) |
|
||
| 8 | Взлёт факт | actual_takeoff (MSK) + delay badge |
|
||
| 9 | Посадка факт | actual_landed (MSK) + delay badge |
|
||
| 10 | Длит. | duration_eff в формате "2ч 35м" |
|
||
| 11 | ВПП | runway_takeoff → runway_landed |
|
||
| 12 | ВС | aircraft_type |
|
||
| 13 | Трек | ✈ FR24 + 🛰 RTL-SDR + FA badge |
|
||
|
||
**Добавлен CSS:**
|
||
- `.src-badge` + `.src-fr24` для badge источника данных
|
||
|
||
---
|
||
|
||
### `schedule.js` — полная перепись
|
||
|
||
**Новые функции:**
|
||
- `fmtDuration(min)` — форматирует минуты как "2ч 35м" или "45м"
|
||
|
||
**`renderTable()` переписана:**
|
||
- 13 колонок вместо 12
|
||
- `actTakeoffCell`: actual_takeoff + delayCell(delay_takeoff_min)
|
||
- `actLandedCell`: actual_landed + delayCell(delay_landed_min)
|
||
- `airlineCell`: airline + `<small>registration</small>` под ней
|
||
- `srcBadge`: показывается если `sched_source === 'fr24'`
|
||
- `trackCol`: ✈ (если fr24_id) + 🛰 (если track_source=rtlsdr) + FA (если track_source=fa)
|
||
- `runway`: `runway_takeoff → runway_landed` или "—"
|
||
- `acType`: aircraft_type
|
||
- `durationCell`: fmtDuration(duration_eff)
|
||
|
||
**`renderCards()` обновлена** — добавлены строки:
|
||
- Взлёт факт + задержка
|
||
- Посадка факт + задержка
|
||
- Длительность
|
||
- ВПП
|
||
- ВС / Борт (aircraft_type / registration)
|
||
- Трек (✈ FR24, 🛰 RTL-SDR, FA)
|
||
|
||
**`delayCell()`** — убран возврат "—" для null (теперь возвращает пустую строку,
|
||
чтобы не засорять ячейки когда задержки нет)
|
||
|
||
**colspan** везде обновлён с 12 на 13 (setLoading, showError, empty state)
|
||
|
||
---
|
||
|
||
## Деплой
|
||
|
||
Файлы нужно скопировать на VM в контейнер `fr24-api`:
|
||
```
|
||
/home/fr24/projects/fr24/frontend/main.py
|
||
/home/fr24/projects/fr24/frontend/static/schedule.html
|
||
/home/fr24/projects/fr24/frontend/static/schedule.js
|
||
```
|
||
После: `docker restart fr24-api`
|
||
|
||
---
|