добавил таблицу на отдельную страницу вместе с фильтрами
This commit is contained in:
196
dbapp/mainapp/templates/mainapp/actions.html
Normal file
196
dbapp/mainapp/templates/mainapp/actions.html
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
{% extends 'mainapp/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Действия{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="text-center mb-5">
|
||||||
|
<h1 class="display-4 fw-bold">Действия</h1>
|
||||||
|
<p class="lead">Управление данными спутников</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Alert messages -->
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert {{ message.tags }} alert-dismissible fade show" role="alert">
|
||||||
|
{{ message }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Main feature cards -->
|
||||||
|
<div class="row g-4">
|
||||||
|
<!-- Excel Data Upload Card -->
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card h-100 shadow-sm border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
<div class="bg-primary bg-opacity-10 rounded-circle p-2 me-3">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-file-earmark-excel text-primary" viewBox="0 0 16 16">
|
||||||
|
<path d="M5.884 6.68a.5.5 0 1 0-.768.64L7.349 10l-2.233 2.68a.5.5 0 0 0 .768.64L8 10.781l2.116 2.54a.5.5 0 0 0 .768-.641L8.651 10l2.233-2.68a.5.5 0 0 0-.768-.64L8 9.219z"/>
|
||||||
|
<path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2M9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-0">Загрузка данных из Excel</h3>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">Загрузите данные из Excel-файла в базу данных. Поддерживается выбор спутника и ограничение количества записей.</p>
|
||||||
|
<a href="{% url 'load_excel_data' %}" class="btn btn-primary">
|
||||||
|
Перейти к загрузке данных
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CSV Data Upload 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-success 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-file-earmark-text text-success" viewBox="0 0 16 16">
|
||||||
|
<path d="M5.5 7a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1zm0 2a.5.5 0 0 0 0 1h2a.5.5 0 0 0 0-1z"/>
|
||||||
|
<path d="M9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.5L9.5 0m0 1v2A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-0">Загрузка данных из CSV</h3>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">Загрузите данные из CSV-файла в базу данных. Простая загрузка с возможностью указания пути к файлу.</p>
|
||||||
|
<a href="{% url 'load_csv_data' %}" class="btn btn-success">
|
||||||
|
Перейти к загрузке данных
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Satellite List 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-info 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-satellite text-info" viewBox="0 0 16 16">
|
||||||
|
<path d="M13.37 1.37c-2.75 0-5.4 1.13-7.29 3.02C4.13 6.33 3 8.98 3 11.73c0 2.75 1.13 5.4 3.02 7.29 1.94 1.94 4.54 3.02 7.29 3.02 2.75 0 5.4-1.13 7.29-3.02 1.94-1.94 3.02-4.54 3.02-7.29 0-2.75-1.13-5.4-3.02-7.29C18.77 2.5-2.75 1.37-5.5 1.37m-5.5 8.26c0-1.52.62-3.02 1.73-4.13 1.11-1.11 2.61-1.73 4.13-1.73 1.52 0 3.02.62 4.13 1.73 1.11 1.11 1.73 2.61 1.73 4.13 0 1.52-.62 3.02-1.73 4.13-1.11 1.11-2.61 1.73-4.13 1.73-1.52 0-3.02-.62-4.13-1.73-1.11-1.11-1.73-2.61-1.73-4.13"/>
|
||||||
|
<path d="M6.63 6.63c.62-.62 1.45-.98 2.27-.98.82 0 1.65.36 2.27.98.62.62.98 1.45.98 2.27 0 .82-.36 1.65-.98 2.27-.62.62-1.45.98-2.27.98-.82 0-1.65-.36-2.27-.98-.62-.62-.98-1.45-.98-2.27 0-.82.36-1.65.98-2.27m2.27 1.02c-.26 0-.52.1-.71.29-.2.2-.29.46-.29.71 0 .26.1.52.29.71.2.2.46.29.71.29.26 0 .52-.1.71-.29.2-.2.29-.46.29-.71 0-.26-.1-.52-.29-.71-.19-.19-.45-.29-.71-.29"/>
|
||||||
|
<path d="M5.13 5.13c.46-.46 1.08-.73 1.73-.73.65 0 1.27.27 1.73.73.46.46.73 1.08.73 1.73 0 .65-.27 1.27-.73 1.73-.46.46-1.08.73-1.73.73-.65 0-1.27-.27-1.73-.73-.46-.46-.73-1.08-.73-1.73 0-.65.27-1.27.73-1.73m1.73.58c-.15 0-.3.06-.42.18-.12.12-.18.27-.18.42 0 .15.06.3.18.42.12.12.27.18.42.18.15 0 .3-.06.42-.18.12-.12.18-.27.18-.42 0-.15-.06-.3-.18-.42-.12-.12-.27-.18-.42-.18"/>
|
||||||
|
<path d="M8 3.5c.28 0 .5.22.5.5v1c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-1c0-.28.22-.5.5-.5"/>
|
||||||
|
<path d="M10.5 8c0-.28.22-.5.5-.5h1c.28 0 .5.22.5.5s-.22.5-.5.5h-1c-.28 0-.5-.22-.5-.5"/>
|
||||||
|
<path d="M8 12.5c-.28 0-.5.22-.5.5v1c0 .28.22.5.5.5s.5-.22.5-.5v-1c0-.28-.22-.5-.5-.5"/>
|
||||||
|
<path d="M3.5 8c0 .28-.22.5-.5.5h-1c-.28 0-.5-.22-.5-.5s.22-.5.5-.5h1c.28 0 .5.22.5.5"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-0">Добавление списка спутников</h3>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">Добавьте новый список спутников в базу данных для последующего использования в загрузке данных.</p>
|
||||||
|
<a href="{% url 'add_sats' %}" class="btn btn-info">
|
||||||
|
Добавить список спутников
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Transponders 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-wifi text-warning" viewBox="0 0 16 16">
|
||||||
|
<path d="M6.002 3.5a5.5 5.5 0 1 1 3.996 9.5H10A5.5 5.5 0 0 1 6.002 3.5M6.002 5.5a3.5 3.5 0 1 0 3.996 5.5H10A3.5 3.5 0 0 0 6.002 5.5"/>
|
||||||
|
<path d="M10.5 12.5a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5.5.5 0 0 0-1 0 .5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5.5.5 0 0 0-1 0 .5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5 3.5 3.5 0 0 1 7 0"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-0">Добавление транспондеров</h3>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">Добавьте список транспондеров из JSON-файла в базу данных. Требуется наличие файла transponders.json.</p>
|
||||||
|
<a href="{% url 'add_trans' %}" class="btn btn-warning">
|
||||||
|
Добавить транспондеры
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- VCH Load Data 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-danger 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-upload text-danger" viewBox="0 0 16 16">
|
||||||
|
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5"/>
|
||||||
|
<path d="M7.646 1.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 2.707V11.5a.5.5 0 0 1-1 0V2.707L5.354 4.854a.5.5 0 1 1-.708-.708z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-0">Добавление данных ВЧ загрузки</h3>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">Загрузите данные ВЧ загрузки из HTML-файла с таблицами. Поддерживается выбор спутника для привязки данных.</p>
|
||||||
|
<a href="{% url 'vch_load' %}" class="btn btn-danger">
|
||||||
|
Добавить данные ВЧ загрузки
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Map Views 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-secondary 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-map text-secondary" viewBox="0 0 16 16">
|
||||||
|
<path d="M15.817.113A.5.5 0 0 1 16 .5v14a.5.5 0 0 1-.402.49l-5 1a.502.502 0 0 1-.196 0L5.5 15.01l-4.902.98A.5.5 0 0 1 0 15.5v-14a.5.5 0 0 1 .402-.49l5-1a.5.5 0 0 1 .196 0L10.5.99l4.902-.98a.5.5 0 0 1 .415.103M10 1.91l-4-.8v12.98l4 .8zM1.61 2.22l4.39.88v10.88l-4.39-.88zm9.18 10.88 4-.8V2.34l-4 .8z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-0">Карты</h3>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">Просматривайте данные на 2D и 3D картах для визуализации геолокации спутников.</p>
|
||||||
|
<div class="mt-2">
|
||||||
|
<a href="{% url '2dmap' %}" class="btn btn-secondary me-2">2D Карта</a>
|
||||||
|
<a href="{% url '3dmap' %}" class="btn btn-outline-secondary">3D Карта</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Calculation 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-info 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-calculator text-info" viewBox="0 0 16 16">
|
||||||
|
<path d="M2 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v4h2V2a1 1 0 0 0-1-1M5 6v1h1V6zm2 0v1h1V6zm2 0v1h1V6zm2 0v1h1V6zm1 2v1h1V8zm0 2v1h1v-1zm0 2v1h1v-1zm-8-6v8H3V8zm2 0v8h1V8zm2 0v8h1V8zm2 0v8h1V8z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-0">Привязка ВЧ загрузки</h3>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">Привязка ВЧ загрузки с sigma</p>
|
||||||
|
<a href="{% url 'link_vch_sigma' %}" class="btn btn-info">
|
||||||
|
Открыть форму
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- New Event 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-success 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-plus-circle text-success" viewBox="0 0 16 16">
|
||||||
|
<path d="M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0M4.5 7.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5M7.5 4.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 0 1h-1a.5.5 0 0 1-.5-.5m1 3a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-1 0v-3a.5.5 0 0 1 .5-.5"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-0">Формирование таблицы для Кубсатов</h3>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">Добавьте новое событие с помощью выбора спутника и загрузки файла данных.</p>
|
||||||
|
<a href="{% url 'kubsat_excel' %}" class="btn btn-success">
|
||||||
|
Добавить событие
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -24,7 +24,10 @@
|
|||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav me-auto">
|
<ul class="navbar-nav me-auto">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{% url 'home' %}">Главная</a>
|
<a class="nav-link" href="{% url 'home' %}">Объекты</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'actions' %}">Действия</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{% url '3dmap' %}">3D карта</a>
|
<a class="nav-link" href="{% url '3dmap' %}">3D карта</a>
|
||||||
@@ -41,9 +44,8 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- Основной контент -->
|
<!-- Основной контент -->
|
||||||
<main class="container mt-4">
|
<main class="{% if full_width_page %}container-fluid p-0{% else %}container mt-4{% endif %}">
|
||||||
{% block content %}
|
{% block content %}{% endblock %}
|
||||||
{% endblock %}
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script src="{% static 'bootstrap/bootstrap.bundle.min.js' %}"></script>
|
<script src="{% static 'bootstrap/bootstrap.bundle.min.js' %}"></script>
|
||||||
|
|||||||
@@ -1,196 +1,422 @@
|
|||||||
{% extends 'mainapp/base.html' %}
|
{% extends 'mainapp/base.html' %}
|
||||||
|
|
||||||
{% block title %}Главная{% endblock %}
|
{% block title %}Список объектов{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container-fluid px-3">
|
||||||
<div class="text-center mb-5">
|
<div class="row mb-3">
|
||||||
<h1 class="display-4 fw-bold">Геолокация</h1>
|
<div class="col-12">
|
||||||
<p class="lead">Управление данными спутников</p>
|
<h2>Список объектов</h2>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Alert messages -->
|
<!-- Toolbar -->
|
||||||
{% if messages %}
|
<div class="row mb-3">
|
||||||
{% for message in messages %}
|
<div class="col-12">
|
||||||
<div class="alert {{ message.tags }} alert-dismissible fade show" role="alert">
|
<div class="card">
|
||||||
{{ message }}
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Main feature cards -->
|
|
||||||
<div class="row g-4">
|
|
||||||
<!-- Excel Data Upload Card -->
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="card h-100 shadow-sm border-0">
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex align-items-center mb-3">
|
<div class="d-flex flex-wrap align-items-center gap-3">
|
||||||
<div class="bg-primary bg-opacity-10 rounded-circle p-2 me-3">
|
<div style="min-width: 300px; flex-grow: 1;">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-file-earmark-excel text-primary" viewBox="0 0 16 16">
|
<label for="toolbar-search" class="form-label mb-0">Поиск:</label>
|
||||||
<path d="M5.884 6.68a.5.5 0 1 0-.768.64L7.349 10l-2.233 2.68a.5.5 0 0 0 .768.64L8 10.781l2.116 2.54a.5.5 0 0 0 .768-.641L8.651 10l2.233-2.68a.5.5 0 0 0-.768-.64L8 9.219z"/>
|
<input type="text" id="toolbar-search" class="form-control" placeholder="Поиск по имени, местоположению..." value="{{ search_query|default:'' }}">
|
||||||
<path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2M9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5z"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title mb-0">Загрузка данных из Excel</h3>
|
<div class="ms-auto">
|
||||||
</div>
|
<button type="button" class="btn btn-outline-primary" onclick="performSearch()">Найти</button>
|
||||||
<p class="card-text">Загрузите данные из Excel-файла в базу данных. Поддерживается выбор спутника и ограничение количества записей.</p>
|
<button type="button" class="btn btn-outline-secondary" onclick="clearSearch()">Очистить</button>
|
||||||
<a href="{% url 'load_excel_data' %}" class="btn btn-primary">
|
|
||||||
Перейти к загрузке данных
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- CSV Data Upload 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-success 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-file-earmark-text text-success" viewBox="0 0 16 16">
|
|
||||||
<path d="M5.5 7a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1zm0 2a.5.5 0 0 0 0 1h2a.5.5 0 0 0 0-1z"/>
|
|
||||||
<path d="M9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.5L9.5 0m0 1v2A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1z"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title mb-0">Загрузка данных из CSV</h3>
|
|
||||||
</div>
|
|
||||||
<p class="card-text">Загрузите данные из CSV-файла в базу данных. Простая загрузка с возможностью указания пути к файлу.</p>
|
|
||||||
<a href="{% url 'load_csv_data' %}" class="btn btn-success">
|
|
||||||
Перейти к загрузке данных
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Satellite List 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-info 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-satellite text-info" viewBox="0 0 16 16">
|
|
||||||
<path d="M13.37 1.37c-2.75 0-5.4 1.13-7.29 3.02C4.13 6.33 3 8.98 3 11.73c0 2.75 1.13 5.4 3.02 7.29 1.94 1.94 4.54 3.02 7.29 3.02 2.75 0 5.4-1.13 7.29-3.02 1.94-1.94 3.02-4.54 3.02-7.29 0-2.75-1.13-5.4-3.02-7.29C18.77 2.5-2.75 1.37-5.5 1.37m-5.5 8.26c0-1.52.62-3.02 1.73-4.13 1.11-1.11 2.61-1.73 4.13-1.73 1.52 0 3.02.62 4.13 1.73 1.11 1.11 1.73 2.61 1.73 4.13 0 1.52-.62 3.02-1.73 4.13-1.11 1.11-2.61 1.73-4.13 1.73-1.52 0-3.02-.62-4.13-1.73-1.11-1.11-1.73-2.61-1.73-4.13"/>
|
|
||||||
<path d="M6.63 6.63c.62-.62 1.45-.98 2.27-.98.82 0 1.65.36 2.27.98.62.62.98 1.45.98 2.27 0 .82-.36 1.65-.98 2.27-.62.62-1.45.98-2.27.98-.82 0-1.65-.36-2.27-.98-.62-.62-.98-1.45-.98-2.27 0-.82.36-1.65.98-2.27m2.27 1.02c-.26 0-.52.1-.71.29-.2.2-.29.46-.29.71 0 .26.1.52.29.71.2.2.46.29.71.29.26 0 .52-.1.71-.29.2-.2.29-.46.29-.71 0-.26-.1-.52-.29-.71-.19-.19-.45-.29-.71-.29"/>
|
|
||||||
<path d="M5.13 5.13c.46-.46 1.08-.73 1.73-.73.65 0 1.27.27 1.73.73.46.46.73 1.08.73 1.73 0 .65-.27 1.27-.73 1.73-.46.46-1.08.73-1.73.73-.65 0-1.27-.27-1.73-.73-.46-.46-.73-1.08-.73-1.73 0-.65.27-1.27.73-1.73m1.73.58c-.15 0-.3.06-.42.18-.12.12-.18.27-.18.42 0 .15.06.3.18.42.12.12.27.18.42.18.15 0 .3-.06.42-.18.12-.12.18-.27.18-.42 0-.15-.06-.3-.18-.42-.12-.12-.27-.18-.42-.18"/>
|
|
||||||
<path d="M8 3.5c.28 0 .5.22.5.5v1c0 .28-.22.5-.5.5s-.5-.22-.5-.5v-1c0-.28.22-.5.5-.5"/>
|
|
||||||
<path d="M10.5 8c0-.28.22-.5.5-.5h1c.28 0 .5.22.5.5s-.22.5-.5.5h-1c-.28 0-.5-.22-.5-.5"/>
|
|
||||||
<path d="M8 12.5c-.28 0-.5.22-.5.5v1c0 .28.22.5.5.5s.5-.22.5-.5v-1c0-.28-.22-.5-.5-.5"/>
|
|
||||||
<path d="M3.5 8c0 .28-.22.5-.5.5h-1c-.28 0-.5-.22-.5-.5s.22-.5.5-.5h1c.28 0 .5.22.5.5"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h3 class="card-title mb-0">Добавление списка спутников</h3>
|
|
||||||
</div>
|
|
||||||
<p class="card-text">Добавьте новый список спутников в базу данных для последующего использования в загрузке данных.</p>
|
|
||||||
<a href="{% url 'add_sats' %}" class="btn btn-info">
|
|
||||||
Добавить список спутников
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Transponders 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-wifi text-warning" viewBox="0 0 16 16">
|
|
||||||
<path d="M6.002 3.5a5.5 5.5 0 1 1 3.996 9.5H10A5.5 5.5 0 0 1 6.002 3.5M6.002 5.5a3.5 3.5 0 1 0 3.996 5.5H10A3.5 3.5 0 0 0 6.002 5.5"/>
|
|
||||||
<path d="M10.5 12.5a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5.5.5 0 0 0-1 0 .5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5.5.5 0 0 0-1 0 .5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5 3.5 3.5 0 0 1 7 0"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h3 class="card-title mb-0">Добавление транспондеров</h3>
|
|
||||||
</div>
|
|
||||||
<p class="card-text">Добавьте список транспондеров из JSON-файла в базу данных. Требуется наличие файла transponders.json.</p>
|
|
||||||
<a href="{% url 'add_trans' %}" class="btn btn-warning">
|
|
||||||
Добавить транспондеры
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- VCH Load Data 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-danger 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-upload text-danger" viewBox="0 0 16 16">
|
|
||||||
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5"/>
|
|
||||||
<path d="M7.646 1.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 2.707V11.5a.5.5 0 0 1-1 0V2.707L5.354 4.854a.5.5 0 1 1-.708-.708z"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h3 class="card-title mb-0">Добавление данных ВЧ загрузки</h3>
|
|
||||||
</div>
|
|
||||||
<p class="card-text">Загрузите данные ВЧ загрузки из HTML-файла с таблицами. Поддерживается выбор спутника для привязки данных.</p>
|
|
||||||
<a href="{% url 'vch_load' %}" class="btn btn-danger">
|
|
||||||
Добавить данные ВЧ загрузки
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Map Views 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-secondary 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-map text-secondary" viewBox="0 0 16 16">
|
|
||||||
<path d="M15.817.113A.5.5 0 0 1 16 .5v14a.5.5 0 0 1-.402.49l-5 1a.502.502 0 0 1-.196 0L5.5 15.01l-4.902.98A.5.5 0 0 1 0 15.5v-14a.5.5 0 0 1 .402-.49l5-1a.5.5 0 0 1 .196 0L10.5.99l4.902-.98a.5.5 0 0 1 .415.103M10 1.91l-4-.8v12.98l4 .8zM1.61 2.22l4.39.88v10.88l-4.39-.88zm9.18 10.88 4-.8V2.34l-4 .8z"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h3 class="card-title mb-0">Карты</h3>
|
|
||||||
</div>
|
|
||||||
<p class="card-text">Просматривайте данные на 2D и 3D картах для визуализации геолокации спутников.</p>
|
|
||||||
<div class="mt-2">
|
|
||||||
<a href="{% url '2dmap' %}" class="btn btn-secondary me-2">2D Карта</a>
|
|
||||||
<a href="{% url '3dmap' %}" class="btn btn-outline-secondary">3D Карта</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Calculation Card -->
|
<div class="row g-3">
|
||||||
<div class="col-lg-6">
|
<!-- Filters Sidebar - Made narrower -->
|
||||||
<div class="card h-100 shadow-sm border-0">
|
<div class="col-md-2">
|
||||||
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex align-items-center mb-3">
|
<h5 class="card-title">Фильтры</h5>
|
||||||
<div class="bg-info bg-opacity-10 rounded-circle p-2 me-3">
|
<form method="get" id="filter-form">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-calculator text-info" viewBox="0 0 16 16">
|
<!-- Satellite Selection - Multi-select -->
|
||||||
<path d="M2 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v4h2V2a1 1 0 0 0-1-1M5 6v1h1V6zm2 0v1h1V6zm2 0v1h1V6zm2 0v1h1V6zm1 2v1h1V8zm0 2v1h1v-1zm0 2v1h1v-1zm-8-6v8H3V8zm2 0v8h1V8zm2 0v8h1V8zm2 0v8h1V8z"/>
|
<div class="mb-2">
|
||||||
</svg>
|
<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="4">
|
||||||
|
{% for satellite in satellites %}
|
||||||
|
<option value="{{ satellite.id }}"
|
||||||
|
{% if satellite.id in selected_satellites %}selected{% endif %}>
|
||||||
|
{{ satellite.name }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title mb-0">Привязка ВЧ загрузки</h3>
|
|
||||||
</div>
|
<!-- Frequency Filter -->
|
||||||
<p class="card-text">Привязка ВЧ загрузки с sigma</p>
|
<div class="mb-2">
|
||||||
<a href="{% url 'link_vch_sigma' %}" class="btn btn-info">
|
<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:'' }}">
|
||||||
</a>
|
<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>
|
||||||
|
|
||||||
|
<!-- Removed old search input as it's now in the toolbar -->
|
||||||
|
|
||||||
|
<!-- 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="4">
|
||||||
|
{% 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>
|
||||||
|
|
||||||
|
<!-- Items Per Page -->
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="items-per-page" class="form-label">Элементов:</label>
|
||||||
|
<select name="items_per_page" id="items-per-page" class="form-select form-select-sm" onchange="document.getElementById('filter-form').submit();">
|
||||||
|
{% for option in available_items_per_page %}
|
||||||
|
<option value="{{ option }}" {% if option == items_per_page %}selected{% endif %}>
|
||||||
|
{{ option }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- New Event Card -->
|
<!-- Main Table -->
|
||||||
<div class="col-lg-6">
|
<div class="col-md-10">
|
||||||
<div class="card h-100 shadow-sm border-0">
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body p-0">
|
||||||
<div class="d-flex align-items-center mb-3">
|
<div class="table-responsive" style="max-height: 75vh; overflow-y: auto;">
|
||||||
<div class="bg-success bg-opacity-10 rounded-circle p-2 me-3">
|
<table class="table table-striped table-hover table-sm" style="font-size: 0.85rem;">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-plus-circle text-success" viewBox="0 0 16 16">
|
<thead class="table-dark sticky-top">
|
||||||
<path d="M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0M4.5 7.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5M7.5 4.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 0 1h-1a.5.5 0 0 1-.5-.5m1 3a.5.5 0 0 1 .5.5v3a.5.5 0 0 1-1 0v-3a.5.5 0 0 1 .5-.5"/>
|
<tr>
|
||||||
</svg>
|
<th scope="col" class="text-center" style="width: 3%;">
|
||||||
</div>
|
<input type="checkbox" id="select-all" class="form-check-input">
|
||||||
<h3 class="card-title mb-0">Формирование таблицы для Кубсатов</h3>
|
</th>
|
||||||
|
<th scope="col">Имя</th>
|
||||||
|
<th scope="col">Спутник</th>
|
||||||
|
<th scope="col">Част, МГц</th>
|
||||||
|
<th scope="col">Полоса, МГц</th>
|
||||||
|
<th scope="col">Поляр</th>
|
||||||
|
<th scope="col">Сим. v</th>
|
||||||
|
<th scope="col">Модул</th>
|
||||||
|
<th scope="col">ОСШ</th>
|
||||||
|
<th scope="col">Геолокация</th>
|
||||||
|
<th scope="col">Кубсат</th>
|
||||||
|
<th scope="col">Опер. отд</th>
|
||||||
|
<th scope="col">Гео-куб, км</th>
|
||||||
|
<th scope="col">Гео-опер, км</th>
|
||||||
|
<th scope="col">Куб-опер, км</th>
|
||||||
|
</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>{{ item.name }}</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_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>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="15" class="text-center py-4">
|
||||||
|
{% if selected_satellite_id %}
|
||||||
|
Нет данных для выбранных фильтров
|
||||||
|
{% else %}
|
||||||
|
Пожалуйста, выберите спутник для отображения данных
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<p class="card-text">Добавьте новое событие с помощью выбора спутника и загрузки файла данных.</p>
|
|
||||||
<a href="{% url 'kubsat_excel' %}" class="btn btn-success">
|
<!-- Pagination -->
|
||||||
Добавить событие
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
</a>
|
<nav aria-label="Page navigation" class="px-3 pb-3">
|
||||||
|
<ul class="pagination justify-content-center">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page=1">Первая</a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.previous_page_number }}">Предыдущая</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for num in page_obj.paginator.page_range %}
|
||||||
|
{% if page_obj.number == num %}
|
||||||
|
<li class="page-item active">
|
||||||
|
<span class="page-link">{{ num }}</span>
|
||||||
|
</li>
|
||||||
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ num }}">{{ num }}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.next_page_number }}">Следующая</a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.paginator.num_pages }}">Последняя</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Pagination Info -->
|
||||||
|
{% if page_obj %}
|
||||||
|
<div class="px-3 pb-3 d-flex justify-content-between align-items-center">
|
||||||
|
<div>Показано {{ page_obj.start_index }}-{{ page_obj.end_index }} из {{ page_obj.paginator.count }} записей</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- JavaScript for checkbox functionality and filters -->
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Select/Deselect all checkboxes
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update select all checkbox state based on individual selections
|
||||||
|
itemCheckboxes.forEach(checkbox => {
|
||||||
|
checkbox.addEventListener('change', function() {
|
||||||
|
const allChecked = Array.from(itemCheckboxes).every(cb => cb.checked);
|
||||||
|
selectAllCheckbox.checked = allChecked;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle multiple selection for modulations and polarizations
|
||||||
|
const modulationSelect = document.querySelector('select[name="modulation"]');
|
||||||
|
const polarizationSelect = document.querySelector('select[name="polarization"]');
|
||||||
|
|
||||||
|
// Prevent deselecting all options when Ctrl+click is used
|
||||||
|
if (modulationSelect) {
|
||||||
|
modulationSelect.addEventListener('change', function(e) {
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (polarizationSelect) {
|
||||||
|
polarizationSelect.addEventListener('change', function(e) {
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setupRadioLikeCheckboxes('has_kupsat');
|
||||||
|
setupRadioLikeCheckboxes('has_valid');
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to update the page when satellite selection changes
|
||||||
|
function updateSatelliteSelection() {
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// Remove search parameter if empty
|
||||||
|
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() {
|
||||||
|
// Clear only the search input in the toolbar
|
||||||
|
document.getElementById('toolbar-search').value = '';
|
||||||
|
// Submit the form to update the results
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listener to satellite select for immediate update
|
||||||
|
const satelliteSelect = document.querySelector('select[name="satellite_id"]');
|
||||||
|
if (satelliteSelect) {
|
||||||
|
satelliteSelect.addEventListener('change', function() {
|
||||||
|
updateSatelliteSelection();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
422
dbapp/mainapp/templates/mainapp/objitem_list.html
Normal file
422
dbapp/mainapp/templates/mainapp/objitem_list.html
Normal file
@@ -0,0 +1,422 @@
|
|||||||
|
{% extends 'mainapp/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Список объектов{% 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">
|
||||||
|
<div style="min-width: 300px; flex-grow: 1;">
|
||||||
|
<label for="toolbar-search" class="form-label mb-0">Поиск:</label>
|
||||||
|
<input type="text" id="toolbar-search" class="form-control" placeholder="Поиск по имени, местоположению..." value="{{ search_query|default:'' }}">
|
||||||
|
</div>
|
||||||
|
<div class="ms-auto">
|
||||||
|
<button type="button" class="btn btn-outline-primary" onclick="performSearch()">Найти</button>
|
||||||
|
<button type="button" class="btn btn-outline-secondary" onclick="clearSearch()">Очистить</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3">
|
||||||
|
<!-- Filters Sidebar - Made narrower -->
|
||||||
|
<div class="col-md-2">
|
||||||
|
<div class="card h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Фильтры</h5>
|
||||||
|
<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="4">
|
||||||
|
{% 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>
|
||||||
|
|
||||||
|
<!-- Removed old search input as it's now in the toolbar -->
|
||||||
|
|
||||||
|
<!-- 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="4">
|
||||||
|
{% 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>
|
||||||
|
|
||||||
|
<!-- Items Per Page -->
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="items-per-page" class="form-label">Элементов:</label>
|
||||||
|
<select name="items_per_page" id="items-per-page" class="form-select form-select-sm" onchange="document.getElementById('filter-form').submit();">
|
||||||
|
{% for option in available_items_per_page %}
|
||||||
|
<option value="{{ option }}" {% if option == items_per_page %}selected{% endif %}>
|
||||||
|
{{ option }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</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-10">
|
||||||
|
<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>
|
||||||
|
<th scope="col">Имя</th>
|
||||||
|
<th scope="col">Спутник</th>
|
||||||
|
<th scope="col">Част, МГц</th>
|
||||||
|
<th scope="col">Полоса, МГц</th>
|
||||||
|
<th scope="col">Поляр</th>
|
||||||
|
<th scope="col">Сим. v</th>
|
||||||
|
<th scope="col">Модул</th>
|
||||||
|
<th scope="col">ОСШ</th>
|
||||||
|
<th scope="col">Геолокация</th>
|
||||||
|
<th scope="col">Кубсат</th>
|
||||||
|
<th scope="col">Опер. отд</th>
|
||||||
|
<th scope="col">Гео-куб, км</th>
|
||||||
|
<th scope="col">Гео-опер, км</th>
|
||||||
|
<th scope="col">Куб-опер, км</th>
|
||||||
|
</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>{{ item.name }}</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_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>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="15" class="text-center py-4">
|
||||||
|
{% if selected_satellite_id %}
|
||||||
|
Нет данных для выбранных фильтров
|
||||||
|
{% else %}
|
||||||
|
Пожалуйста, выберите спутник для отображения данных
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
|
<nav aria-label="Page navigation" class="px-3 pb-3">
|
||||||
|
<ul class="pagination justify-content-center">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page=1">Первая</a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.previous_page_number }}">Предыдущая</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for num in page_obj.paginator.page_range %}
|
||||||
|
{% if page_obj.number == num %}
|
||||||
|
<li class="page-item active">
|
||||||
|
<span class="page-link">{{ num }}</span>
|
||||||
|
</li>
|
||||||
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ num }}">{{ num }}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.next_page_number }}">Следующая</a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.paginator.num_pages }}">Последняя</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Pagination Info -->
|
||||||
|
{% if page_obj %}
|
||||||
|
<div class="px-3 pb-3 d-flex justify-content-between align-items-center">
|
||||||
|
<div>Показано {{ page_obj.start_index }}-{{ page_obj.end_index }} из {{ page_obj.paginator.count }} записей</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- JavaScript for checkbox functionality and filters -->
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Select/Deselect all checkboxes
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update select all checkbox state based on individual selections
|
||||||
|
itemCheckboxes.forEach(checkbox => {
|
||||||
|
checkbox.addEventListener('change', function() {
|
||||||
|
const allChecked = Array.from(itemCheckboxes).every(cb => cb.checked);
|
||||||
|
selectAllCheckbox.checked = allChecked;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle multiple selection for modulations and polarizations
|
||||||
|
const modulationSelect = document.querySelector('select[name="modulation"]');
|
||||||
|
const polarizationSelect = document.querySelector('select[name="polarization"]');
|
||||||
|
|
||||||
|
// Prevent deselecting all options when Ctrl+click is used
|
||||||
|
if (modulationSelect) {
|
||||||
|
modulationSelect.addEventListener('change', function(e) {
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (polarizationSelect) {
|
||||||
|
polarizationSelect.addEventListener('change', function(e) {
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setupRadioLikeCheckboxes('has_kupsat');
|
||||||
|
setupRadioLikeCheckboxes('has_valid');
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to update the page when satellite selection changes
|
||||||
|
function updateSatelliteSelection() {
|
||||||
|
document.getElementById('filter-form').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// Remove search parameter if empty
|
||||||
|
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() {
|
||||||
|
// Clear only the search input in the toolbar
|
||||||
|
document.getElementById('toolbar-search').value = '';
|
||||||
|
// Submit the form to update the results
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listener to satellite select for immediate update
|
||||||
|
const satelliteSelect = document.querySelector('select[name="satellite_id"]');
|
||||||
|
if (satelliteSelect) {
|
||||||
|
satelliteSelect.addEventListener('change', function() {
|
||||||
|
updateSatelliteSelection();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -5,7 +5,8 @@ from . import views
|
|||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.HomePageView.as_view(), name='home'),
|
path('', views.ObjItemListView.as_view(), name='home'), # Make objitems the main page
|
||||||
|
path('actions/', views.HomePageView.as_view(), name='actions'), # Move actions to a separate page
|
||||||
path('excel-data', views.LoadExcelDataView.as_view(), name='load_excel_data'),
|
path('excel-data', views.LoadExcelDataView.as_view(), name='load_excel_data'),
|
||||||
path('satellites', views.AddSatellitesView.as_view(), name='add_sats'),
|
path('satellites', views.AddSatellitesView.as_view(), name='add_sats'),
|
||||||
path('api/locations/<int:sat_id>/geojson/', views.GetLocationsView.as_view(), name='locations_by_id'),
|
path('api/locations/<int:sat_id>/geojson/', views.GetLocationsView.as_view(), name='locations_by_id'),
|
||||||
@@ -16,6 +17,7 @@ urlpatterns = [
|
|||||||
path('vch-upload/', views.UploadVchLoadView.as_view(), name='vch_load'),
|
path('vch-upload/', views.UploadVchLoadView.as_view(), name='vch_load'),
|
||||||
path('vch-link/', views.LinkVchSigmaView.as_view(), name='link_vch_sigma'),
|
path('vch-link/', views.LinkVchSigmaView.as_view(), name='link_vch_sigma'),
|
||||||
path('kubsat-excel/', views.ProcessKubsatView.as_view(), name='kubsat_excel'),
|
path('kubsat-excel/', views.ProcessKubsatView.as_view(), name='kubsat_excel'),
|
||||||
|
path('objitems/', views.ObjItemListView.as_view(), name='objitem_list'),
|
||||||
# path('upload/', views.upload_file, name='upload_file'),
|
# path('upload/', views.upload_file, name='upload_file'),
|
||||||
|
|
||||||
]
|
]
|
||||||
@@ -7,6 +7,7 @@ from django.utils.decorators import method_decorator
|
|||||||
from django.views import View
|
from django.views import View
|
||||||
from django.views.generic import TemplateView, FormView
|
from django.views.generic import TemplateView, FormView
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||||
|
from django.db import models
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from .utils import (
|
from .utils import (
|
||||||
fill_data_from_df,
|
fill_data_from_df,
|
||||||
@@ -58,7 +59,7 @@ class AddTranspondersView(FormView):
|
|||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
|
|
||||||
class HomePageView(TemplateView):
|
class HomePageView(TemplateView):
|
||||||
template_name = 'mainapp/home.html'
|
template_name = 'mainapp/actions.html'
|
||||||
|
|
||||||
|
|
||||||
class LoadExcelDataView(FormView):
|
class LoadExcelDataView(FormView):
|
||||||
@@ -89,6 +90,9 @@ class LoadExcelDataView(FormView):
|
|||||||
|
|
||||||
|
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
|
from django.core.paginator import Paginator
|
||||||
|
from django.db.models import Prefetch
|
||||||
|
from .models import Satellite, ObjItem, Parameter, Geo
|
||||||
|
|
||||||
class GetLocationsView(View):
|
class GetLocationsView(View):
|
||||||
def get(self, request, sat_id):
|
def get(self, request, sat_id):
|
||||||
@@ -273,3 +277,272 @@ class ProcessKubsatView(FormView):
|
|||||||
def form_invalid(self, form):
|
def form_invalid(self, form):
|
||||||
messages.error(self.request, "Форма заполнена некорректно.")
|
messages.error(self.request, "Форма заполнена некорректно.")
|
||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
|
|
||||||
|
class ObjItemListView(View):
|
||||||
|
def get(self, request):
|
||||||
|
# Get satellites that have associated objects, sorted alphabetically
|
||||||
|
satellites = Satellite.objects.filter(parameters__objitems__isnull=False).distinct().order_by('name')
|
||||||
|
|
||||||
|
# Get selected satellite from query parameters
|
||||||
|
selected_sat_id = request.GET.get('satellite_id')
|
||||||
|
page_number = request.GET.get('page', 1)
|
||||||
|
items_per_page = request.GET.get('items_per_page', '25') # Default to 25 items per page
|
||||||
|
|
||||||
|
# Get filter parameters
|
||||||
|
freq_min = request.GET.get('freq_min')
|
||||||
|
freq_max = request.GET.get('freq_max')
|
||||||
|
range_min = request.GET.get('range_min')
|
||||||
|
range_max = request.GET.get('range_max')
|
||||||
|
snr_min = request.GET.get('snr_min')
|
||||||
|
snr_max = request.GET.get('snr_max')
|
||||||
|
bod_min = request.GET.get('bod_min')
|
||||||
|
bod_max = request.GET.get('bod_max')
|
||||||
|
search_query = request.GET.get('search')
|
||||||
|
selected_modulations = request.GET.getlist('modulation')
|
||||||
|
selected_polarizations = request.GET.getlist('polarization')
|
||||||
|
selected_satellites = request.GET.getlist('satellite_id')
|
||||||
|
has_kupsat = request.GET.get('has_kupsat')
|
||||||
|
has_valid = request.GET.get('has_valid')
|
||||||
|
|
||||||
|
try:
|
||||||
|
items_per_page = int(items_per_page)
|
||||||
|
except ValueError:
|
||||||
|
items_per_page = 25
|
||||||
|
|
||||||
|
# Only filter objects by selected satellite if provided (no data shown by default)
|
||||||
|
objects = ObjItem.objects.none() # Initially empty
|
||||||
|
|
||||||
|
if selected_satellites or selected_sat_id:
|
||||||
|
# Handle single satellite from old parameter or multiple from new parameter
|
||||||
|
if selected_sat_id and not selected_satellites:
|
||||||
|
# For backward compatibility - if only single satellite parameter is provided
|
||||||
|
try:
|
||||||
|
selected_sat_id_single = int(selected_sat_id)
|
||||||
|
selected_satellites = [selected_sat_id_single]
|
||||||
|
except ValueError:
|
||||||
|
selected_satellites = []
|
||||||
|
|
||||||
|
# Start with the basic filter if any satellites are selected
|
||||||
|
if selected_satellites:
|
||||||
|
# Start with the basic filter
|
||||||
|
objects = ObjItem.objects.select_related(
|
||||||
|
'id_user_add__user',
|
||||||
|
'geo_obj'
|
||||||
|
).prefetch_related(
|
||||||
|
'parameters_obj__id_satellite',
|
||||||
|
'parameters_obj__polarization',
|
||||||
|
'parameters_obj__modulation',
|
||||||
|
'parameters_obj__standard'
|
||||||
|
).filter(parameters_obj__id_satellite_id__in=selected_satellites)
|
||||||
|
else:
|
||||||
|
# If no satellites are selected, start with all objects
|
||||||
|
objects = ObjItem.objects.select_related(
|
||||||
|
'id_user_add__user',
|
||||||
|
'geo_obj'
|
||||||
|
).prefetch_related(
|
||||||
|
'parameters_obj__id_satellite',
|
||||||
|
'parameters_obj__polarization',
|
||||||
|
'parameters_obj__modulation',
|
||||||
|
'parameters_obj__standard'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Apply additional filters
|
||||||
|
# Frequency filter
|
||||||
|
if freq_min is not None and freq_min.strip() != '':
|
||||||
|
try:
|
||||||
|
freq_min_val = float(freq_min)
|
||||||
|
objects = objects.filter(parameters_obj__frequency__gte=freq_min_val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if freq_max is not None and freq_max.strip() != '':
|
||||||
|
try:
|
||||||
|
freq_max_val = float(freq_max)
|
||||||
|
objects = objects.filter(parameters_obj__frequency__lte=freq_max_val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Range filter
|
||||||
|
if range_min is not None and range_min.strip() != '':
|
||||||
|
try:
|
||||||
|
range_min_val = float(range_min)
|
||||||
|
objects = objects.filter(parameters_obj__freq_range__gte=range_min_val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if range_max is not None and range_max.strip() != '':
|
||||||
|
try:
|
||||||
|
range_max_val = float(range_max)
|
||||||
|
objects = objects.filter(parameters_obj__freq_range__lte=range_max_val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# SNR filter
|
||||||
|
if snr_min is not None and snr_min.strip() != '':
|
||||||
|
try:
|
||||||
|
snr_min_val = float(snr_min)
|
||||||
|
objects = objects.filter(parameters_obj__snr__gte=snr_min_val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if snr_max is not None and snr_max.strip() != '':
|
||||||
|
try:
|
||||||
|
snr_max_val = float(snr_max)
|
||||||
|
objects = objects.filter(parameters_obj__snr__lte=snr_max_val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Symbol rate filter
|
||||||
|
if bod_min is not None and bod_min.strip() != '':
|
||||||
|
try:
|
||||||
|
bod_min_val = float(bod_min)
|
||||||
|
objects = objects.filter(parameters_obj__bod_velocity__gte=bod_min_val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if bod_max is not None and bod_max.strip() != '':
|
||||||
|
try:
|
||||||
|
bod_max_val = float(bod_max)
|
||||||
|
objects = objects.filter(parameters_obj__bod_velocity__lte=bod_max_val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Modulation filter
|
||||||
|
if selected_modulations:
|
||||||
|
objects = objects.filter(parameters_obj__modulation__id__in=selected_modulations)
|
||||||
|
|
||||||
|
# Polarization filter
|
||||||
|
if selected_polarizations:
|
||||||
|
objects = objects.filter(parameters_obj__polarization__id__in=selected_polarizations)
|
||||||
|
|
||||||
|
# Kupsat coords filter
|
||||||
|
if has_kupsat == '1': # has coords
|
||||||
|
objects = objects.filter(geo_obj__coords_kupsat__isnull=False)
|
||||||
|
elif has_kupsat == '0': # no coords
|
||||||
|
objects = objects.filter(geo_obj__coords_kupsat__isnull=True)
|
||||||
|
|
||||||
|
# Valid coords filter
|
||||||
|
if has_valid == '1': # has coords
|
||||||
|
objects = objects.filter(geo_obj__coords_valid__isnull=False)
|
||||||
|
elif has_valid == '0': # no coords
|
||||||
|
objects = objects.filter(geo_obj__coords_valid__isnull=True)
|
||||||
|
|
||||||
|
# Add search functionality - search only in name and location fields to avoid spatial lookup errors
|
||||||
|
if search_query:
|
||||||
|
search_query = search_query.strip()
|
||||||
|
if search_query:
|
||||||
|
# Search in name and location fields to match displayed text
|
||||||
|
objects = objects.filter(
|
||||||
|
models.Q(name__icontains=search_query) |
|
||||||
|
models.Q(geo_obj__location__icontains=search_query)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
selected_sat_id = None
|
||||||
|
|
||||||
|
# Add pagination
|
||||||
|
paginator = Paginator(objects, items_per_page)
|
||||||
|
page_obj = paginator.get_page(page_number)
|
||||||
|
|
||||||
|
# Prepare the data to include calculated fields for the template
|
||||||
|
processed_objects = []
|
||||||
|
for obj in page_obj:
|
||||||
|
# Get the first parameter
|
||||||
|
param = obj.parameters_obj.first() if obj.parameters_obj.exists() else None
|
||||||
|
|
||||||
|
# Process geo coordinates
|
||||||
|
geo_coords = "-"
|
||||||
|
kupsat_coords = "-"
|
||||||
|
valid_coords = "-"
|
||||||
|
distance_geo_kup = "-"
|
||||||
|
distance_geo_valid = "-"
|
||||||
|
distance_kup_valid = "-"
|
||||||
|
|
||||||
|
if obj.geo_obj:
|
||||||
|
# Format geo coordinates
|
||||||
|
if obj.geo_obj.coords:
|
||||||
|
longitude = obj.geo_obj.coords.coords[0]
|
||||||
|
latitude = obj.geo_obj.coords.coords[1]
|
||||||
|
lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
|
||||||
|
lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
|
||||||
|
geo_coords = f"{lat} {lon}"
|
||||||
|
|
||||||
|
# Format kupsat coordinates
|
||||||
|
if obj.geo_obj.coords_kupsat:
|
||||||
|
longitude = obj.geo_obj.coords_kupsat.coords[0]
|
||||||
|
latitude = obj.geo_obj.coords_kupsat.coords[1]
|
||||||
|
lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
|
||||||
|
lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
|
||||||
|
kupsat_coords = f"{lat} {lon}"
|
||||||
|
elif obj.geo_obj.coords_kupsat is not None:
|
||||||
|
kupsat_coords = "-"
|
||||||
|
|
||||||
|
# Format valid coordinates
|
||||||
|
if obj.geo_obj.coords_valid:
|
||||||
|
longitude = obj.geo_obj.coords_valid.coords[0]
|
||||||
|
latitude = obj.geo_obj.coords_valid.coords[1]
|
||||||
|
lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
|
||||||
|
lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
|
||||||
|
valid_coords = f"{lat} {lon}"
|
||||||
|
elif obj.geo_obj.coords_valid is not None:
|
||||||
|
valid_coords = "-"
|
||||||
|
|
||||||
|
# Format distances
|
||||||
|
if obj.geo_obj.distance_coords_kup is not None:
|
||||||
|
distance_geo_kup = f"{obj.geo_obj.distance_coords_kup:.3f}"
|
||||||
|
|
||||||
|
if obj.geo_obj.distance_coords_valid is not None:
|
||||||
|
distance_geo_valid = f"{obj.geo_obj.distance_coords_valid:.3f}"
|
||||||
|
|
||||||
|
if obj.geo_obj.distance_kup_valid is not None:
|
||||||
|
distance_kup_valid = f"{obj.geo_obj.distance_kup_valid:.3f}"
|
||||||
|
|
||||||
|
processed_objects.append({
|
||||||
|
'id': obj.id,
|
||||||
|
'name': obj.name or "-",
|
||||||
|
'satellite_name': param.id_satellite.name if param and param.id_satellite else "-",
|
||||||
|
'frequency': f"{param.frequency:.3f}" if param and param.frequency else "-",
|
||||||
|
'freq_range': f"{param.freq_range:.3f}" if param and param.freq_range else "-",
|
||||||
|
'polarization': param.polarization.name if param and param.polarization else "-",
|
||||||
|
'bod_velocity': f"{param.bod_velocity:.3f}" if param and param.bod_velocity else "-",
|
||||||
|
'modulation': param.modulation.name if param and param.modulation else "-",
|
||||||
|
'snr': f"{param.snr:.3f}" if param and param.snr else "-",
|
||||||
|
'geo_coords': geo_coords,
|
||||||
|
'kupsat_coords': kupsat_coords,
|
||||||
|
'valid_coords': valid_coords,
|
||||||
|
'distance_geo_kup': distance_geo_kup,
|
||||||
|
'distance_geo_valid': distance_geo_valid,
|
||||||
|
'distance_kup_valid': distance_kup_valid,
|
||||||
|
'obj': obj
|
||||||
|
})
|
||||||
|
|
||||||
|
# Get all modulations and polarizations for filter dropdowns
|
||||||
|
from .models import Modulation, Polarization
|
||||||
|
modulations = Modulation.objects.all()
|
||||||
|
polarizations = Polarization.objects.all()
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'satellites': satellites,
|
||||||
|
'selected_satellite_id': selected_sat_id,
|
||||||
|
'page_obj': page_obj,
|
||||||
|
'processed_objects': processed_objects,
|
||||||
|
'items_per_page': items_per_page,
|
||||||
|
'available_items_per_page': [10, 25, 50, 100],
|
||||||
|
# Filter values
|
||||||
|
'freq_min': freq_min,
|
||||||
|
'freq_max': freq_max,
|
||||||
|
'range_min': range_min,
|
||||||
|
'range_max': range_max,
|
||||||
|
'snr_min': snr_min,
|
||||||
|
'snr_max': snr_max,
|
||||||
|
'bod_min': bod_min,
|
||||||
|
'bod_max': bod_max,
|
||||||
|
'search_query': search_query,
|
||||||
|
'selected_modulations': [int(x) for x in selected_modulations if x.isdigit()],
|
||||||
|
'selected_polarizations': [int(x) for x in selected_polarizations if x.isdigit()],
|
||||||
|
'selected_satellites': [int(x) for x in selected_satellites if x.isdigit()],
|
||||||
|
'has_kupsat': has_kupsat,
|
||||||
|
'has_valid': has_valid,
|
||||||
|
# For filter dropdowns
|
||||||
|
'modulations': modulations,
|
||||||
|
'polarizations': polarizations,
|
||||||
|
# Enable full width layout
|
||||||
|
'full_width_page': True,
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, 'mainapp/objitem_list.html', context)
|
||||||
Reference in New Issue
Block a user