484 lines
26 KiB
HTML
484 lines
26 KiB
HTML
{% extends 'mainapp/base.html' %}
|
||
{% load static %}
|
||
|
||
{% block title %}Главная страница{% endblock %}
|
||
|
||
{% block extra_css %}
|
||
<style>
|
||
.filter-section {
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.filter-group {
|
||
background: white;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 6px;
|
||
padding: 15px;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.filter-group-title {
|
||
font-weight: 600;
|
||
color: #495057;
|
||
margin-bottom: 10px;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
.conditional-filters {
|
||
margin-top: 15px;
|
||
padding-top: 15px;
|
||
border-top: 1px solid #e9ecef;
|
||
}
|
||
|
||
.table-container {
|
||
display: none;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.table-container.show {
|
||
display: block;
|
||
}
|
||
|
||
.btn-generate {
|
||
font-size: 1.1rem;
|
||
padding: 12px 40px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.filter-badge {
|
||
display: inline-block;
|
||
padding: 4px 10px;
|
||
background: #007bff;
|
||
color: white;
|
||
border-radius: 12px;
|
||
font-size: 0.85rem;
|
||
margin: 2px;
|
||
}
|
||
|
||
.active-filters {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.mark-badge {
|
||
display: inline-block;
|
||
padding: 2px 8px;
|
||
border-radius: 4px;
|
||
font-size: 0.8rem;
|
||
margin: 2px 0;
|
||
}
|
||
|
||
.mark-present {
|
||
background: #28a745;
|
||
color: white;
|
||
}
|
||
|
||
.mark-absent {
|
||
background: #dc3545;
|
||
color: white;
|
||
}
|
||
</style>
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="container-fluid px-4 py-3">
|
||
<h2 class="mb-4">Главная страница - Динамический отчёт</h2>
|
||
|
||
<!-- Фильтры -->
|
||
<div class="filter-section">
|
||
<form method="get" id="filter-form">
|
||
<div class="row">
|
||
<!-- Основной выбор: Объекти или Объекты -->
|
||
<div class="col-12">
|
||
<div class="filter-group">
|
||
<div class="filter-group-title">1. Тип отображения</div>
|
||
<div class="btn-group w-100" role="group">
|
||
<input type="radio" class="btn-check" name="display_mode" id="mode_sources" value="sources"
|
||
{% if display_mode == 'sources' %}checked{% endif %} onchange="updateConditionalFilters()">
|
||
<label class="btn btn-outline-primary" for="mode_sources">Объекти (Source)</label>
|
||
|
||
<input type="radio" class="btn-check" name="display_mode" id="mode_objitems" value="objitems"
|
||
{% if display_mode == 'objitems' %}checked{% endif %} onchange="updateConditionalFilters()">
|
||
<label class="btn btn-outline-primary" for="mode_objitems">Объекты (ObjItem)</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<!-- Общие фильтры -->
|
||
<div class="col-md-6">
|
||
<div class="filter-group">
|
||
<div class="filter-group-title">2. Общие фильтры</div>
|
||
|
||
<!-- Спутники -->
|
||
<div class="mb-3">
|
||
<label class="form-label">Спутники:</label>
|
||
<div class="d-flex gap-2 mb-2">
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="selectAll('satellite_id', true)">Все</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="selectAll('satellite_id', false)">Снять</button>
|
||
</div>
|
||
<select name="satellite_id" class="form-select form-select-sm" multiple size="5">
|
||
{% for sat in satellites %}
|
||
<option value="{{ sat.id }}" {% if sat.id in selected_satellites %}selected{% endif %}>
|
||
{{ sat.name }}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Условные фильтры (зависят от типа отображения) -->
|
||
<div class="col-md-6">
|
||
<!-- Фильтры для Объектов -->
|
||
<div class="filter-group" id="sources-filters" style="display: none;">
|
||
<div class="filter-group-title">3. Фильтры для Объектов</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Усреднённые координаты:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_coords_average" id="avg_all" value="" {% if not has_coords_average %}checked{% endif %}>
|
||
<label class="form-check-label" for="avg_all">Все</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_coords_average" id="avg_yes" value="1" {% if has_coords_average == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="avg_yes">Есть</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_coords_average" id="avg_no" value="0" {% if has_coords_average == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="avg_no">Нет</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Координаты Кубсата:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_kupsat" id="kup_all" value="" {% if not has_kupsat %}checked{% endif %}>
|
||
<label class="form-check-label" for="kup_all">Все</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_kupsat" id="kup_yes" value="1" {% if has_kupsat == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="kup_yes">Есть</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_kupsat" id="kup_no" value="0" {% if has_kupsat == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="kup_no">Нет</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Координаты оперативников:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_valid" id="val_all" value="" {% if not has_valid %}checked{% endif %}>
|
||
<label class="form-check-label" for="val_all">Все</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_valid" id="val_yes" value="1" {% if has_valid == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="val_yes">Есть</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_valid" id="val_no" value="0" {% if has_valid == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="val_no">Нет</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Справочные координаты:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_reference" id="ref_all" value="" {% if not has_reference %}checked{% endif %}>
|
||
<label class="form-check-label" for="ref_all">Все</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_reference" id="ref_yes" value="1" {% if has_reference == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="ref_yes">Есть</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_reference" id="ref_no" value="0" {% if has_reference == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="ref_no">Нет</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Наличие сигнала для объектов -->
|
||
<div class="conditional-filters">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">Отображать наличие сигнала:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="checkbox" name="show_marks" id="marks_src" value="1"
|
||
{% if show_marks == '1' %}checked{% endif %} onchange="toggleMarksFilters()">
|
||
<label class="form-check-label" for="marks_src">Да</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="marks-additional-filters-src" style="{% if show_marks != '1' %}display:none;{% endif %}">
|
||
<div class="mb-3">
|
||
<label class="form-label">Период отметок:</label>
|
||
<input type="datetime-local" name="marks_date_from" class="form-control form-control-sm mb-1" value="{{ marks_date_from }}">
|
||
<input type="datetime-local" name="marks_date_to" class="form-control form-control-sm" value="{{ marks_date_to }}">
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Статус отметок:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="marks_status" id="marks_all_src" value="" {% if not marks_status %}checked{% endif %}>
|
||
<label class="form-check-label" for="marks_all_src">Все</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="marks_status" id="marks_present_src" value="present" {% if marks_status == 'present' %}checked{% endif %}>
|
||
<label class="form-check-label" for="marks_present_src">✓ Есть</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="marks_status" id="marks_absent_src" value="absent" {% if marks_status == 'absent' %}checked{% endif %}>
|
||
<label class="form-check-label" for="marks_absent_src">✗ Нет</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Фильтры для Объектов -->
|
||
<div class="filter-group" id="objitems-filters" style="display: none;">
|
||
<div class="filter-group-title">3. Фильтры для Объектов</div>
|
||
|
||
<!-- Дата геолокации -->
|
||
<div class="mb-3">
|
||
<label class="form-label">Дата геолокации:</label>
|
||
<input type="date" name="date_from" class="form-control form-control-sm mb-1" value="{{ date_from }}">
|
||
<input type="date" name="date_to" class="form-control form-control-sm" value="{{ date_to }}">
|
||
</div>
|
||
|
||
<!-- Частота -->
|
||
<div class="mb-3">
|
||
<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 }}">
|
||
<input type="number" step="0.001" name="freq_max" class="form-control form-control-sm" placeholder="До" value="{{ freq_max }}">
|
||
</div>
|
||
|
||
<!-- Полоса -->
|
||
<div class="mb-3">
|
||
<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 }}">
|
||
<input type="number" step="0.001" name="range_max" class="form-control form-control-sm" placeholder="До" value="{{ range_max }}">
|
||
</div>
|
||
|
||
<!-- Модуляция -->
|
||
<div class="mb-3">
|
||
<label class="form-label">Модуляция:</label>
|
||
<div class="d-flex gap-2 mb-2">
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="selectAll('modulation', true)">Все</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="selectAll('modulation', false)">Снять</button>
|
||
</div>
|
||
<select name="modulation" class="form-select form-select-sm" 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>
|
||
|
||
<!-- Поляризация -->
|
||
<div class="mb-3">
|
||
<label class="form-label">Поляризация:</label>
|
||
<div class="d-flex gap-2 mb-2">
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="selectAll('polarization', true)">Все</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="selectAll('polarization', false)">Снять</button>
|
||
</div>
|
||
<select name="polarization" class="form-select form-select-sm" 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>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Координаты геолокации:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_geo" id="geo_all" value="" {% if not has_geo %}checked{% endif %}>
|
||
<label class="form-check-label" for="geo_all">Все</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_geo" id="geo_yes" value="1" {% if has_geo == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="geo_yes">Есть</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_geo" id="geo_no" value="0" {% if has_geo == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="geo_no">Нет</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Связь с LyngSat:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_lyngsat" id="lyng_all" value="" {% if not has_lyngsat %}checked{% endif %}>
|
||
<label class="form-check-label" for="lyng_all">Все</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_lyngsat" id="lyng_yes" value="1" {% if has_lyngsat == '1' %}checked{% endif %}>
|
||
<label class="form-check-label" for="lyng_yes">Есть</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="has_lyngsat" id="lyng_no" value="0" {% if has_lyngsat == '0' %}checked{% endif %}>
|
||
<label class="form-check-label" for="lyng_no">Нет</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Наличие сигнала -->
|
||
<div class="conditional-filters">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">Отображать наличие сигнала:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="checkbox" name="show_marks" id="marks_obj" value="1"
|
||
{% if show_marks == '1' %}checked{% endif %} onchange="toggleMarksFilters()">
|
||
<label class="form-check-label" for="marks_obj">Да</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="marks-additional-filters" style="{% if show_marks != '1' %}display:none;{% endif %}">
|
||
<div class="mb-3">
|
||
<label class="form-label">Период отметок:</label>
|
||
<input type="datetime-local" name="marks_date_from" class="form-control form-control-sm mb-1" value="{{ marks_date_from }}">
|
||
<input type="datetime-local" name="marks_date_to" class="form-control form-control-sm" value="{{ marks_date_to }}">
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Статус отметок:</label>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="marks_status" id="marks_all" value="" {% if not marks_status %}checked{% endif %}>
|
||
<label class="form-check-label" for="marks_all">Все</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="marks_status" id="marks_present" value="present" {% if marks_status == 'present' %}checked{% endif %}>
|
||
<label class="form-check-label" for="marks_present">✓ Есть</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="marks_status" id="marks_absent" value="absent" {% if marks_status == 'absent' %}checked{% endif %}>
|
||
<label class="form-check-label" for="marks_absent">✗ Нет</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Настройки отображения -->
|
||
<div class="row">
|
||
<div class="col-12">
|
||
<div class="filter-group">
|
||
<div class="filter-group-title">4. Настройки отображения</div>
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<label class="form-label">Элементов на странице:</label>
|
||
<select name="items_per_page" class="form-select form-select-sm">
|
||
{% for option in available_items_per_page %}
|
||
<option value="{{ option }}" {% if option == items_per_page %}selected{% endif %}>{{ option }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Кнопки -->
|
||
<div class="row">
|
||
<div class="col-12 text-center">
|
||
<button type="submit" class="btn btn-primary btn-generate">
|
||
<i class="bi bi-table"></i> Сформировать таблицу
|
||
</button>
|
||
<a href="?" class="btn btn-secondary ms-2">Сбросить фильтры</a>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Активные фильтры -->
|
||
{% if page_obj %}
|
||
<div class="active-filters">
|
||
<strong>Активные фильтры:</strong>
|
||
{% if display_mode == 'sources' %}
|
||
<span class="filter-badge">Объекти</span>
|
||
{% else %}
|
||
<span class="filter-badge">Объекты</span>
|
||
{% endif %}
|
||
{% if selected_satellites %}
|
||
<span class="filter-badge">Спутники: {{ selected_satellites|length }}</span>
|
||
{% endif %}
|
||
{% if date_from or date_to %}
|
||
<span class="filter-badge">Дата геолокации</span>
|
||
{% endif %}
|
||
{% if show_marks == '1' %}
|
||
<span class="filter-badge">С наличие сигналами</span>
|
||
{% endif %}
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- Таблица (показывается только после генерации) -->
|
||
<div class="table-container {% if page_obj %}show{% endif %}">
|
||
{% if display_mode == 'sources' %}
|
||
{% include 'mainapp/components/_sources_table.html' %}
|
||
{% else %}
|
||
{% include 'mainapp/components/_objitems_table.html' %}
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block extra_js %}
|
||
<script>
|
||
function selectAll(name, select) {
|
||
const element = document.querySelector(`select[name="${name}"]`);
|
||
if (element) {
|
||
for (let option of element.options) {
|
||
option.selected = select;
|
||
}
|
||
}
|
||
}
|
||
|
||
function updateConditionalFilters() {
|
||
const mode = document.querySelector('input[name="display_mode"]:checked').value;
|
||
const sourcesFilters = document.getElementById('sources-filters');
|
||
const objitemsFilters = document.getElementById('objitems-filters');
|
||
|
||
if (mode === 'sources') {
|
||
sourcesFilters.style.display = 'block';
|
||
objitemsFilters.style.display = 'none';
|
||
} else {
|
||
sourcesFilters.style.display = 'none';
|
||
objitemsFilters.style.display = 'block';
|
||
}
|
||
}
|
||
|
||
function toggleMarksFilters() {
|
||
const mode = document.querySelector('input[name="display_mode"]:checked')?.value;
|
||
|
||
if (mode === 'sources') {
|
||
const checkbox = document.getElementById('marks_src');
|
||
const filters = document.getElementById('marks-additional-filters-src');
|
||
if (checkbox && filters) {
|
||
filters.style.display = checkbox.checked ? 'block' : 'none';
|
||
}
|
||
} else if (mode === 'objitems') {
|
||
const checkbox = document.getElementById('marks_obj');
|
||
const filters = document.getElementById('marks-additional-filters');
|
||
if (checkbox && filters) {
|
||
filters.style.display = checkbox.checked ? 'block' : 'none';
|
||
}
|
||
}
|
||
}
|
||
|
||
// Initialize on page load
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
updateConditionalFilters();
|
||
toggleMarksFilters();
|
||
});
|
||
</script>
|
||
{% endblock %}
|