Исправил отображения объектов в источниках
This commit is contained in:
@@ -205,6 +205,28 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Unlink All 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-warning 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-unlink text-warning" viewBox="0 0 16 16">
|
||||
<path d="M6.354 5.5H4a3 3 0 0 0 0 6h3a3 3 0 0 0 2.83-4H9q-.13 0-.25.031A2 2 0 0 1 7 10.5H4a2 2 0 1 1 0-4h1.535c.218-.376.495-.714.82-1z"/>
|
||||
<path d="M9 5.5a3 3 0 0 0-2.83 4h1.098A2 2 0 0 1 9 6.5h3a2 2 0 1 1 0 4h-1.535a4 4 0 0 1-.82 1H12a3 3 0 1 0 0-6z"/>
|
||||
<path d="M1 1l14 14"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="card-title mb-0">Отвязка всех источников LyngSat</h3>
|
||||
</div>
|
||||
<p class="card-text">Отвязать все источники LyngSat от объектов. Все объекты перестанут отображаться как "ТВ" источники. Операция обратима через повторную привязку.</p>
|
||||
<a href="{% url 'mainapp:unlink_all_lyngsat' %}" class="btn btn-warning">
|
||||
Отвязать все источники
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -16,9 +16,15 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'mainapp:objitem_list' %}">Объекты</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'mainapp:home' %}">Источники</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'mainapp:transponder_list' %}">Транспондеры</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'lyngsatapp:lyngsat_list' %}">LyngSat</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'mainapp:actions' %}">Действия</a>
|
||||
</li>
|
||||
|
||||
@@ -192,6 +192,23 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LyngSat Filter -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Тип источника (ТВ):</label>
|
||||
<div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" name="has_lyngsat" id="has_lyngsat_1"
|
||||
value="1" {% if has_lyngsat == '1' %}checked{% endif %}>
|
||||
<label class="form-check-label" for="has_lyngsat_1">Есть</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" name="has_lyngsat" id="has_lyngsat_0"
|
||||
value="0" {% if has_lyngsat == '0' %}checked{% endif %}>
|
||||
<label class="form-check-label" for="has_lyngsat_0">Нет</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Point Count Filter -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Количество точек:</label>
|
||||
@@ -246,6 +263,9 @@
|
||||
<th scope="col" style="min-width: 150px;">Координаты Кубсата</th>
|
||||
<th scope="col" style="min-width: 150px;">Координаты оперативников</th>
|
||||
<th scope="col" style="min-width: 150px;">Координаты справочные</th>
|
||||
{% if has_any_lyngsat %}
|
||||
<th scope="col" class="text-center" style="min-width: 80px;">Тип источника</th>
|
||||
{% endif %}
|
||||
<th scope="col" class="text-center" style="min-width: 100px;">
|
||||
<a href="javascript:void(0)" onclick="updateSort('objitem_count')" class="text-white text-decoration-none">
|
||||
Кол-во точек
|
||||
@@ -292,6 +312,18 @@
|
||||
<td>{{ source.coords_kupsat }}</td>
|
||||
<td>{{ source.coords_valid }}</td>
|
||||
<td>{{ source.coords_reference }}</td>
|
||||
{% if has_any_lyngsat %}
|
||||
<td class="text-center">
|
||||
{% if source.has_lyngsat %}
|
||||
<a href="#" class="text-primary text-decoration-none"
|
||||
onclick="showLyngsatModal({{ source.lyngsat_id }}); return false;">
|
||||
<i class="bi bi-tv"></i> ТВ
|
||||
</a>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="text-center">{{ source.objitem_count }}</td>
|
||||
<td>{{ source.created_at|date:"d.m.Y H:i" }}</td>
|
||||
<td>{{ source.updated_at|date:"d.m.Y H:i" }}</td>
|
||||
@@ -360,7 +392,7 @@
|
||||
|
||||
<!-- Modal for Source Details -->
|
||||
<div class="modal fade" id="sourceDetailsModal" tabindex="-1" aria-labelledby="sourceDetailsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl">
|
||||
<div class="modal-dialog modal-fullscreen">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="sourceDetailsModalLabel">Детали источника #<span id="modalSourceId"></span></h5>
|
||||
@@ -374,26 +406,77 @@
|
||||
</div>
|
||||
<div id="modalErrorMessage" class="alert alert-danger" style="display: none;"></div>
|
||||
<div id="modalContent" style="display: none;">
|
||||
<h6>Связанные точки (<span id="objitemCount">0</span>):</h6>
|
||||
<div class="table-responsive" style="max-height: 60vh; overflow-y: auto;">
|
||||
<table class="table table-striped table-hover table-sm">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h6 class="mb-0">Связанные точки (<span id="objitemCount">0</span>):</h6>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle"
|
||||
id="modalColumnVisibilityDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-gear"></i> Колонки
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="modalColumnVisibilityDropdown" style="max-height: 400px; overflow-y: auto;">
|
||||
<li>
|
||||
<label class="dropdown-item">
|
||||
<input type="checkbox" id="modal-select-all-columns" onchange="toggleAllModalColumns(this)"> Выбрать всё
|
||||
</label>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="0" checked onchange="toggleModalColumn(this)"> Выбрать</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="1" checked onchange="toggleModalColumn(this)"> ID</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="2" checked onchange="toggleModalColumn(this)"> Имя</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="3" checked onchange="toggleModalColumn(this)"> Спутник</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="4" checked onchange="toggleModalColumn(this)"> Транспондер</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="5" checked onchange="toggleModalColumn(this)"> Частота, МГц</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="6" checked onchange="toggleModalColumn(this)"> Полоса, МГц</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="7" checked onchange="toggleModalColumn(this)"> Поляризация</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="8" checked onchange="toggleModalColumn(this)"> Сим. V</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="9" checked onchange="toggleModalColumn(this)"> Модул</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="10" checked onchange="toggleModalColumn(this)"> ОСШ</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="11" checked onchange="toggleModalColumn(this)"> Время ГЛ</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="12" checked onchange="toggleModalColumn(this)"> Местоположение</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="13" checked onchange="toggleModalColumn(this)"> Геолокация</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="14" checked onchange="toggleModalColumn(this)"> Обновлено</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="15" checked onchange="toggleModalColumn(this)"> Кем(обн)</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="16" onchange="toggleModalColumn(this)"> Создано</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="17" onchange="toggleModalColumn(this)"> Кем(созд)</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="18" onchange="toggleModalColumn(this)"> Комментарий</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="19" onchange="toggleModalColumn(this)"> Усреднённое</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="20" onchange="toggleModalColumn(this)"> Стандарт</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="21" checked onchange="toggleModalColumn(this)"> Тип источника</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="22" onchange="toggleModalColumn(this)"> Sigma</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="modal-column-toggle" data-column="23" checked onchange="toggleModalColumn(this)"> Зеркала</label></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive" style="max-height: 80vh; overflow-y: auto;">
|
||||
<table class="table table-striped table-hover table-sm" style="font-size: 0.85rem;">
|
||||
<thead class="table-light sticky-top">
|
||||
<tr>
|
||||
<th class="text-center" style="width: 3%;">
|
||||
<input type="checkbox" id="modal-select-all" class="form-check-input">
|
||||
</th>
|
||||
<th class="text-center" style="min-width: 60px;">ID</th>
|
||||
<th>Имя</th>
|
||||
<th>Спутник</th>
|
||||
<th>Частота, МГц</th>
|
||||
<th>Полоса, МГц</th>
|
||||
<th>Поляризация</th>
|
||||
<th>Сим. скорость, БОД</th>
|
||||
<th>Модуляция</th>
|
||||
<th>ОСШ</th>
|
||||
<th>Время ГЛ</th>
|
||||
<th>Местоположение</th>
|
||||
<th>Координаты ГЛ</th>
|
||||
<th style="min-width: 120px;">Имя</th>
|
||||
<th style="min-width: 120px;">Спутник</th>
|
||||
<th style="min-width: 100px;">Транспондер</th>
|
||||
<th style="min-width: 100px;">Частота, МГц</th>
|
||||
<th style="min-width: 100px;">Полоса, МГц</th>
|
||||
<th style="min-width: 100px;">Поляризация</th>
|
||||
<th style="min-width: 100px;">Сим. V</th>
|
||||
<th style="min-width: 100px;">Модул</th>
|
||||
<th style="min-width: 80px;">ОСШ</th>
|
||||
<th style="min-width: 120px;">Время ГЛ</th>
|
||||
<th style="min-width: 120px;">Местоположение</th>
|
||||
<th style="min-width: 120px;">Геолокация</th>
|
||||
<th style="min-width: 120px;">Обновлено</th>
|
||||
<th style="min-width: 100px;">Кем(обн)</th>
|
||||
<th style="min-width: 120px;">Создано</th>
|
||||
<th style="min-width: 100px;">Кем(созд)</th>
|
||||
<th style="min-width: 150px;">Комментарий</th>
|
||||
<th style="min-width: 100px;">Усреднённое</th>
|
||||
<th style="min-width: 100px;">Стандарт</th>
|
||||
<th style="min-width: 100px;">Тип источника</th>
|
||||
<th style="min-width: 80px;">Sigma</th>
|
||||
<th style="min-width: 80px;">Зеркала</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="objitemTableBody">
|
||||
@@ -639,6 +722,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
setupRadioLikeCheckboxes('has_coords_kupsat');
|
||||
setupRadioLikeCheckboxes('has_coords_valid');
|
||||
setupRadioLikeCheckboxes('has_coords_reference');
|
||||
setupRadioLikeCheckboxes('has_lyngsat');
|
||||
|
||||
// Update filter counter on page load
|
||||
updateFilterCounter();
|
||||
@@ -686,7 +770,7 @@ function showSourceDetails(sourceId) {
|
||||
modal.show();
|
||||
|
||||
// Fetch data from API
|
||||
fetch(`/api/source/${sourceId}/objitems/`)
|
||||
fetch('/api/source/' + sourceId + '/objitems/')
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
@@ -712,28 +796,70 @@ function showSourceDetails(sourceId) {
|
||||
|
||||
data.objitems.forEach(objitem => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td class="text-center">
|
||||
<input type="checkbox" class="form-check-input modal-item-checkbox" value="${objitem.id}">
|
||||
</td>
|
||||
<td class="text-center">${objitem.id}</td>
|
||||
<td>${objitem.name}</td>
|
||||
<td>${objitem.satellite_name}</td>
|
||||
<td>${objitem.frequency}</td>
|
||||
<td>${objitem.freq_range}</td>
|
||||
<td>${objitem.polarization}</td>
|
||||
<td>${objitem.bod_velocity}</td>
|
||||
<td>${objitem.modulation}</td>
|
||||
<td>${objitem.snr}</td>
|
||||
<td>${objitem.geo_timestamp}</td>
|
||||
<td>${objitem.geo_location}</td>
|
||||
<td>${objitem.geo_coords}</td>
|
||||
`;
|
||||
|
||||
// Build transponder cell
|
||||
let transponderCell = '-';
|
||||
if (objitem.has_transponder) {
|
||||
transponderCell = '<a href="#" class="text-success text-decoration-none" ' +
|
||||
'onclick="showTransponderModal(' + objitem.transponder_id + '); return false;" ' +
|
||||
'title="Показать данные транспондера">' +
|
||||
'<i class="bi bi-broadcast"></i> ' + objitem.transponder_info +
|
||||
'</a>';
|
||||
}
|
||||
|
||||
// Build LyngSat cell
|
||||
let lyngsatCell = '-';
|
||||
if (objitem.has_lyngsat) {
|
||||
lyngsatCell = '<a href="#" class="text-primary text-decoration-none" ' +
|
||||
'onclick="showLyngsatModal(' + objitem.lyngsat_id + '); return false;">' +
|
||||
'<i class="bi bi-tv"></i> ТВ' +
|
||||
'</a>';
|
||||
}
|
||||
|
||||
// Build Sigma cell
|
||||
let sigmaCell = '-';
|
||||
if (objitem.has_sigma) {
|
||||
sigmaCell = '<a href="#" class="text-info text-decoration-none" ' +
|
||||
'onclick="showSigmaParameterModal(' + objitem.parameter_id + '); return false;" ' +
|
||||
'title="' + objitem.sigma_info + '">' +
|
||||
'<i class="bi bi-graph-up"></i> ' + objitem.sigma_info +
|
||||
'</a>';
|
||||
}
|
||||
|
||||
row.innerHTML = '<td class="text-center">' +
|
||||
'<input type="checkbox" class="form-check-input modal-item-checkbox" value="' + objitem.id + '">' +
|
||||
'</td>' +
|
||||
'<td class="text-center">' + objitem.id + '</td>' +
|
||||
'<td>' + objitem.name + '</td>' +
|
||||
'<td>' + objitem.satellite_name + '</td>' +
|
||||
'<td>' + transponderCell + '</td>' +
|
||||
'<td>' + objitem.frequency + '</td>' +
|
||||
'<td>' + objitem.freq_range + '</td>' +
|
||||
'<td>' + objitem.polarization + '</td>' +
|
||||
'<td>' + objitem.bod_velocity + '</td>' +
|
||||
'<td>' + objitem.modulation + '</td>' +
|
||||
'<td>' + objitem.snr + '</td>' +
|
||||
'<td>' + objitem.geo_timestamp + '</td>' +
|
||||
'<td>' + objitem.geo_location + '</td>' +
|
||||
'<td>' + objitem.geo_coords + '</td>' +
|
||||
'<td>' + objitem.updated_at + '</td>' +
|
||||
'<td>' + objitem.updated_by + '</td>' +
|
||||
'<td>' + objitem.created_at + '</td>' +
|
||||
'<td>' + objitem.created_by + '</td>' +
|
||||
'<td>' + objitem.comment + '</td>' +
|
||||
'<td>' + objitem.is_average + '</td>' +
|
||||
'<td>' + objitem.standard + '</td>' +
|
||||
'<td>' + lyngsatCell + '</td>' +
|
||||
'<td>' + sigmaCell + '</td>' +
|
||||
'<td>' + objitem.mirrors + '</td>';
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
|
||||
// Setup modal select-all checkbox
|
||||
setupModalSelectAll();
|
||||
|
||||
// Initialize column visibility
|
||||
initModalColumnVisibility();
|
||||
} else {
|
||||
// Show no data message
|
||||
document.getElementById('modalNoData').style.display = 'block';
|
||||
@@ -776,5 +902,196 @@ function setupModalSelectAll() {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Function to toggle modal column visibility
|
||||
function toggleModalColumn(checkbox) {
|
||||
const columnIndex = parseInt(checkbox.getAttribute('data-column'));
|
||||
const modal = document.getElementById('sourceDetailsModal');
|
||||
const table = modal.querySelector('.table');
|
||||
if (!table) return;
|
||||
|
||||
const cells = table.querySelectorAll('td:nth-child(' + (columnIndex + 1) + '), th:nth-child(' + (columnIndex + 1) + ')');
|
||||
|
||||
if (checkbox.checked) {
|
||||
cells.forEach(cell => {
|
||||
cell.style.display = '';
|
||||
});
|
||||
} else {
|
||||
cells.forEach(cell => {
|
||||
cell.style.display = 'none';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Function to toggle all modal columns
|
||||
function toggleAllModalColumns(selectAllCheckbox) {
|
||||
const columnCheckboxes = document.querySelectorAll('.modal-column-toggle');
|
||||
columnCheckboxes.forEach(checkbox => {
|
||||
checkbox.checked = selectAllCheckbox.checked;
|
||||
toggleModalColumn(checkbox);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize modal column visibility
|
||||
function initModalColumnVisibility() {
|
||||
// Hide columns by default: Создано (16), Кем(созд) (17), Комментарий (18), Усреднённое (19), Стандарт (20), Sigma (22)
|
||||
const columnsToHide = [16, 17, 18, 19, 20, 22];
|
||||
columnsToHide.forEach(columnIndex => {
|
||||
const checkbox = document.querySelector('.modal-column-toggle[data-column="' + columnIndex + '"]');
|
||||
if (checkbox && !checkbox.checked) {
|
||||
toggleModalColumn(checkbox);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Function to show LyngSat modal
|
||||
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 => {
|
||||
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>';
|
||||
});
|
||||
}
|
||||
|
||||
// Function to show transponder modal
|
||||
function showTransponderModal(transponderId) {
|
||||
const modal = new bootstrap.Modal(document.getElementById('transponderModal'));
|
||||
modal.show();
|
||||
|
||||
const modalBody = document.getElementById('transponderModalBody');
|
||||
modalBody.innerHTML = '<div class="text-center py-4"><div class="spinner-border text-success" role="status"><span class="visually-hidden">Загрузка...</span></div></div>';
|
||||
|
||||
fetch('/api/transponder/' + transponderId + '/')
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Ошибка загрузки данных транспондера');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
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.name || '-') + '</strong></td></tr>' +
|
||||
'<tr><td class="text-muted">Спутник:</td><td><strong>' + data.satellite + '</strong></td></tr>' +
|
||||
'<tr><td class="text-muted">Зона покрытия:</td><td>' + (data.zone_name || '-') + '</td></tr>' +
|
||||
'<tr><td class="text-muted">Поляризация:</td><td><span class="badge bg-info">' + data.polarization + '</span></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-broadcast"></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%;">Downlink:</td><td><strong>' + data.downlink + ' МГц</strong></td></tr>' +
|
||||
'<tr><td class="text-muted">Uplink:</td><td><strong>' + (data.uplink || '-') + (data.uplink ? ' МГц' : '') + '</strong></td></tr>' +
|
||||
'<tr><td class="text-muted">Полоса:</td><td><strong>' + data.frequency_range + ' МГц</strong></td></tr>' +
|
||||
'<tr><td class="text-muted">Перенос:</td><td>' + (data.transfer || '-') + (data.transfer ? ' МГц' : '') + '</td></tr>' +
|
||||
'<tr><td class="text-muted">ОСШ:</td><td><strong>' + (data.snr || '-') + (data.snr ? ' дБ' : '') + '</strong></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.created_at || '-') + '</strong></p></div>' +
|
||||
'<div class="col-md-6"><p class="mb-2"><span class="text-muted">Создан пользователем:</span><br><strong>' + (data.created_by || '-') + '</strong></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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- Transponder Data Modal -->
|
||||
<div class="modal fade" id="transponderModal" tabindex="-1" aria-labelledby="transponderModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-success text-white">
|
||||
<h5 class="modal-title" id="transponderModalLabel">
|
||||
<i class="bi bi-broadcast"></i> Данные транспондера
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="transponderModalBody">
|
||||
<div class="text-center py-4">
|
||||
<div class="spinner-border text-success" 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>
|
||||
|
||||
<!-- Include the sigma parameter modal component -->
|
||||
{% include 'mainapp/components/_sigma_parameter_modal.html' %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
79
dbapp/mainapp/templates/mainapp/unlink_lyngsat_confirm.html
Normal file
79
dbapp/mainapp/templates/mainapp/unlink_lyngsat_confirm.html
Normal file
@@ -0,0 +1,79 @@
|
||||
{% extends 'mainapp/base.html' %}
|
||||
|
||||
{% block title %}Подтверждение отвязки LyngSat{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center mt-5">
|
||||
<div class="col-md-8">
|
||||
<div class="card shadow">
|
||||
<div class="card-header bg-warning text-dark">
|
||||
<h4 class="mb-0">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
Подтверждение отвязки источников LyngSat
|
||||
</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<h5 class="alert-heading">
|
||||
<i class="bi bi-info-circle-fill me-2"></i>
|
||||
Внимание!
|
||||
</h5>
|
||||
<p class="mb-0">
|
||||
Вы собираетесь отвязать <strong>все</strong> источники LyngSat от объектов.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h5>Информация:</h5>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Объектов с привязанными источниками LyngSat:
|
||||
<span class="badge bg-primary rounded-pill">{{ linked_count }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% if linked_count > 0 %}
|
||||
<div class="alert alert-info" role="alert">
|
||||
<p class="mb-0">
|
||||
<i class="bi bi-lightbulb-fill me-2"></i>
|
||||
После отвязки все объекты перестанут отображаться как "ТВ" источники.
|
||||
Вы сможете заново привязать источники через форму привязки LyngSat.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-between">
|
||||
<a href="{% url 'mainapp:actions' %}" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>
|
||||
Отмена
|
||||
</a>
|
||||
<button type="submit" class="btn btn-warning">
|
||||
<i class="bi bi-unlink me-1"></i>
|
||||
Отвязать все источники ({{ linked_count }})
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="alert alert-success" role="alert">
|
||||
<p class="mb-0">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>
|
||||
Нет объектов с привязанными источниками LyngSat. Отвязка не требуется.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="d-grid">
|
||||
<a href="{% url 'mainapp:actions' %}" class="btn btn-primary">
|
||||
<i class="bi bi-arrow-left me-1"></i>
|
||||
Вернуться к действиям
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -39,6 +39,7 @@ from .views import (
|
||||
TransponderListView,
|
||||
TransponderCreateView,
|
||||
TransponderUpdateView,
|
||||
UnlinkAllLyngsatSourcesView,
|
||||
UploadVchLoadView,
|
||||
custom_logout,
|
||||
)
|
||||
@@ -85,5 +86,6 @@ urlpatterns = [
|
||||
path('lyngsat-task-status/<str:task_id>/', LyngsatTaskStatusView.as_view(), name='lyngsat_task_status'),
|
||||
path('api/lyngsat-task-status/<str:task_id>/', LyngsatTaskStatusAPIView.as_view(), name='lyngsat_task_status_api'),
|
||||
path('clear-lyngsat-cache/', ClearLyngsatCacheView.as_view(), name='clear_lyngsat_cache'),
|
||||
path('unlink-all-lyngsat/', UnlinkAllLyngsatSourcesView.as_view(), name='unlink_all_lyngsat'),
|
||||
path('logout/', custom_logout, name='logout'),
|
||||
]
|
||||
@@ -30,6 +30,7 @@ from .lyngsat import (
|
||||
FillLyngsatDataView,
|
||||
LyngsatTaskStatusView,
|
||||
ClearLyngsatCacheView,
|
||||
UnlinkAllLyngsatSourcesView,
|
||||
)
|
||||
from .source import SourceListView, SourceUpdateView, SourceDeleteView, DeleteSelectedSourcesView
|
||||
from .transponder import (
|
||||
@@ -78,6 +79,7 @@ __all__ = [
|
||||
'FillLyngsatDataView',
|
||||
'LyngsatTaskStatusView',
|
||||
'ClearLyngsatCacheView',
|
||||
'UnlinkAllLyngsatSourcesView',
|
||||
# Source
|
||||
'SourceListView',
|
||||
'SourceUpdateView',
|
||||
|
||||
@@ -186,7 +186,13 @@ class SourceObjItemsAPIView(LoginRequiredMixin, View):
|
||||
'source_objitems__parameter_obj__id_satellite',
|
||||
'source_objitems__parameter_obj__polarization',
|
||||
'source_objitems__parameter_obj__modulation',
|
||||
'source_objitems__geo_obj'
|
||||
'source_objitems__parameter_obj__standard',
|
||||
'source_objitems__geo_obj',
|
||||
'source_objitems__geo_obj__mirrors',
|
||||
'source_objitems__lyngsat_source',
|
||||
'source_objitems__transponder',
|
||||
'source_objitems__created_by__user',
|
||||
'source_objitems__updated_by__user'
|
||||
).get(id=source_id)
|
||||
|
||||
# Get all related ObjItems, sorted by created_at
|
||||
@@ -202,9 +208,12 @@ class SourceObjItemsAPIView(LoginRequiredMixin, View):
|
||||
polarization = '-'
|
||||
bod_velocity = '-'
|
||||
modulation = '-'
|
||||
standard = '-'
|
||||
snr = '-'
|
||||
parameter_id = None
|
||||
|
||||
if param:
|
||||
parameter_id = param.id
|
||||
if hasattr(param, 'id_satellite') and param.id_satellite:
|
||||
satellite_name = param.id_satellite.name
|
||||
frequency = f"{param.frequency:.3f}" if param.frequency is not None else '-'
|
||||
@@ -214,6 +223,8 @@ class SourceObjItemsAPIView(LoginRequiredMixin, View):
|
||||
bod_velocity = f"{param.bod_velocity:.0f}" if param.bod_velocity is not None else '-'
|
||||
if hasattr(param, 'modulation') and param.modulation:
|
||||
modulation = param.modulation.name
|
||||
if hasattr(param, 'standard') and param.standard:
|
||||
standard = param.standard.name
|
||||
snr = f"{param.snr:.0f}" if param.snr is not None else '-'
|
||||
|
||||
# Get geo data
|
||||
@@ -235,6 +246,56 @@ class SourceObjItemsAPIView(LoginRequiredMixin, View):
|
||||
lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
|
||||
geo_coords = f"{lat} {lon}"
|
||||
|
||||
# Get created/updated info
|
||||
created_at = '-'
|
||||
if objitem.created_at:
|
||||
local_time = timezone.localtime(objitem.created_at)
|
||||
created_at = local_time.strftime("%d.%m.%Y %H:%M")
|
||||
|
||||
updated_at = '-'
|
||||
if objitem.updated_at:
|
||||
local_time = timezone.localtime(objitem.updated_at)
|
||||
updated_at = local_time.strftime("%d.%m.%Y %H:%M")
|
||||
|
||||
created_by = str(objitem.created_by) if objitem.created_by else '-'
|
||||
updated_by = str(objitem.updated_by) if objitem.updated_by else '-'
|
||||
|
||||
# Check for LyngSat
|
||||
has_lyngsat = hasattr(objitem, 'lyngsat_source') and objitem.lyngsat_source is not None
|
||||
lyngsat_id = objitem.lyngsat_source.id if has_lyngsat else None
|
||||
|
||||
# Check for Transponder
|
||||
has_transponder = hasattr(objitem, 'transponder') and objitem.transponder is not None
|
||||
transponder_id = objitem.transponder.id if has_transponder else None
|
||||
transponder_info = '-'
|
||||
if has_transponder:
|
||||
try:
|
||||
downlink = objitem.transponder.downlink if objitem.transponder.downlink else '-'
|
||||
freq_range_t = objitem.transponder.frequency_range if objitem.transponder.frequency_range else '-'
|
||||
transponder_info = f"{downlink}:{freq_range_t}"
|
||||
except Exception:
|
||||
transponder_info = '-'
|
||||
|
||||
# Check for Sigma
|
||||
has_sigma = False
|
||||
sigma_info = '-'
|
||||
if param and hasattr(param, 'sigma_parameter'):
|
||||
sigma_count = param.sigma_parameter.count()
|
||||
if sigma_count > 0:
|
||||
has_sigma = True
|
||||
sigma_info = f"{sigma_count}"
|
||||
|
||||
# Get comment, is_average, and mirrors from geo_obj
|
||||
comment = '-'
|
||||
is_average = '-'
|
||||
mirrors = '-'
|
||||
if hasattr(objitem, 'geo_obj') and objitem.geo_obj:
|
||||
comment = objitem.geo_obj.comment or '-'
|
||||
is_average = 'Да' if objitem.geo_obj.is_average else 'Нет'
|
||||
# Get mirrors list
|
||||
mirrors_list = list(objitem.geo_obj.mirrors.values_list('name', flat=True))
|
||||
mirrors = ', '.join(mirrors_list) if mirrors_list else '-'
|
||||
|
||||
objitems_data.append({
|
||||
'id': objitem.id,
|
||||
'name': objitem.name or '-',
|
||||
@@ -244,10 +305,26 @@ class SourceObjItemsAPIView(LoginRequiredMixin, View):
|
||||
'polarization': polarization,
|
||||
'bod_velocity': bod_velocity,
|
||||
'modulation': modulation,
|
||||
'standard': standard,
|
||||
'snr': snr,
|
||||
'geo_timestamp': geo_timestamp,
|
||||
'geo_location': geo_location,
|
||||
'geo_coords': geo_coords
|
||||
'geo_coords': geo_coords,
|
||||
'created_at': created_at,
|
||||
'updated_at': updated_at,
|
||||
'created_by': created_by,
|
||||
'updated_by': updated_by,
|
||||
'comment': comment,
|
||||
'is_average': is_average,
|
||||
'has_lyngsat': has_lyngsat,
|
||||
'lyngsat_id': lyngsat_id,
|
||||
'has_transponder': has_transponder,
|
||||
'transponder_id': transponder_id,
|
||||
'transponder_info': transponder_info,
|
||||
'has_sigma': has_sigma,
|
||||
'sigma_info': sigma_info,
|
||||
'parameter_id': parameter_id,
|
||||
'mirrors': mirrors,
|
||||
})
|
||||
|
||||
return JsonResponse({
|
||||
|
||||
@@ -46,22 +46,30 @@ class LinkLyngsatSourcesView(LoginRequiredMixin, FormMessageMixin, FormView):
|
||||
|
||||
param = objitem.parameter_obj
|
||||
|
||||
# Round object frequency
|
||||
# Round object frequency to 1 decimal place
|
||||
if param.frequency:
|
||||
rounded_freq = round(param.frequency, 0) # Round to integer
|
||||
rounded_freq = round(param.frequency, 1) # Round to 1 decimal place
|
||||
|
||||
# Find matching LyngSat source
|
||||
# Compare by rounded frequency and polarization
|
||||
# Compare by rounded frequency (with tolerance) and polarization
|
||||
# LyngSat frequencies are also rounded to 1 decimal place for comparison
|
||||
lyngsat_sources = LyngSat.objects.filter(
|
||||
id_satellite=param.id_satellite,
|
||||
polarization=param.polarization,
|
||||
frequency__gte=rounded_freq - frequency_tolerance,
|
||||
frequency__lte=rounded_freq + frequency_tolerance
|
||||
).order_by('frequency')
|
||||
polarization=param.polarization
|
||||
).select_related('id_satellite', 'polarization')
|
||||
|
||||
if lyngsat_sources.exists():
|
||||
# Take first matching source
|
||||
objitem.lyngsat_source = lyngsat_sources.first()
|
||||
# Filter by rounded frequency with tolerance
|
||||
matching_sources = []
|
||||
for lyngsat in lyngsat_sources:
|
||||
if lyngsat.frequency:
|
||||
rounded_lyngsat_freq = round(lyngsat.frequency, 1)
|
||||
if abs(rounded_lyngsat_freq - rounded_freq) <= frequency_tolerance:
|
||||
matching_sources.append(lyngsat)
|
||||
|
||||
if matching_sources:
|
||||
# Take first matching source (sorted by frequency difference)
|
||||
matching_sources.sort(key=lambda x: abs(round(x.frequency, 1) - rounded_freq))
|
||||
objitem.lyngsat_source = matching_sources[0]
|
||||
objitem.save(update_fields=['lyngsat_source'])
|
||||
linked_count += 1
|
||||
|
||||
@@ -159,3 +167,35 @@ class ClearLyngsatCacheView(LoginRequiredMixin, View):
|
||||
def get(self, request):
|
||||
"""Cache management page."""
|
||||
return render(request, 'mainapp/clear_lyngsat_cache.html')
|
||||
|
||||
|
||||
class UnlinkAllLyngsatSourcesView(LoginRequiredMixin, View):
|
||||
"""View for unlinking all LyngSat sources from ObjItems."""
|
||||
|
||||
def post(self, request):
|
||||
"""Unlink all LyngSat sources."""
|
||||
try:
|
||||
# Count objects with LyngSat sources before unlinking
|
||||
linked_count = ObjItem.objects.filter(lyngsat_source__isnull=False).count()
|
||||
|
||||
# Unlink all LyngSat sources
|
||||
ObjItem.objects.filter(lyngsat_source__isnull=False).update(lyngsat_source=None)
|
||||
|
||||
messages.success(
|
||||
request,
|
||||
f"Успешно отвязано {linked_count} объектов от источников LyngSat"
|
||||
)
|
||||
except Exception as e:
|
||||
messages.error(request, f"Ошибка при отвязке источников: {str(e)}")
|
||||
|
||||
return redirect('mainapp:actions')
|
||||
|
||||
def get(self, request):
|
||||
"""Show confirmation page."""
|
||||
# Count objects with LyngSat sources
|
||||
linked_count = ObjItem.objects.filter(lyngsat_source__isnull=False).count()
|
||||
|
||||
context = {
|
||||
'linked_count': linked_count
|
||||
}
|
||||
return render(request, 'mainapp/unlink_lyngsat_confirm.html', context)
|
||||
|
||||
@@ -35,6 +35,7 @@ class SourceListView(LoginRequiredMixin, View):
|
||||
has_coords_kupsat = request.GET.get("has_coords_kupsat")
|
||||
has_coords_valid = request.GET.get("has_coords_valid")
|
||||
has_coords_reference = request.GET.get("has_coords_reference")
|
||||
has_lyngsat = request.GET.get("has_lyngsat")
|
||||
objitem_count_min = request.GET.get("objitem_count_min", "").strip()
|
||||
objitem_count_max = request.GET.get("objitem_count_max", "").strip()
|
||||
date_from = request.GET.get("date_from", "").strip()
|
||||
@@ -86,6 +87,14 @@ class SourceListView(LoginRequiredMixin, View):
|
||||
elif has_coords_reference == "0":
|
||||
sources = sources.filter(coords_reference__isnull=True)
|
||||
|
||||
# Filter by LyngSat presence
|
||||
if has_lyngsat == "1":
|
||||
sources = sources.filter(source_objitems__lyngsat_source__isnull=False).distinct()
|
||||
elif has_lyngsat == "0":
|
||||
sources = sources.filter(
|
||||
~Q(source_objitems__lyngsat_source__isnull=False)
|
||||
).distinct()
|
||||
|
||||
# Filter by ObjItem count
|
||||
if objitem_count_min:
|
||||
try:
|
||||
@@ -155,6 +164,8 @@ class SourceListView(LoginRequiredMixin, View):
|
||||
|
||||
# Prepare data for display
|
||||
processed_sources = []
|
||||
has_any_lyngsat = False # Track if any source has LyngSat data
|
||||
|
||||
for source in page_obj:
|
||||
# Format coordinates
|
||||
def format_coords(point):
|
||||
@@ -174,12 +185,21 @@ class SourceListView(LoginRequiredMixin, View):
|
||||
# Get count of related ObjItems
|
||||
objitem_count = source.objitem_count
|
||||
|
||||
# Get satellites for this source
|
||||
# Get satellites for this source and check for LyngSat
|
||||
satellite_names = set()
|
||||
has_lyngsat = False
|
||||
lyngsat_id = None
|
||||
|
||||
for objitem in source.source_objitems.all():
|
||||
if hasattr(objitem, 'parameter_obj') and objitem.parameter_obj:
|
||||
if hasattr(objitem.parameter_obj, 'id_satellite') and objitem.parameter_obj.id_satellite:
|
||||
satellite_names.add(objitem.parameter_obj.id_satellite.name)
|
||||
|
||||
# Check if any objitem has LyngSat
|
||||
if hasattr(objitem, 'lyngsat_source') and objitem.lyngsat_source:
|
||||
has_lyngsat = True
|
||||
lyngsat_id = objitem.lyngsat_source.id
|
||||
has_any_lyngsat = True
|
||||
|
||||
satellite_str = ", ".join(sorted(satellite_names)) if satellite_names else "-"
|
||||
|
||||
@@ -193,6 +213,8 @@ class SourceListView(LoginRequiredMixin, View):
|
||||
'satellite': satellite_str,
|
||||
'created_at': source.created_at,
|
||||
'updated_at': source.updated_at,
|
||||
'has_lyngsat': has_lyngsat,
|
||||
'lyngsat_id': lyngsat_id,
|
||||
})
|
||||
|
||||
# Prepare context for template
|
||||
@@ -207,6 +229,8 @@ class SourceListView(LoginRequiredMixin, View):
|
||||
'has_coords_kupsat': has_coords_kupsat,
|
||||
'has_coords_valid': has_coords_valid,
|
||||
'has_coords_reference': has_coords_reference,
|
||||
'has_lyngsat': has_lyngsat,
|
||||
'has_any_lyngsat': has_any_lyngsat,
|
||||
'objitem_count_min': objitem_count_min,
|
||||
'objitem_count_max': objitem_count_max,
|
||||
'date_from': date_from,
|
||||
|
||||
Reference in New Issue
Block a user