Привязка данных LyngSat

This commit is contained in:
2025-11-11 22:40:52 +03:00
parent a3c381b9c7
commit 5e94086bf0
9 changed files with 455 additions and 36 deletions

View File

@@ -184,6 +184,27 @@
</div>
</div>
</div>
<!-- Link LyngSat Sources Card -->
<div class="col-lg-6">
<div class="card h-100 shadow-sm border-0">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<div class="bg-primary bg-opacity-10 rounded-circle p-2 me-3">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-link-45deg text-primary" viewBox="0 0 16 16">
<path d="M4.715 6.542 3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1.002 1.002 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4.018 4.018 0 0 1-.128-1.287z"/>
<path d="M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 1 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 1 0-4.243-4.243z"/>
</svg>
</div>
<h3 class="card-title mb-0">Привязка источников LyngSat</h3>
</div>
<p class="card-text">Автоматическая привязка источников из базы LyngSat к объектам по частоте и поляризации. Объекты с привязанными источниками отображаются как "ТВ".</p>
<a href="{% url 'mainapp:link_lyngsat' %}" class="btn btn-primary">
Привязать источники
</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,90 @@
{% extends 'mainapp/base.html' %}
{% block title %}Привязка источников LyngSat{% endblock %}
{% block content %}
<div class="container mt-4">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow-sm">
<div class="card-header bg-primary text-white">
<h3 class="mb-0">
<i class="bi bi-link-45deg"></i> Привязка источников LyngSat к объектам
</h3>
</div>
<div class="card-body">
<!-- Alert messages -->
{% include 'mainapp/components/_messages.html' %}
<div class="alert alert-info" role="alert">
<i class="bi bi-info-circle"></i>
<strong>Информация:</strong> Эта функция автоматически привязывает источники из базы LyngSat к объектам
на основе совпадения частоты (с округлением) и поляризации. Объекты с привязанными источниками LyngSat
будут отмечены как "ТВ" в списке объектов.
</div>
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
<div class="mb-4">
<label for="{{ form.satellites.id_for_label }}" class="form-label">
{{ form.satellites.label }}
</label>
{{ form.satellites }}
{% if form.satellites.help_text %}
<div class="form-text">{{ form.satellites.help_text }}</div>
{% endif %}
{% if form.satellites.errors %}
<div class="invalid-feedback d-block">
{{ form.satellites.errors }}
</div>
{% endif %}
</div>
<div class="mb-4">
<label for="{{ form.frequency_tolerance.id_for_label }}" class="form-label">
{{ form.frequency_tolerance.label }}
</label>
{{ form.frequency_tolerance }}
{% if form.frequency_tolerance.help_text %}
<div class="form-text">{{ form.frequency_tolerance.help_text }}</div>
{% endif %}
{% if form.frequency_tolerance.errors %}
<div class="invalid-feedback d-block">
{{ form.frequency_tolerance.errors }}
</div>
{% endif %}
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary btn-lg">
<i class="bi bi-link-45deg"></i> Привязать источники
</button>
<a href="{% url 'mainapp:actions' %}" class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> Назад к действиям
</a>
</div>
</form>
</div>
</div>
<!-- Help section -->
<div class="card mt-4 shadow-sm">
<div class="card-header bg-light">
<h5 class="mb-0">
<i class="bi bi-question-circle"></i> Как это работает?
</h5>
</div>
<div class="card-body">
<ol class="mb-0">
<li>Система округляет частоту каждого объекта до целого числа</li>
<li>Ищет источники LyngSat с той же поляризацией и близкой частотой (в пределах допуска)</li>
<li>При нахождении совпадения создается связь между объектом и источником LyngSat</li>
<li>Объекты с привязанными источниками отображаются как "ТВ" в списке</li>
</ol>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -251,6 +251,12 @@
onchange="toggleColumn(this)"> Стандарт
</label>
</li>
<li>
<label class="dropdown-item">
<input type="checkbox" class="column-toggle" data-column="24" checked
onchange="toggleColumn(this)"> Тип источника
</label>
</li>
</ul>
</div>
@@ -463,6 +469,7 @@
{% include 'mainapp/components/_table_header.html' with label="Комментарий" field="" sortable=False %}
{% include 'mainapp/components/_table_header.html' with label="Усреднённое" field="" sortable=False %}
{% include 'mainapp/components/_table_header.html' with label="Стандарт" field="standard" sort=sort %}
{% include 'mainapp/components/_table_header.html' with label="Тип источника" field="" sortable=False %}
</tr>
</thead>
<tbody>
@@ -495,10 +502,19 @@
<td>{{ item.comment }}</td>
<td>{{ item.is_average }}</td>
<td>{{ item.standard }}</td>
<td>
{% if item.obj.lyngsat_source %}
<a href="#" class="text-primary text-decoration-none" onclick="showLyngsatModal({{ item.obj.lyngsat_source.id }}); return false;">
<i class="bi bi-tv"></i> ТВ
</a>
{% else %}
-
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="22" class="text-center py-4">
<td colspan="25" class="text-center py-4">
{% if selected_satellite_id %}
Нет данных для выбранных фильтров
{% else %}
@@ -1165,4 +1181,160 @@
<!-- Include the selected items offcanvas component -->
{% include 'mainapp/components/_selected_items_offcanvas.html' %}
<!-- LyngSat Data Modal -->
<div class="modal fade" id="lyngsatModal" tabindex="-1" aria-labelledby="lyngsatModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" id="lyngsatModalLabel">
<i class="bi bi-tv"></i> Данные источника LyngSat
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Закрыть"></button>
</div>
<div class="modal-body" id="lyngsatModalBody">
<div class="text-center py-4">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Загрузка...</span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
</div>
</div>
</div>
</div>
<script>
function showLyngsatModal(lyngsatId) {
// Показываем модальное окно
const modal = new bootstrap.Modal(document.getElementById('lyngsatModal'));
modal.show();
// Показываем индикатор загрузки
const modalBody = document.getElementById('lyngsatModalBody');
modalBody.innerHTML = `
<div class="text-center py-4">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Загрузка...</span>
</div>
</div>
`;
// Загружаем данные
fetch(`/api/lyngsat/${lyngsatId}/`)
.then(response => {
if (!response.ok) {
throw new Error('Ошибка загрузки данных');
}
return response.json();
})
.then(data => {
// Формируем HTML с данными
let html = `
<div class="container-fluid">
<div class="row g-3">
<div class="col-md-6">
<div class="card h-100">
<div class="card-header bg-light">
<strong><i class="bi bi-info-circle"></i> Основная информация</strong>
</div>
<div class="card-body">
<table class="table table-sm table-borderless mb-0">
<tbody>
<tr>
<td class="text-muted" style="width: 40%;">Спутник:</td>
<td><strong>${data.satellite}</strong></td>
</tr>
<tr>
<td class="text-muted">Частота:</td>
<td><strong>${data.frequency} МГц</strong></td>
</tr>
<tr>
<td class="text-muted">Поляризация:</td>
<td><span class="badge bg-info">${data.polarization}</span></td>
</tr>
<tr>
<td class="text-muted">Канал:</td>
<td>${data.channel_info}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<div class="card-header bg-light">
<strong><i class="bi bi-gear"></i> Технические параметры</strong>
</div>
<div class="card-body">
<table class="table table-sm table-borderless mb-0">
<tbody>
<tr>
<td class="text-muted" style="width: 40%;">Модуляция:</td>
<td><span class="badge bg-secondary">${data.modulation}</span></td>
</tr>
<tr>
<td class="text-muted">Стандарт:</td>
<td><span class="badge bg-secondary">${data.standard}</span></td>
</tr>
<tr>
<td class="text-muted">Сим. скорость:</td>
<td><strong>${data.sym_velocity} БОД</strong></td>
</tr>
<tr>
<td class="text-muted">FEC:</td>
<td>${data.fec}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-12">
<div class="card">
<div class="card-header bg-light">
<strong><i class="bi bi-clock-history"></i> Дополнительная информация</strong>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<p class="mb-2">
<span class="text-muted">Последнее обновление:</span><br>
<strong>${data.last_update}</strong>
</p>
</div>
<div class="col-md-6">
${data.url ? `
<p class="mb-2">
<span class="text-muted">Ссылка на источник:</span><br>
<a href="${data.url}" target="_blank" class="btn btn-sm btn-outline-primary">
<i class="bi bi-link-45deg"></i> Открыть на LyngSat
</a>
</p>
` : ''}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
modalBody.innerHTML = html;
})
.catch(error => {
modalBody.innerHTML = `
<div class="alert alert-danger" role="alert">
<i class="bi bi-exclamation-triangle"></i> ${error.message}
</div>
`;
});
}
</script>
{% endblock %}