1395 lines
72 KiB
HTML
1395 lines
72 KiB
HTML
{% extends 'mainapp/base.html' %}
|
||
|
||
{% block title %}Список объектов{% endblock %}
|
||
{% block extra_css %}
|
||
<style>
|
||
.table-responsive tr.selected {
|
||
background-color: #d4edff;
|
||
}
|
||
</style>
|
||
{% endblock %}
|
||
{% block content %}
|
||
<div class="container-fluid px-3">
|
||
<div class="row mb-3">
|
||
<div class="col-12">
|
||
<h2>Список объектов</h2>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Toolbar -->
|
||
<div class="row mb-3">
|
||
<div class="col-12">
|
||
<div class="card">
|
||
<div class="card-body">
|
||
<div class="d-flex flex-wrap align-items-center gap-3">
|
||
<!-- Search bar made more compact -->
|
||
<div style="min-width: 200px; flex-grow: 1; max-width: 400px;">
|
||
<div class="input-group">
|
||
<input type="text" id="toolbar-search" class="form-control" placeholder="Поиск..."
|
||
value="{{ search_query|default:'' }}">
|
||
<button type="button" class="btn btn-outline-primary"
|
||
onclick="performSearch()">Найти</button>
|
||
<button type="button" class="btn btn-outline-secondary"
|
||
onclick="clearSearch()">Очистить</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Action buttons bar -->
|
||
<div class="d-flex gap-2">
|
||
{% comment %} <button type="button" class="btn btn-success btn-sm" title="Добавить">
|
||
<i class="bi bi-plus-circle"></i> Добавить
|
||
</button>
|
||
<button type="button" class="btn btn-info btn-sm" title="Изменить">
|
||
<i class="bi bi-pencil"></i> Изменить
|
||
</button> {% endcomment %}
|
||
{% if user.customuser.role == 'admin' or user.customuser.role == 'moderator' %}
|
||
<button type="button" class="btn btn-danger btn-sm" title="Удалить"
|
||
onclick="deleteSelectedObjects()">
|
||
<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> Карта
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Items per page select moved here -->
|
||
<div>
|
||
<label for="items-per-page" class="form-label mb-0">Показать:</label>
|
||
<select name="items_per_page" id="items-per-page"
|
||
class="form-select form-select-sm d-inline-block" style="width: auto;"
|
||
onchange="updateItemsPerPage()">
|
||
{% for option in available_items_per_page %}
|
||
<option value="{{ option }}" {% if option == items_per_page %}selected{% endif %}>
|
||
{{ option }}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
|
||
<!-- Filter Toggle Button -->
|
||
<div>
|
||
<button class="btn btn-outline-primary btn-sm" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasFilters" aria-controls="offcanvasFilters">
|
||
<i class="bi bi-funnel"></i> Фильтры
|
||
<span id="filterCounter" class="badge bg-danger" style="display: none;">0</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Add to List Button with Counter -->
|
||
<div>
|
||
<button class="btn btn-outline-success btn-sm" type="button" onclick="addSelectedToList()">
|
||
<i class="bi bi-plus-circle"></i> Добавить к
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Selected Items Counter Button -->
|
||
<div>
|
||
<button class="btn btn-outline-info btn-sm" type="button" data-bs-toggle="offcanvas" data-bs-target="#selectedItemsOffcanvas" aria-controls="selectedItemsOffcanvas">
|
||
<i class="bi bi-list-check"></i> Список
|
||
<span id="selectedCounter" class="badge bg-info" style="display: none;">0</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Column visibility toggle button -->
|
||
<div class="dropdown">
|
||
<button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle"
|
||
id="columnVisibilityDropdown" data-bs-toggle="dropdown" aria-expanded="false">
|
||
<i class="bi bi-gear"></i> Колонки
|
||
</button>
|
||
<ul class="dropdown-menu" aria-labelledby="columnVisibilityDropdown" style="z-index: 1050; max-height: 300px; overflow-y: auto;">
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" id="select-all-columns" unchecked
|
||
onchange="toggleAllColumns(this)"> Выбрать всё
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<hr class="dropdown-divider">
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="0" checked
|
||
onchange="toggleColumn(this)"> Выбрать
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="1" checked
|
||
onchange="toggleColumn(this)"> Имя
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="2" checked
|
||
onchange="toggleColumn(this)"> Спутник
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="3" checked
|
||
onchange="toggleColumn(this)"> Част, МГц
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="4" checked
|
||
onchange="toggleColumn(this)"> Полоса, МГц
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="5" checked
|
||
onchange="toggleColumn(this)"> Поляризация
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="6" checked
|
||
onchange="toggleColumn(this)"> Сим. V
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="7" checked
|
||
onchange="toggleColumn(this)"> Модул
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="8" checked
|
||
onchange="toggleColumn(this)"> ОСШ
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="9" checked
|
||
onchange="toggleColumn(this)"> Время ГЛ
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="10" checked
|
||
onchange="toggleColumn(this)"> Местоположение
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="11" checked
|
||
onchange="toggleColumn(this)"> Геолокация
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="12" checked
|
||
onchange="toggleColumn(this)"> Кубсат
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="13" checked
|
||
onchange="toggleColumn(this)"> Опер. отд
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="14" checked
|
||
onchange="toggleColumn(this)"> Гео-куб, км
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="15" checked
|
||
onchange="toggleColumn(this)"> Гео-опер, км
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="16" checked
|
||
onchange="toggleColumn(this)"> Куб-опер, км
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="17" checked
|
||
onchange="toggleColumn(this)"> Обновлено
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="18" checked
|
||
onchange="toggleColumn(this)"> Кем (обновление)
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="19" checked
|
||
onchange="toggleColumn(this)"> Создано
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="20" checked
|
||
onchange="toggleColumn(this)"> Кем (создание)
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="21" unchecked
|
||
onchange="toggleColumn(this)"> Комментарий
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="22" unchecked
|
||
onchange="toggleColumn(this)"> Усреднённое
|
||
</label>
|
||
</li>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="23" unchecked
|
||
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>
|
||
<li>
|
||
<label class="dropdown-item">
|
||
<input type="checkbox" class="column-toggle" data-column="25" checked
|
||
onchange="toggleColumn(this)"> Sigma
|
||
</label>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Pagination -->
|
||
<div class="ms-auto">
|
||
{% include 'mainapp/components/_pagination.html' with page_obj=page_obj show_info=True %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Offcanvas Filter Panel -->
|
||
<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasFilters" aria-labelledby="offcanvasFiltersLabel">
|
||
<div class="offcanvas-header">
|
||
<h5 class="offcanvas-title" id="offcanvasFiltersLabel">Фильтры</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Закрыть"></button>
|
||
</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>
|
||
|
||
<!-- Frequency Filter -->
|
||
<div class="mb-2">
|
||
<label class="form-label">Частота, МГц:</label>
|
||
<input type="number" step="0.001" name="freq_min" class="form-control form-control-sm mb-1"
|
||
placeholder="От" value="{{ freq_min|default:'' }}">
|
||
<input type="number" step="0.001" name="freq_max" class="form-control form-control-sm"
|
||
placeholder="До" value="{{ freq_max|default:'' }}">
|
||
</div>
|
||
|
||
<!-- Range Filter -->
|
||
<div class="mb-2">
|
||
<label class="form-label">Полоса, МГц:</label>
|
||
<input type="number" step="0.001" name="range_min" class="form-control form-control-sm mb-1"
|
||
placeholder="От" value="{{ range_min|default:'' }}">
|
||
<input type="number" step="0.001" name="range_max" class="form-control form-control-sm"
|
||
placeholder="До" value="{{ range_max|default:'' }}">
|
||
</div>
|
||
|
||
<!-- SNR Filter -->
|
||
<div class="mb-2">
|
||
<label class="form-label">ОСШ:</label>
|
||
<input type="number" step="0.001" name="snr_min" class="form-control form-control-sm mb-1"
|
||
placeholder="От" value="{{ snr_min|default:'' }}">
|
||
<input type="number" step="0.001" name="snr_max" class="form-control form-control-sm"
|
||
placeholder="До" value="{{ snr_max|default:'' }}">
|
||
</div>
|
||
|
||
<!-- Symbol Rate Filter -->
|
||
<div class="mb-2">
|
||
<label class="form-label">Сим. v, БОД:</label>
|
||
<input type="number" step="0.001" name="bod_min" class="form-control form-control-sm mb-1"
|
||
placeholder="От" value="{{ bod_min|default:'' }}">
|
||
<input type="number" step="0.001" name="bod_max" class="form-control form-control-sm"
|
||
placeholder="До" value="{{ bod_max|default:'' }}">
|
||
</div>
|
||
|
||
<!-- Modulation Filter -->
|
||
<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('modulation', true)">Выбрать</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary"
|
||
onclick="selectAllOptions('modulation', false)">Снять</button>
|
||
</div>
|
||
<select name="modulation" class="form-select form-select-sm mb-2" multiple size="6">
|
||
{% for mod in modulations %}
|
||
<option value="{{ mod.id }}" {% if mod.id in selected_modulations %}selected{% endif %}>
|
||
{{ mod.name }}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
|
||
<!-- Polarization Filter -->
|
||
<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('polarization', true)">Выбрать</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary"
|
||
onclick="selectAllOptions('polarization', false)">Снять</button>
|
||
</div>
|
||
<select name="polarization" class="form-select form-select-sm mb-2" multiple size="4">
|
||
{% for pol in polarizations %}
|
||
<option value="{{ pol.id }}" {% if pol.id in selected_polarizations %}selected{% endif %}>
|
||
{{ pol.name }}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
|
||
<!-- Kubsat Coordinates 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_kupsat" id="has_kupsat_1"
|
||
value="1" {% if has_kupsat == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="has_kupsat_1">Есть</label>
|
||
</div>
|
||
<div class="form-check form-check-inline">
|
||
<input class="form-check-input" type="checkbox" name="has_kupsat" id="has_kupsat_0"
|
||
value="0" {% if has_kupsat == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="has_kupsat_0">Нет</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Valid Coordinates 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_valid" id="has_valid_1"
|
||
value="1" {% if has_valid == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="has_valid_1">Есть</label>
|
||
</div>
|
||
<div class="form-check form-check-inline">
|
||
<input class="form-check-input" type="checkbox" name="has_valid" id="has_valid_0"
|
||
value="0" {% if has_valid == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="has_valid_0">Нет</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Source Type 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_source_type" id="has_source_type_1"
|
||
value="1" {% if has_source_type == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="has_source_type_1">Есть (ТВ)</label>
|
||
</div>
|
||
<div class="form-check form-check-inline">
|
||
<input class="form-check-input" type="checkbox" name="has_source_type" id="has_source_type_0"
|
||
value="0" {% if has_source_type == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="has_source_type_0">Нет</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sigma Filter -->
|
||
<div class="mb-2">
|
||
<label class="form-label">Sigma:</label>
|
||
<div>
|
||
<div class="form-check form-check-inline">
|
||
<input class="form-check-input" type="checkbox" name="has_sigma" id="has_sigma_1"
|
||
value="1" {% if has_sigma == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="has_sigma_1">Есть</label>
|
||
</div>
|
||
<div class="form-check form-check-inline">
|
||
<input class="form-check-input" type="checkbox" name="has_sigma" id="has_sigma_0"
|
||
value="0" {% if has_sigma == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="has_sigma_0">Нет</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Date Filter -->
|
||
<div class="mb-2">
|
||
<label class="form-label">Дата ГЛ:</label>
|
||
<div class="mb-2">
|
||
<div class="btn-group btn-group-sm w-100 mb-1" role="group">
|
||
<button type="button" class="btn btn-outline-secondary"
|
||
onclick="setDateRange('today')">Сегодня</button>
|
||
<button type="button" class="btn btn-outline-secondary"
|
||
onclick="setDateRange('week')">Неделя</button>
|
||
</div>
|
||
<div class="btn-group btn-group-sm w-100 mb-1" role="group">
|
||
<button type="button" class="btn btn-outline-secondary"
|
||
onclick="setDateRange('month')">Месяц</button>
|
||
<button type="button" class="btn btn-outline-secondary"
|
||
onclick="setDateRange('year')">Год</button>
|
||
</div>
|
||
</div>
|
||
<input type="date" name="date_from" id="date_from" class="form-control form-control-sm mb-1"
|
||
placeholder="От" value="{{ date_from|default:'' }}">
|
||
<input type="date" name="date_to" id="date_to" class="form-control form-control-sm"
|
||
placeholder="До" value="{{ date_to|default:'' }}">
|
||
</div>
|
||
|
||
<!-- Apply Filters and Reset Buttons -->
|
||
<div class="d-grid gap-2 mt-2">
|
||
<button type="submit" class="btn btn-primary btn-sm">Применить</button>
|
||
<a href="?" class="btn btn-secondary btn-sm">Сбросить</a>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Main Table -->
|
||
<div class="col-md">
|
||
<div class="card h-100">
|
||
<div class="card-body p-0">
|
||
<div class="table-responsive" style="max-height: 75vh; overflow-y: auto;">
|
||
<table class="table table-striped table-hover table-sm" style="font-size: 0.85rem;">
|
||
<thead class="table-dark sticky-top">
|
||
<tr>
|
||
<th scope="col" class="text-center" style="width: 3%;">
|
||
<input type="checkbox" id="select-all" class="form-check-input">
|
||
</th>
|
||
{% include 'mainapp/components/_table_header.html' with label="Имя" field="name" sort=sort %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Спутник" field="satellite" sort=sort %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Част, МГц" field="frequency" sort=sort %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Полоса, МГц" field="freq_range" sort=sort %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Поляризация" field="polarization" sort=sort %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Сим. V" field="bod_velocity" sort=sort %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Модул" field="modulation" sort=sort %}
|
||
{% include 'mainapp/components/_table_header.html' with label="ОСШ" field="snr" sort=sort %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Время ГЛ" field="geo_timestamp" sort=sort %}
|
||
{% 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="" sortable=False %}
|
||
{% 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="" sortable=False %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Куб-опер, км" field="" sortable=False %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Обновлено" field="updated_at" sort=sort %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Кем(обн)" field="" sortable=False %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Создано" field="created_at" sort=sort %}
|
||
{% 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="" 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 %}
|
||
{% include 'mainapp/components/_table_header.html' with label="Sigma" field="" sortable=False %}
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for item in processed_objects %}
|
||
<tr>
|
||
<td class="text-center">
|
||
<input type="checkbox" class="form-check-input item-checkbox"
|
||
value="{{ item.id }}">
|
||
</td>
|
||
<td><a href="{% if item.obj.id %}{% if user.customuser.role == 'admin' or user.customuser.role == 'moderator' %}{% url 'mainapp:objitem_update' item.obj.id %}?{{ request.GET.urlencode }}{% else %}{% url 'mainapp:objitem_detail' item.obj.id %}?{{ request.GET.urlencode }}{% endif %}{% endif %}">{{ item.name }}</a></td>
|
||
<td>{{ item.satellite_name }}</td>
|
||
<td>{{ item.frequency }}</td>
|
||
<td>{{ item.freq_range }}</td>
|
||
<td>{{ item.polarization }}</td>
|
||
<td>{{ item.bod_velocity }}</td>
|
||
<td>{{ item.modulation }}</td>
|
||
<td>{{ item.snr }}</td>
|
||
<td>{{ item.geo_timestamp|date:"d.m.Y H:i" }}</td>
|
||
<td>{{ item.geo_location}}</td>
|
||
<td>{{ item.geo_coords }}</td>
|
||
<td>{{ item.kupsat_coords }}</td>
|
||
<td>{{ item.valid_coords }}</td>
|
||
<td>{{ item.distance_geo_kup }}</td>
|
||
<td>{{ item.distance_geo_valid }}</td>
|
||
<td>{{ item.distance_kup_valid }}</td>
|
||
<td>{{ item.obj.updated_at|date:"d.m.Y H:i" }}</td>
|
||
<td>{{ item.updated_by }}</td>
|
||
<td>{{ item.obj.created_at|date:"d.m.Y H:i" }}</td>
|
||
<td>{{ item.obj.created_by }}</td>
|
||
<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>
|
||
<td>
|
||
{% if item.has_sigma %}
|
||
<a href="#" class="text-info text-decoration-none" onclick="showSigmaParameterModal({{ item.obj.parameter_obj.id }}); return false;" title="{{ item.sigma_info }}">
|
||
<i class="bi bi-graph-up"></i> {{ item.sigma_info }}
|
||
</a>
|
||
{% else %}
|
||
-
|
||
{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% empty %}
|
||
<tr>
|
||
<td colspan="26" class="text-center py-4">
|
||
{% if selected_satellite_id %}
|
||
Нет данных для выбранных фильтров
|
||
{% else %}
|
||
Пожалуйста, выберите спутник для отображения данных
|
||
{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<script>
|
||
let lastCheckedIndex = null;
|
||
|
||
function updateRowHighlight(checkbox) {
|
||
const row = checkbox.closest('tr');
|
||
if (checkbox.checked) {
|
||
row.classList.add('selected');
|
||
} else {
|
||
row.classList.remove('selected');
|
||
}
|
||
}
|
||
|
||
function handleCheckboxClick(e) {
|
||
if (e.shiftKey && lastCheckedIndex !== null) {
|
||
const checkboxes = document.querySelectorAll('.item-checkbox');
|
||
const currentIndex = Array.from(checkboxes).indexOf(e.target);
|
||
const startIndex = Math.min(lastCheckedIndex, currentIndex);
|
||
const endIndex = Math.max(lastCheckedIndex, currentIndex);
|
||
|
||
for (let i = startIndex; i <= endIndex; i++) {
|
||
checkboxes[i].checked = e.target.checked;
|
||
updateRowHighlight(checkboxes[i]);
|
||
}
|
||
} else {
|
||
updateRowHighlight(e.target);
|
||
}
|
||
lastCheckedIndex = Array.from(document.querySelectorAll('.item-checkbox')).indexOf(e.target);
|
||
}
|
||
|
||
// Function to show selected objects on map
|
||
function showSelectedOnMap() {
|
||
// 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 the map view with selected IDs as query parameter
|
||
const url = '{% url "mainapp:show_selected_objects_map" %}' + '?ids=' + selectedIds.join(',');
|
||
window.open(url, '_blank'); // Open in a new tab
|
||
}
|
||
|
||
function clearSelections() {
|
||
const itemCheckboxes = document.querySelectorAll('.item-checkbox');
|
||
itemCheckboxes.forEach(checkbox => {
|
||
checkbox.checked = false;
|
||
});
|
||
// Also uncheck the select-all checkbox if it exists
|
||
const selectAllCheckbox = document.getElementById('select-all');
|
||
if (selectAllCheckbox) {
|
||
selectAllCheckbox.checked = false;
|
||
}
|
||
// Remove selected class from rows
|
||
const selectedRows = document.querySelectorAll('tr.selected');
|
||
selectedRows.forEach(row => {
|
||
row.classList.remove('selected');
|
||
});
|
||
}
|
||
|
||
// Function to delete selected objects
|
||
function deleteSelectedObjects() {
|
||
// Get all checked checkboxes
|
||
const checkedCheckboxes = document.querySelectorAll('.item-checkbox:checked');
|
||
|
||
if (checkedCheckboxes.length === 0) {
|
||
alert('Пожалуйста, выберите хотя бы один объект для удаления');
|
||
return;
|
||
}
|
||
|
||
// Confirm deletion with user
|
||
if (!confirm(`Вы уверены, что хотите удалить ${checkedCheckboxes.length} объект(ов)?`)) {
|
||
return;
|
||
}
|
||
|
||
// Extract IDs from checked checkboxes
|
||
const selectedIds = [];
|
||
checkedCheckboxes.forEach(checkbox => {
|
||
selectedIds.push(checkbox.value);
|
||
});
|
||
|
||
function getCookie(name) {
|
||
let cookieValue = null;
|
||
if (document.cookie && document.cookie !== '') {
|
||
const cookies = document.cookie.split(';');
|
||
for (let i = 0; i < cookies.length; i++) {
|
||
const cookie = cookies[i].trim();
|
||
// Does this cookie string begin with the name we want?
|
||
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return cookieValue;
|
||
}
|
||
const csrftoken = getCookie('csrftoken');
|
||
|
||
|
||
// Prepare request headers
|
||
const headers = {
|
||
'Content-Type': 'application/x-www-form-urlencoded',
|
||
};
|
||
|
||
// Add CSRF token to headers only if it exists
|
||
if (csrftoken) {
|
||
headers['X-CSRFToken'] = csrftoken;
|
||
}
|
||
|
||
// Send AJAX request to delete selected objects
|
||
fetch('{% url "mainapp:delete_selected_objects" %}', {
|
||
method: 'POST',
|
||
headers: headers,
|
||
body: 'ids=' + selectedIds.join(',')
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
alert(data.message);
|
||
clearSelections();
|
||
location.reload();
|
||
} else {
|
||
alert('Ошибка: ' + (data.error || 'Неизвестная ошибка'));
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
alert('Произошла ошибка при удалении объектов');
|
||
});
|
||
}
|
||
|
||
// Остальной ваш JavaScript код остается без изменений
|
||
function toggleColumn(checkbox) {
|
||
const columnIndex = parseInt(checkbox.getAttribute('data-column'));
|
||
const table = document.querySelector('.table');
|
||
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 toggleAllColumns(selectAllCheckbox) {
|
||
const columnCheckboxes = document.querySelectorAll('.column-toggle');
|
||
columnCheckboxes.forEach(checkbox => {
|
||
checkbox.checked = selectAllCheckbox.checked;
|
||
toggleColumn(checkbox);
|
||
});
|
||
}
|
||
|
||
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
const selectAllCheckbox = document.getElementById('select-all');
|
||
const itemCheckboxes = document.querySelectorAll('.item-checkbox');
|
||
|
||
if (selectAllCheckbox && itemCheckboxes.length > 0) {
|
||
selectAllCheckbox.addEventListener('change', function () {
|
||
itemCheckboxes.forEach(checkbox => {
|
||
checkbox.checked = selectAllCheckbox.checked;
|
||
});
|
||
});
|
||
|
||
itemCheckboxes.forEach(checkbox => {
|
||
checkbox.addEventListener('change', function () {
|
||
const allChecked = Array.from(itemCheckboxes).every(cb => cb.checked);
|
||
selectAllCheckbox.checked = allChecked;
|
||
});
|
||
});
|
||
|
||
// Добавляем обработчик для выбора диапазона
|
||
itemCheckboxes.forEach(checkbox => {
|
||
checkbox.addEventListener('click', handleCheckboxClick);
|
||
});
|
||
}
|
||
|
||
|
||
// Handle kubsat and valid coords checkboxes (mutually exclusive)
|
||
// Add a function to handle radio-like behavior for these checkboxes
|
||
function setupRadioLikeCheckboxes(name) {
|
||
const checkboxes = document.querySelectorAll(`input[name="${name}"]`);
|
||
checkboxes.forEach(checkbox => {
|
||
checkbox.addEventListener('change', function () {
|
||
// If this checkbox is checked, uncheck the other
|
||
if (this.checked) {
|
||
checkboxes.forEach(other => {
|
||
if (other !== this) {
|
||
other.checked = false;
|
||
}
|
||
});
|
||
} else {
|
||
// If both are unchecked, no action needed
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
setupRadioLikeCheckboxes('has_kupsat');
|
||
setupRadioLikeCheckboxes('has_valid');
|
||
setupRadioLikeCheckboxes('has_source_type');
|
||
setupRadioLikeCheckboxes('has_sigma');
|
||
|
||
// Date range quick selection functions
|
||
window.setDateRange = function (period) {
|
||
const dateFrom = document.getElementById('date_from');
|
||
const dateTo = document.getElementById('date_to');
|
||
const today = new Date();
|
||
|
||
// Set end date to today
|
||
dateTo.valueAsDate = today;
|
||
|
||
// Calculate start date based on period
|
||
const startDate = new Date();
|
||
switch (period) {
|
||
case 'today':
|
||
startDate.setDate(today.getDate());
|
||
break;
|
||
case 'week':
|
||
startDate.setDate(today.getDate() - 7);
|
||
break;
|
||
case 'month':
|
||
startDate.setMonth(today.getMonth() - 1);
|
||
break;
|
||
case 'year':
|
||
startDate.setFullYear(today.getFullYear() - 1);
|
||
break;
|
||
}
|
||
|
||
dateFrom.valueAsDate = startDate;
|
||
};
|
||
|
||
// Function to select/deselect all options in a select element
|
||
window.selectAllOptions = function (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;
|
||
}
|
||
}
|
||
};
|
||
|
||
// Get all current filter values and return as URL parameters
|
||
function getAllFilterParams() {
|
||
const form = document.getElementById('filter-form');
|
||
const searchValue = document.getElementById('toolbar-search').value;
|
||
|
||
// Create URLSearchParams object from the form
|
||
const params = new URLSearchParams(new FormData(form));
|
||
|
||
// Add search value from toolbar if present
|
||
if (searchValue.trim() !== '') {
|
||
params.set('search', searchValue);
|
||
} else {
|
||
params.delete('search');
|
||
}
|
||
|
||
return params.toString();
|
||
}
|
||
|
||
// Function to perform search
|
||
window.performSearch = function () {
|
||
const filterParams = getAllFilterParams();
|
||
window.location.search = filterParams;
|
||
};
|
||
|
||
// Function to clear search
|
||
window.clearSearch = function () {
|
||
document.getElementById('toolbar-search').value = '';
|
||
const filterParams = getAllFilterParams();
|
||
window.location.search = filterParams;
|
||
};
|
||
|
||
// Handle Enter key in toolbar search
|
||
const toolbarSearch = document.getElementById('toolbar-search');
|
||
if (toolbarSearch) {
|
||
toolbarSearch.addEventListener('keypress', function (e) {
|
||
if (e.key === 'Enter') {
|
||
performSearch();
|
||
}
|
||
});
|
||
}
|
||
|
||
//const satelliteSelect = document.querySelector('select[name="satellite_id"]');
|
||
//if (satelliteSelect) {
|
||
//satelliteSelect.addEventListener('change', function() {
|
||
// updateSatelliteSelection();
|
||
// });
|
||
//}
|
||
|
||
// Function to update items per page
|
||
window.updateItemsPerPage = function () {
|
||
const itemsPerPageSelect = document.getElementById('items-per-page');
|
||
const currentParams = new URLSearchParams(window.location.search);
|
||
|
||
// Add or update the items_per_page parameter
|
||
currentParams.set('items_per_page', itemsPerPageSelect.value);
|
||
|
||
// Remove page parameter to reset to first page when changing items per page
|
||
currentParams.delete('page');
|
||
|
||
// Update URL and reload
|
||
window.location.search = currentParams.toString();
|
||
};
|
||
|
||
// Initialize column visibility - hide creation columns by default
|
||
function initColumnVisibility() {
|
||
const creationDateCheckbox = document.querySelector('input[data-column="19"]');
|
||
const creationUserCheckbox = document.querySelector('input[data-column="20"]');
|
||
const creationDistanceGOpCheckbox = document.querySelector('input[data-column="15"]');
|
||
const creationDistanceKubOpCheckbox = document.querySelector('input[data-column="16"]');
|
||
if (creationDistanceGOpCheckbox) {
|
||
creationDistanceGOpCheckbox.checked = false;
|
||
toggleColumn(creationDistanceGOpCheckbox);
|
||
}
|
||
if (creationDistanceKubOpCheckbox) {
|
||
creationDistanceKubOpCheckbox.checked = false;
|
||
toggleColumn(creationDistanceKubOpCheckbox);
|
||
}
|
||
|
||
if (creationDateCheckbox) {
|
||
creationDateCheckbox.checked = false;
|
||
toggleColumn(creationDateCheckbox);
|
||
}
|
||
|
||
if (creationUserCheckbox) {
|
||
creationUserCheckbox.checked = false;
|
||
toggleColumn(creationUserCheckbox);
|
||
}
|
||
|
||
// Hide comment, is_average, and standard columns by default
|
||
const commentCheckbox = document.querySelector('input[data-column="21"]');
|
||
const isAverageCheckbox = document.querySelector('input[data-column="22"]');
|
||
const standardCheckbox = document.querySelector('input[data-column="23"]');
|
||
|
||
if (commentCheckbox) {
|
||
commentCheckbox.checked = false;
|
||
toggleColumn(commentCheckbox);
|
||
}
|
||
|
||
if (isAverageCheckbox) {
|
||
isAverageCheckbox.checked = false;
|
||
toggleColumn(isAverageCheckbox);
|
||
}
|
||
|
||
if (standardCheckbox) {
|
||
standardCheckbox.checked = false;
|
||
toggleColumn(standardCheckbox);
|
||
}
|
||
}
|
||
// Filter counter functionality
|
||
function updateFilterCounter() {
|
||
const form = document.getElementById('filter-form');
|
||
const formData = new FormData(form);
|
||
let filterCount = 0;
|
||
|
||
// Count non-empty form fields
|
||
for (const [key, value] of formData.entries()) {
|
||
if (value && value.trim() !== '') {
|
||
// For multi-select fields, we need to handle them separately
|
||
if (key === 'satellite_id' || key === 'modulation' || key === 'polarization') {
|
||
// Skip counting individual selections - they'll be counted as one filter
|
||
continue;
|
||
}
|
||
filterCount++;
|
||
}
|
||
}
|
||
|
||
// Count selected options in multi-select fields
|
||
const multiSelectFields = ['satellite_id', 'modulation', 'polarization'];
|
||
for (const field of multiSelectFields) {
|
||
const selectElement = document.querySelector(`select[name="${field}"]`);
|
||
if (selectElement) {
|
||
const selectedOptions = Array.from(selectElement.selectedOptions).filter(opt => opt.selected);
|
||
if (selectedOptions.length > 0) {
|
||
filterCount++; // Count the entire field as one filter even if multiple options are selected
|
||
}
|
||
}
|
||
}
|
||
|
||
// Count checkbox filters
|
||
const hasKupsatCheckboxes = document.querySelectorAll('input[name="has_kupsat"]:checked');
|
||
const hasValidCheckboxes = document.querySelectorAll('input[name="has_valid"]:checked');
|
||
|
||
if (hasKupsatCheckboxes.length > 0) {
|
||
filterCount++;
|
||
}
|
||
if (hasValidCheckboxes.length > 0) {
|
||
filterCount++;
|
||
}
|
||
|
||
// Display the filter counter
|
||
const counterElement = document.getElementById('filterCounter');
|
||
if (counterElement) {
|
||
if (filterCount > 0) {
|
||
counterElement.textContent = filterCount;
|
||
counterElement.style.display = 'inline';
|
||
} else {
|
||
counterElement.style.display = 'none';
|
||
}
|
||
}
|
||
}
|
||
|
||
// Update filter counter when page loads
|
||
updateFilterCounter();
|
||
|
||
// Add event listeners to form elements to update counter when filters change
|
||
const form = document.getElementById('filter-form');
|
||
if (form) {
|
||
// For input fields
|
||
const inputFields = form.querySelectorAll('input[type="text"], input[type="number"], input[type="date"]');
|
||
inputFields.forEach(input => {
|
||
input.addEventListener('input', updateFilterCounter);
|
||
input.addEventListener('change', updateFilterCounter);
|
||
});
|
||
|
||
// For select elements (including multi-select)
|
||
const selectFields = form.querySelectorAll('select');
|
||
selectFields.forEach(select => {
|
||
select.addEventListener('change', updateFilterCounter);
|
||
});
|
||
|
||
// For checkbox inputs
|
||
const checkboxFields = form.querySelectorAll('input[type="checkbox"]');
|
||
checkboxFields.forEach(checkbox => {
|
||
checkbox.addEventListener('change', updateFilterCounter);
|
||
});
|
||
}
|
||
|
||
// Also update when the offcanvas is shown
|
||
const offcanvasElement = document.getElementById('offcanvasFilters');
|
||
if (offcanvasElement) {
|
||
offcanvasElement.addEventListener('show.bs.offcanvas', updateFilterCounter);
|
||
}
|
||
|
||
// Initialize selected items array from localStorage
|
||
function loadSelectedItemsFromStorage() {
|
||
try {
|
||
const storedItems = localStorage.getItem('selectedItems');
|
||
if (storedItems) {
|
||
window.selectedItems = JSON.parse(storedItems);
|
||
} else {
|
||
window.selectedItems = [];
|
||
}
|
||
} catch (e) {
|
||
console.error('Error loading selected items from storage:', e);
|
||
window.selectedItems = [];
|
||
}
|
||
}
|
||
|
||
// Function to save selected items to localStorage
|
||
window.saveSelectedItemsToStorage = function() {
|
||
try {
|
||
localStorage.setItem('selectedItems', JSON.stringify(window.selectedItems));
|
||
} catch (e) {
|
||
console.error('Error saving selected items to storage:', e);
|
||
}
|
||
}
|
||
|
||
// Function to update the selected items counter
|
||
window.updateSelectedCounter = function() {
|
||
const counterElement = document.getElementById('selectedCounter');
|
||
if (window.selectedItems && window.selectedItems.length > 0) {
|
||
counterElement.textContent = window.selectedItems.length;
|
||
counterElement.style.display = 'inline';
|
||
} else {
|
||
counterElement.style.display = 'none';
|
||
}
|
||
|
||
// Also update the counter in the offcanvas
|
||
const offcanvasCounter = document.querySelector('#selectedItemsOffcanvas .offcanvas-header .badge');
|
||
if (offcanvasCounter && window.selectedItems && window.selectedItems.length > 0) {
|
||
offcanvasCounter.textContent = window.selectedItems.length;
|
||
}
|
||
}
|
||
|
||
// Load selected items from localStorage on page load
|
||
loadSelectedItemsFromStorage();
|
||
|
||
// Update counters after loading items from localStorage
|
||
updateSelectedCounter();
|
||
|
||
// Function to add selected items to the list
|
||
window.addSelectedToList = function() {
|
||
const checkedCheckboxes = document.querySelectorAll('.item-checkbox:checked');
|
||
|
||
if (checkedCheckboxes.length === 0) {
|
||
alert('Пожалуйста, выберите хотя бы один элемент для добавления в список');
|
||
return;
|
||
}
|
||
|
||
// Get the data for each selected row and add to the selectedItems array
|
||
checkedCheckboxes.forEach(checkbox => {
|
||
const row = checkbox.closest('tr');
|
||
const itemId = checkbox.value;
|
||
|
||
const itemExists = window.selectedItems.some(item => item.id === itemId);
|
||
if (!itemExists) {
|
||
const rowData = {
|
||
id: itemId,
|
||
name: row.cells[1].textContent,
|
||
satellite: row.cells[2].textContent,
|
||
frequency: row.cells[3].textContent,
|
||
freq_range: row.cells[4].textContent,
|
||
polarization: row.cells[5].textContent,
|
||
bod_velocity: row.cells[6].textContent,
|
||
modulation: row.cells[7].textContent,
|
||
snr: row.cells[8].textContent,
|
||
geo_timestamp: row.cells[9].textContent,
|
||
geo_location: row.cells[10].textContent,
|
||
geo_coords: row.cells[11].textContent,
|
||
kupsat_coords: row.cells[12].textContent,
|
||
valid_coords: row.cells[13].textContent,
|
||
updated_at: row.cells[17].textContent,
|
||
updated_by: row.cells[18].textContent,
|
||
created_at: row.cells[19].textContent,
|
||
created_by: row.cells[20].textContent
|
||
};
|
||
|
||
window.selectedItems.push(rowData);
|
||
}
|
||
});
|
||
|
||
// Update the counter
|
||
if (typeof updateSelectedCounter === 'function') {
|
||
updateSelectedCounter();
|
||
}
|
||
|
||
// Save selected items to localStorage
|
||
saveSelectedItemsToStorage();
|
||
|
||
// Clear selections in the main table
|
||
const itemCheckboxes = document.querySelectorAll('.item-checkbox');
|
||
itemCheckboxes.forEach(checkbox => {
|
||
checkbox.checked = false;
|
||
});
|
||
const selectAllCheckbox = document.getElementById('select-all');
|
||
if (selectAllCheckbox) {
|
||
selectAllCheckbox.checked = false;
|
||
}
|
||
//alert(`Добавлено ${checkedCheckboxes.length} элемент(ов) в список. Всего: ${window.selectedItems.length} элемент(ов).`);
|
||
}
|
||
|
||
setTimeout(initColumnVisibility, 100);
|
||
});
|
||
|
||
// Function to populate the selected items table in the offcanvas
|
||
function populateSelectedItemsTable() {
|
||
const tableBody = document.getElementById('selected-items-table-body');
|
||
if (!tableBody) return;
|
||
|
||
// Clear existing rows
|
||
tableBody.innerHTML = '';
|
||
|
||
// Add rows for each selected item
|
||
window.selectedItems.forEach((item, index) => {
|
||
const row = document.createElement('tr');
|
||
row.innerHTML = `
|
||
<td class="text-center">
|
||
<input type="checkbox" class="form-check-input selected-item-checkbox" value="${item.id}">
|
||
</td>
|
||
<td>${item.name}</td>
|
||
<td>${item.satellite}</td>
|
||
<td>${item.frequency}</td>
|
||
<td>${item.freq_range}</td>
|
||
<td>${item.polarization}</td>
|
||
<td>${item.bod_velocity}</td>
|
||
<td>${item.modulation}</td>
|
||
<td>${item.snr}</td>
|
||
<td>${item.geo_timestamp}</td>
|
||
<td>${item.geo_location}</td>
|
||
<td>${item.geo_coords}</td>
|
||
<td>${item.kupsat_coords}</td>
|
||
<td>${item.valid_coords}</td>
|
||
<td>${item.updated_at}</td>
|
||
<td>${item.updated_by}</td>
|
||
<td>${item.created_at}</td>
|
||
<td>${item.created_by}</td>
|
||
`;
|
||
tableBody.appendChild(row);
|
||
});
|
||
}
|
||
|
||
// Function to remove selected items from the list
|
||
function removeSelectedItems() {
|
||
const checkboxes = document.querySelectorAll('#selected-items-table-body .selected-item-checkbox:checked');
|
||
if (checkboxes.length === 0) {
|
||
alert('Пожалуйста, выберите хотя бы один элемент для удаления из списка');
|
||
return;
|
||
}
|
||
|
||
// Get IDs of items to remove
|
||
const idsToRemove = Array.from(checkboxes).map(checkbox => checkbox.value);
|
||
|
||
// Remove items from the selectedItems array
|
||
window.selectedItems = window.selectedItems.filter(item => !idsToRemove.includes(item.id));
|
||
|
||
// Save selected items to localStorage
|
||
saveSelectedItemsToStorage();
|
||
|
||
// Update the counter and table
|
||
if (typeof updateSelectedCounter === 'function') {
|
||
updateSelectedCounter();
|
||
}
|
||
populateSelectedItemsTable();
|
||
}
|
||
|
||
// Function to send selected items (placeholder)
|
||
function sendSelectedItems() {
|
||
const selectedCount = document.querySelectorAll('#selected-items-table-body .selected-item-checkbox:checked').length;
|
||
if (selectedCount === 0) {
|
||
alert('Пожалуйста, выберите хотя бы один элемент для отправки');
|
||
return;
|
||
}
|
||
|
||
alert(`Отправка ${selectedCount} элементов... (функция в разработке)`);
|
||
// Placeholder for actual send functionality
|
||
}
|
||
|
||
// Function to toggle all checkboxes in the selected items table
|
||
function toggleAllSelected(checkbox) {
|
||
const checkboxes = document.querySelectorAll('#selected-items-table-body .selected-item-checkbox');
|
||
checkboxes.forEach(cb => {
|
||
cb.checked = checkbox.checked;
|
||
});
|
||
}
|
||
|
||
// Update the selected items table when the offcanvas is shown
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const offcanvasElement = document.getElementById('selectedItemsOffcanvas');
|
||
if (offcanvasElement) {
|
||
offcanvasElement.addEventListener('show.bs.offcanvas', function() {
|
||
populateSelectedItemsTable();
|
||
});
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<!-- Include the selected items offcanvas component -->
|
||
{% include 'mainapp/components/_selected_items_offcanvas.html' %}
|
||
|
||
<!-- Include the sigma parameter modal component -->
|
||
{% include 'mainapp/components/_sigma_parameter_modal.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 %} |