Виджет с усреднёнными точками на карте

This commit is contained in:
2025-11-14 16:58:13 +03:00
parent d61236dee2
commit bc226bfc1a
16 changed files with 2268 additions and 14 deletions

View File

@@ -67,6 +67,12 @@
<!-- Action buttons -->
<div class="d-flex gap-2">
{% if user.customuser.role == 'admin' or user.customuser.role == 'moderator' %}
<button type="button" class="btn btn-danger btn-sm" title="Удалить"
onclick="deleteSelectedSources()">
<i class="bi bi-trash"></i> Удалить
</button>
{% endif %}
<button type="button" class="btn btn-outline-primary btn-sm" title="Показать на карте"
onclick="showSelectedOnMap()">
<i class="bi bi-map"></i> Карта
@@ -100,6 +106,24 @@
</div>
<div class="offcanvas-body">
<form method="get" id="filter-form">
<!-- Satellite Selection - Multi-select -->
<div class="mb-2">
<label class="form-label">Спутник:</label>
<div class="d-flex justify-content-between mb-1">
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="selectAllOptions('satellite_id', true)">Выбрать</button>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="selectAllOptions('satellite_id', false)">Снять</button>
</div>
<select name="satellite_id" class="form-select form-select-sm mb-2" multiple size="6">
{% for satellite in satellites %}
<option value="{{ satellite.id }}" {% if satellite.id in selected_satellites %}selected{% endif %}>
{{ satellite.name }}
</option>
{% endfor %}
</select>
</div>
<!-- Coordinates Average Filter -->
<div class="mb-2">
<label class="form-label">Усредненные координаты:</label>
@@ -168,9 +192,9 @@
</div>
</div>
<!-- ObjItem Count Filter -->
<!-- Point Count Filter -->
<div class="mb-2">
<label class="form-label">Количество ObjItem:</label>
<label class="form-label">Количество точек:</label>
<input type="number" name="objitem_count_min" class="form-control form-control-sm mb-1"
placeholder="От" value="{{ objitem_count_min|default:'' }}">
<input type="number" name="objitem_count_max" class="form-control form-control-sm"
@@ -217,13 +241,14 @@
{% endif %}
</a>
</th>
<th scope="col" style="min-width: 120px;">Спутник</th>
<th scope="col" style="min-width: 150px;">Усредненные координаты</th>
<th scope="col" style="min-width: 150px;">Координаты Кубсата</th>
<th scope="col" style="min-width: 150px;">Координаты оперативников</th>
<th scope="col" style="min-width: 150px;">Координаты справочные</th>
<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">
Кол-во ObjItem
Кол-во точек
{% if sort == 'objitem_count' %}
<i class="bi bi-arrow-up"></i>
{% elif sort == '-objitem_count' %}
@@ -262,6 +287,7 @@
value="{{ source.id }}">
</td>
<td class="text-center">{{ source.id }}</td>
<td>{{ source.satellite }}</td>
<td>{{ source.coords_average }}</td>
<td>{{ source.coords_kupsat }}</td>
<td>{{ source.coords_valid }}</td>
@@ -285,6 +311,19 @@
</button>
{% endif %}
{% if source.objitem_count > 1 %}
<a href="{% url 'mainapp:show_source_averaging_map' source.id %}"
target="_blank"
class="btn btn-sm btn-outline-info"
title="Визуализация усреднения">
<i class="bi bi-diagram-3"></i>
</a>
{% else %}
<button type="button" class="btn btn-sm btn-outline-secondary" disabled title="Недостаточно точек для усреднения">
<i class="bi bi-diagram-3"></i>
</button>
{% endif %}
<button type="button" class="btn btn-sm btn-outline-primary"
onclick="showSourceDetails({{ source.id }})"
title="Показать детали">
@@ -307,7 +346,7 @@
</tr>
{% empty %}
<tr>
<td colspan="10" class="text-center text-muted">Нет данных для отображения</td>
<td colspan="11" class="text-center text-muted">Нет данных для отображения</td>
</tr>
{% endfor %}
</tbody>
@@ -335,7 +374,7 @@
</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>
<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">
<thead class="table-light sticky-top">
@@ -364,7 +403,7 @@
</div>
</div>
<div id="modalNoData" class="text-center text-muted py-4" style="display: none;">
Нет связанных объектов
Нет связанных точек
</div>
</div>
<div class="modal-footer">
@@ -427,6 +466,27 @@ function showSelectedOnMap() {
window.open(url, '_blank'); // Open in a new tab
}
// Function to delete selected sources
function deleteSelectedSources() {
// Get all checked checkboxes
const checkedCheckboxes = document.querySelectorAll('.item-checkbox:checked');
if (checkedCheckboxes.length === 0) {
alert('Пожалуйста, выберите хотя бы один источник для удаления');
return;
}
// Extract IDs from checked checkboxes
const selectedIds = [];
checkedCheckboxes.forEach(checkbox => {
selectedIds.push(checkbox.value);
});
// Redirect to confirmation page
const url = '{% url "mainapp:delete_selected_sources" %}' + '?ids=' + selectedIds.join(',');
window.location.href = url;
}
// Search functionality
function performSearch() {
const searchValue = document.getElementById('toolbar-search').value.trim();
@@ -501,6 +561,16 @@ function setupRadioLikeCheckboxes(name) {
});
}
// Function to select/deselect all options in a select element
function selectAllOptions(selectName, selectAll) {
const selectElement = document.querySelector(`select[name="${selectName}"]`);
if (selectElement) {
for (let i = 0; i < selectElement.options.length; i++) {
selectElement.options[i].selected = selectAll;
}
}
}
// Filter counter functionality
function updateFilterCounter() {
const form = document.getElementById('filter-form');
@@ -510,6 +580,19 @@ function updateFilterCounter() {
// Count non-empty form fields
for (const [key, value] of formData.entries()) {
if (value && value.trim() !== '') {
// For multi-select fields, skip counting individual selections
if (key === 'satellite_id') {
continue;
}
filterCount++;
}
}
// Count selected options in satellite multi-select field
const satelliteSelect = document.querySelector('select[name="satellite_id"]');
if (satelliteSelect) {
const selectedOptions = Array.from(satelliteSelect.selectedOptions).filter(opt => opt.selected);
if (selectedOptions.length > 0) {
filterCount++;
}
}
@@ -569,6 +652,11 @@ document.addEventListener('DOMContentLoaded', function() {
input.addEventListener('change', updateFilterCounter);
});
const selectFields = form.querySelectorAll('select');
selectFields.forEach(select => {
select.addEventListener('change', updateFilterCounter);
});
const checkboxFields = form.querySelectorAll('input[type="checkbox"]');
checkboxFields.forEach(checkbox => {
checkbox.addEventListener('change', updateFilterCounter);