Доделал статистику. Поправил разрешение lyngsat
This commit is contained in:
@@ -148,6 +148,10 @@ class LyngSatListView(LoginRequiredMixin, ListView):
|
||||
|
||||
# Action buttons HTML for toolbar component
|
||||
from django.urls import reverse
|
||||
from mainapp.permissions import has_permission
|
||||
|
||||
action_buttons_html = ''
|
||||
if has_permission(self.request.user, 'lyngsat_parse'):
|
||||
action_buttons_html = f'''
|
||||
<a href="{reverse('mainapp:fill_lyngsat_data')}" class="btn btn-secondary btn-sm" title="Заполнить данные Lyngsat">
|
||||
<i class="bi bi-cloud-download"></i> Добавить данные
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 5.2.7 on 2025-12-16 12:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mainapp', '0031_add_unique_date_location_constraint'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='sourcerequest',
|
||||
name='status',
|
||||
field=models.CharField(choices=[('planned', 'Запланировано'), ('canceled_gso', 'Отменено ГСО'), ('canceled_kub', 'Отменено МКА'), ('error_gso', 'Ошибка ГСО'), ('error_kub', 'Ошибка МКА'), ('wait_exec', 'Ожидают проведения'), ('suggested', 'Предложено'), ('gso_fault', 'Не проведены по вине ГСО'), ('conducted', 'Проведён'), ('successful', 'Успешно'), ('no_correlation', 'Нет корреляции'), ('no_signal', 'Нет сигнала в спектре'), ('unsuccessful', 'Неуспешно'), ('downloading', 'Скачивание'), ('processing', 'Обработка'), ('result_received', 'Результат получен')], db_index=True, default='planned', help_text='Текущий статус заявки', max_length=20, verbose_name='Статус'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sourcerequeststatushistory',
|
||||
name='new_status',
|
||||
field=models.CharField(choices=[('planned', 'Запланировано'), ('canceled_gso', 'Отменено ГСО'), ('canceled_kub', 'Отменено МКА'), ('error_gso', 'Ошибка ГСО'), ('error_kub', 'Ошибка МКА'), ('wait_exec', 'Ожидают проведения'), ('suggested', 'Предложено'), ('gso_fault', 'Не проведены по вине ГСО'), ('conducted', 'Проведён'), ('successful', 'Успешно'), ('no_correlation', 'Нет корреляции'), ('no_signal', 'Нет сигнала в спектре'), ('unsuccessful', 'Неуспешно'), ('downloading', 'Скачивание'), ('processing', 'Обработка'), ('result_received', 'Результат получен')], help_text='Статус после изменения', max_length=20, verbose_name='Новый статус'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sourcerequeststatushistory',
|
||||
name='old_status',
|
||||
field=models.CharField(choices=[('planned', 'Запланировано'), ('canceled_gso', 'Отменено ГСО'), ('canceled_kub', 'Отменено МКА'), ('error_gso', 'Ошибка ГСО'), ('error_kub', 'Ошибка МКА'), ('wait_exec', 'Ожидают проведения'), ('suggested', 'Предложено'), ('gso_fault', 'Не проведены по вине ГСО'), ('conducted', 'Проведён'), ('successful', 'Успешно'), ('no_correlation', 'Нет корреляции'), ('no_signal', 'Нет сигнала в спектре'), ('unsuccessful', 'Неуспешно'), ('downloading', 'Скачивание'), ('processing', 'Обработка'), ('result_received', 'Результат получен')], help_text='Статус до изменения', max_length=20, verbose_name='Старый статус'),
|
||||
),
|
||||
]
|
||||
@@ -16,6 +16,11 @@ class SourceRequest(models.Model):
|
||||
('planned', 'Запланировано'),
|
||||
('canceled_gso', 'Отменено ГСО'),
|
||||
('canceled_kub', 'Отменено МКА'),
|
||||
('error_gso', 'Ошибка ГСО'),
|
||||
('error_kub', 'Ошибка МКА'),
|
||||
('wait_exec', 'Ожидают проведения'),
|
||||
('suggested', 'Предложено'),
|
||||
('gso_fault', 'Не проведены по вине ГСО'),
|
||||
('conducted', 'Проведён'),
|
||||
('successful', 'Успешно'),
|
||||
('no_correlation', 'Нет корреляции'),
|
||||
|
||||
@@ -81,23 +81,17 @@
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="requestStatus" class="form-label">Статус</label>
|
||||
<select class="form-select" id="requestStatus" name="status">
|
||||
<option value="planned">Запланировано</option>
|
||||
<option value="conducted">Проведён</option>
|
||||
<option value="successful">Успешно</option>
|
||||
<option value="no_correlation">Нет корреляции</option>
|
||||
<option value="no_signal">Нет сигнала в спектре</option>
|
||||
<option value="unsuccessful">Неуспешно</option>
|
||||
<option value="downloading">Скачивание</option>
|
||||
<option value="processing">Обработка</option>
|
||||
<option value="result_received">Результат получен</option>
|
||||
{% for value, label in status_choices %}
|
||||
<option value="{{ value }}">{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="requestPriority" class="form-label">Приоритет</label>
|
||||
<select class="form-select" id="requestPriority" name="priority">
|
||||
<option value="low">Низкий</option>
|
||||
<option value="medium" selected>Средний</option>
|
||||
<option value="high">Высокий</option>
|
||||
{% for value, label in priority_choices %}
|
||||
<option value="{{ value }}" {% if value == 'medium' %}selected{% endif %}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -377,15 +377,9 @@
|
||||
onclick="selectAllOptions('request_status', false)">Снять</button>
|
||||
</div>
|
||||
<select name="request_status" class="form-select form-select-sm" multiple size="5">
|
||||
<option value="planned" {% if 'planned' in selected_request_statuses %}selected{% endif %}>Запланировано</option>
|
||||
<option value="conducted" {% if 'conducted' in selected_request_statuses %}selected{% endif %}>Проведён</option>
|
||||
<option value="successful" {% if 'successful' in selected_request_statuses %}selected{% endif %}>Успешно</option>
|
||||
<option value="no_correlation" {% if 'no_correlation' in selected_request_statuses %}selected{% endif %}>Нет корреляции</option>
|
||||
<option value="no_signal" {% if 'no_signal' in selected_request_statuses %}selected{% endif %}>Нет сигнала в спектре</option>
|
||||
<option value="unsuccessful" {% if 'unsuccessful' in selected_request_statuses %}selected{% endif %}>Неуспешно</option>
|
||||
<option value="downloading" {% if 'downloading' in selected_request_statuses %}selected{% endif %}>Скачивание</option>
|
||||
<option value="processing" {% if 'processing' in selected_request_statuses %}selected{% endif %}>Обработка</option>
|
||||
<option value="result_received" {% if 'result_received' in selected_request_statuses %}selected{% endif %}>Результат получен</option>
|
||||
{% for value, label in status_choices %}
|
||||
<option value="{{ value }}" {% if value in selected_request_statuses %}selected{% endif %}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -393,9 +387,9 @@
|
||||
<div class="mb-2">
|
||||
<label class="form-label small">Приоритет:</label>
|
||||
<select name="request_priority" class="form-select form-select-sm" multiple size="3">
|
||||
<option value="low" {% if 'low' in selected_request_priorities %}selected{% endif %}>Низкий</option>
|
||||
<option value="medium" {% if 'medium' in selected_request_priorities %}selected{% endif %}>Средний</option>
|
||||
<option value="high" {% if 'high' in selected_request_priorities %}selected{% endif %}>Высокий</option>
|
||||
{% for value, label in priority_choices %}
|
||||
<option value="{{ value }}" {% if value in selected_request_priorities %}selected{% endif %}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -2480,23 +2474,17 @@ function showTransponderModal(transponderId) {
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editRequestStatus" class="form-label">Статус</label>
|
||||
<select class="form-select" id="editRequestStatus" name="status">
|
||||
<option value="planned">Запланировано</option>
|
||||
<option value="conducted">Проведён</option>
|
||||
<option value="successful">Успешно</option>
|
||||
<option value="no_correlation">Нет корреляции</option>
|
||||
<option value="no_signal">Нет сигнала в спектре</option>
|
||||
<option value="unsuccessful">Неуспешно</option>
|
||||
<option value="downloading">Скачивание</option>
|
||||
<option value="processing">Обработка</option>
|
||||
<option value="result_received">Результат получен</option>
|
||||
{% for value, label in status_choices %}
|
||||
<option value="{{ value }}">{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editRequestPriority" class="form-label">Приоритет</label>
|
||||
<select class="form-select" id="editRequestPriority" name="priority">
|
||||
<option value="low">Низкий</option>
|
||||
<option value="medium" selected>Средний</option>
|
||||
<option value="high">Высокий</option>
|
||||
{% for value, label in priority_choices %}
|
||||
<option value="{{ value }}" {% if value == 'medium' %}selected{% endif %}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -558,86 +558,103 @@
|
||||
|
||||
<!-- Kubsat Statistics -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card border-secondary">
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<strong>Кубсаты</strong>
|
||||
<!-- 1. Запланировано -->
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100 border-primary">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<strong><i class="bi bi-calendar-check"></i> Запланировано</strong>
|
||||
<span class="badge bg-light text-primary float-end fs-6" id="kubsat-planned">{{ extended_stats.kubsat.planned_count }}</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row text-center">
|
||||
<div class="col-md-3 mb-3 mb-md-0">
|
||||
<div class="p-3 bg-light rounded">
|
||||
<div class="fs-3 fw-bold text-primary" id="kubsat-planned">{{ extended_stats.kubsat.planned_count }}</div>
|
||||
<div class="text-muted small">
|
||||
<i class="bi bi-calendar-check"></i> Запланировано
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-2 border-bottom">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-check-circle text-success"></i> Проведено:
|
||||
</span>
|
||||
<span class="badge bg-success" id="kubsat-conducted">{{ extended_stats.kubsat.conducted_count }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-2 border-bottom">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-x-circle text-danger"></i> Отменено (ГСО):
|
||||
</span>
|
||||
<span class="badge bg-danger" id="kubsat-canceled-gso">{{ extended_stats.kubsat.canceled_gso_count }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-2 border-bottom">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-x-circle text-warning"></i> Отменено (МКА):
|
||||
</span>
|
||||
<span class="badge bg-warning text-dark" id="kubsat-canceled-kub">{{ extended_stats.kubsat.canceled_kub_count }}</span>
|
||||
</div>
|
||||
<div class="col-md-3 mb-3 mb-md-0">
|
||||
<div class="p-3 bg-light rounded">
|
||||
<div class="fs-3 fw-bold text-success" id="kubsat-conducted">{{ extended_stats.kubsat.conducted_count }}</div>
|
||||
<div class="text-muted small">
|
||||
<i class="bi bi-check-circle"></i> Проведено
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-2 border-bottom">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-hourglass-split text-info"></i> Ожидают проведения:
|
||||
</span>
|
||||
<span class="badge bg-info" id="kubsat-wait-exec">{{ extended_stats.kubsat.wait_exec_count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mb-3 mb-md-0">
|
||||
<div class="p-3 bg-light rounded">
|
||||
<div class="fs-3 fw-bold text-danger" id="kubsat-canceled-gso">{{ extended_stats.kubsat.canceled_gso_count }}</div>
|
||||
<div class="text-muted small">
|
||||
<i class="bi bi-x-circle"></i> Отменено ГСО
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="p-3 bg-light rounded">
|
||||
<div class="fs-3 fw-bold text-warning" id="kubsat-canceled-kub">{{ extended_stats.kubsat.canceled_kub_count }}</div>
|
||||
<div class="text-muted small">
|
||||
<i class="bi bi-x-circle"></i> Отменено МКА
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-exclamation-triangle text-secondary"></i> Не проведены (вина ГСО):
|
||||
</span>
|
||||
<span class="badge bg-secondary" id="kubsat-gso-fault">{{ extended_stats.kubsat.gso_fault_count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Progress bar for Kubsat -->
|
||||
{% if extended_stats.kubsat.planned_count > 0 %}
|
||||
<div class="mt-4">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<small class="text-muted">Распределение статусов</small>
|
||||
<small class="text-muted">Всего: {{ extended_stats.kubsat.planned_count }}</small>
|
||||
<!-- 2. Проведено -->
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100 border-success">
|
||||
<div class="card-header bg-success text-white">
|
||||
<strong><i class="bi bi-check2-circle"></i> Проведено</strong>
|
||||
<span class="badge bg-light text-success float-end fs-6" id="kubsat-total-conducted">{{ extended_stats.kubsat.total_conducted_count }}</span>
|
||||
</div>
|
||||
<div class="progress" style="height: 25px;">
|
||||
{% with total=extended_stats.kubsat.planned_count conducted=extended_stats.kubsat.conducted_count canceled_gso=extended_stats.kubsat.canceled_gso_count canceled_kub=extended_stats.kubsat.canceled_kub_count %}
|
||||
{% if conducted > 0 %}
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
style="width: {% widthratio conducted total 100 %}%"
|
||||
title="Проведено: {{ conducted }}">
|
||||
{{ conducted }}
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-2 border-bottom">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-check-lg text-success"></i> Результат получен:
|
||||
</span>
|
||||
<span class="badge bg-success" id="kubsat-result-received">{{ extended_stats.kubsat.result_received_count }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if canceled_gso > 0 %}
|
||||
<div class="progress-bar bg-danger" role="progressbar"
|
||||
style="width: {% widthratio canceled_gso total 100 %}%"
|
||||
title="Отменено ГСО: {{ canceled_gso }}">
|
||||
{{ canceled_gso }}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-2 border-bottom">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-gear text-primary"></i> Обработка:
|
||||
</span>
|
||||
<span class="badge bg-primary" id="kubsat-processing">{{ extended_stats.kubsat.processing_count }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if canceled_kub > 0 %}
|
||||
<div class="progress-bar bg-warning text-dark" role="progressbar"
|
||||
style="width: {% widthratio canceled_kub total 100 %}%"
|
||||
title="Отменено МКА: {{ canceled_kub }}">
|
||||
{{ canceled_kub }}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-2 border-bottom">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-question-circle text-warning"></i> Нет корреляции:
|
||||
</span>
|
||||
<span class="badge bg-warning text-dark" id="kubsat-no-correlation">{{ extended_stats.kubsat.no_correlation_count }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-2 border-bottom">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-bug text-danger"></i> Ошибка ГСО:
|
||||
</span>
|
||||
<span class="badge bg-danger" id="kubsat-error-gso">{{ extended_stats.kubsat.error_gso_count }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center mt-2">
|
||||
<small class="me-3"><span class="badge bg-success">●</span> Проведено</small>
|
||||
<small class="me-3"><span class="badge bg-danger">●</span> Отменено ГСО</small>
|
||||
<small><span class="badge bg-warning text-dark">●</span> Отменено МКА</small>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-bug text-secondary"></i> Ошибка МКА:
|
||||
</span>
|
||||
<span class="badge bg-secondary" id="kubsat-error-kub">{{ extended_stats.kubsat.error_kub_count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. Предложено -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card border-info">
|
||||
<div class="card-body py-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span>
|
||||
<i class="bi bi-lightbulb text-info fs-5"></i>
|
||||
<strong class="ms-2">Предложено:</strong>
|
||||
</span>
|
||||
<span class="badge bg-info fs-5" id="kubsat-suggested">{{ extended_stats.kubsat.suggested_count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1631,21 +1648,31 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
document.getElementById('dv-new-coords').textContent = data.extended_stats.dv.new_coords;
|
||||
document.getElementById('dv-transfer-delta').textContent = data.extended_stats.dv.transfer_delta + ' МГц';
|
||||
|
||||
// Update Kubsat statistics
|
||||
// Update Kubsat statistics - Запланировано
|
||||
document.getElementById('kubsat-planned').textContent = data.extended_stats.kubsat.planned_count;
|
||||
document.getElementById('kubsat-conducted').textContent = data.extended_stats.kubsat.conducted_count;
|
||||
document.getElementById('kubsat-canceled-gso').textContent = data.extended_stats.kubsat.canceled_gso_count;
|
||||
document.getElementById('kubsat-canceled-kub').textContent = data.extended_stats.kubsat.canceled_kub_count;
|
||||
document.getElementById('kubsat-wait-exec').textContent = data.extended_stats.kubsat.wait_exec_count;
|
||||
document.getElementById('kubsat-gso-fault').textContent = data.extended_stats.kubsat.gso_fault_count;
|
||||
|
||||
// Update progress bar if exists
|
||||
updateKubsatProgressBar(data.extended_stats.kubsat);
|
||||
// Update Kubsat statistics - Проведено
|
||||
document.getElementById('kubsat-total-conducted').textContent = data.extended_stats.kubsat.total_conducted_count;
|
||||
document.getElementById('kubsat-result-received').textContent = data.extended_stats.kubsat.result_received_count;
|
||||
document.getElementById('kubsat-processing').textContent = data.extended_stats.kubsat.processing_count;
|
||||
document.getElementById('kubsat-no-correlation').textContent = data.extended_stats.kubsat.no_correlation_count;
|
||||
document.getElementById('kubsat-error-gso').textContent = data.extended_stats.kubsat.error_gso_count;
|
||||
document.getElementById('kubsat-error-kub').textContent = data.extended_stats.kubsat.error_kub_count;
|
||||
|
||||
// Update Kubsat statistics - Предложено
|
||||
document.getElementById('kubsat-suggested').textContent = data.extended_stats.kubsat.suggested_count;
|
||||
|
||||
// Update period info
|
||||
updatePeriodInfo(data.date_from, data.date_to);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading extended stats:', error);
|
||||
alert('Ошибка загрузки статистики');
|
||||
// alert('Ошибка загрузки статистики');
|
||||
})
|
||||
.finally(() => {
|
||||
// Hide loading indicator
|
||||
@@ -1654,43 +1681,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
}
|
||||
|
||||
// Update Kubsat progress bar
|
||||
function updateKubsatProgressBar(kubsat) {
|
||||
const progressContainer = document.querySelector('.progress');
|
||||
if (!progressContainer) return;
|
||||
|
||||
const total = kubsat.planned_count;
|
||||
if (total === 0) {
|
||||
progressContainer.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
|
||||
if (kubsat.conducted_count > 0) {
|
||||
const pct = Math.round((kubsat.conducted_count / total) * 100);
|
||||
html += `<div class="progress-bar bg-success" role="progressbar" style="width: ${pct}%" title="Проведено: ${kubsat.conducted_count}">${kubsat.conducted_count}</div>`;
|
||||
}
|
||||
|
||||
if (kubsat.canceled_gso_count > 0) {
|
||||
const pct = Math.round((kubsat.canceled_gso_count / total) * 100);
|
||||
html += `<div class="progress-bar bg-danger" role="progressbar" style="width: ${pct}%" title="Отменено ГСО: ${kubsat.canceled_gso_count}">${kubsat.canceled_gso_count}</div>`;
|
||||
}
|
||||
|
||||
if (kubsat.canceled_kub_count > 0) {
|
||||
const pct = Math.round((kubsat.canceled_kub_count / total) * 100);
|
||||
html += `<div class="progress-bar bg-warning text-dark" role="progressbar" style="width: ${pct}%" title="Отменено МКА: ${kubsat.canceled_kub_count}">${kubsat.canceled_kub_count}</div>`;
|
||||
}
|
||||
|
||||
progressContainer.innerHTML = html;
|
||||
|
||||
// Update total count
|
||||
const totalLabel = progressContainer.parentElement.querySelector('.text-muted:last-of-type');
|
||||
if (totalLabel) {
|
||||
totalLabel.textContent = 'Всего: ' + total;
|
||||
}
|
||||
}
|
||||
|
||||
// Update period info display
|
||||
function updatePeriodInfo(dateFrom, dateTo) {
|
||||
const periodAlert = document.querySelector('#extendedStatsModal .alert-light');
|
||||
|
||||
@@ -15,7 +15,7 @@ from django.urls import reverse
|
||||
from django.views import View
|
||||
|
||||
from ..forms import SourceForm
|
||||
from ..models import Source, Satellite
|
||||
from ..models import Source, Satellite, SourceRequest
|
||||
from ..utils import format_coords_display, parse_pagination_params
|
||||
from ..permissions import PermissionRequiredMixin, permission_required
|
||||
|
||||
@@ -419,7 +419,6 @@ class SourceListView(LoginRequiredMixin, View):
|
||||
# Filter by source requests
|
||||
if has_requests == "1":
|
||||
# Has requests - apply subfilters
|
||||
from ..models import SourceRequest
|
||||
from django.db.models import Exists, OuterRef
|
||||
|
||||
# Build subquery for filtering requests
|
||||
@@ -812,6 +811,9 @@ class SourceListView(LoginRequiredMixin, View):
|
||||
'object_infos': object_infos,
|
||||
'polygon_coords': json.dumps(polygon_coords) if polygon_coords else None,
|
||||
'full_width_page': True,
|
||||
# Status and priority choices from model
|
||||
'status_choices': SourceRequest.STATUS_CHOICES,
|
||||
'priority_choices': SourceRequest.PRIORITY_CHOICES,
|
||||
}
|
||||
|
||||
return render(request, "mainapp/source_list.html", context)
|
||||
|
||||
@@ -313,37 +313,39 @@ class StatisticsView(PermissionRequiredMixin, TemplateView):
|
||||
Получает статистику по Кубсатам из SourceRequest.
|
||||
|
||||
Возвращает:
|
||||
- planned_count: количество запланированных сеансов
|
||||
- conducted_count: количество проведённых
|
||||
- canceled_gso_count: количество отменённых ГСО
|
||||
- canceled_kub_count: количество отменённых МКА
|
||||
1. Запланировано (по истории статуса 'planned'):
|
||||
- planned_count: всего запланировано
|
||||
- conducted_count: проведено
|
||||
- canceled_gso_count: отменено ГСО
|
||||
- canceled_kub_count: отменено МКА
|
||||
- wait_exec_count: ожидают проведения
|
||||
- gso_fault_count: не проведены по вине ГСО
|
||||
|
||||
2. Проведено (по истории статуса 'conducted'):
|
||||
- total_conducted_count: всего проведено
|
||||
- result_received_count: результат получен
|
||||
- processing_count: обработка
|
||||
- no_correlation_count: нет корреляции
|
||||
- error_gso_count: ошибка ГСО
|
||||
- error_kub_count: ошибка МКА
|
||||
|
||||
3. Предложено:
|
||||
- suggested_count: количество предложенных
|
||||
"""
|
||||
# Базовый queryset для заявок
|
||||
requests_qs = SourceRequest.objects.all()
|
||||
|
||||
# Фильтруем по дате создания или planned_at
|
||||
if date_from:
|
||||
requests_qs = requests_qs.filter(
|
||||
Q(created_at__date__gte=date_from) | Q(planned_at__date__gte=date_from)
|
||||
)
|
||||
if date_to:
|
||||
requests_qs = requests_qs.filter(
|
||||
Q(created_at__date__lte=date_to) | Q(planned_at__date__lte=date_to)
|
||||
)
|
||||
|
||||
# Получаем ID заявок, у которых в истории был статус 'planned'
|
||||
# Это заявки, которые были запланированы в выбранном периоде
|
||||
history_qs = SourceRequestStatusHistory.objects.filter(
|
||||
# === 1. ЗАПЛАНИРОВАНО ===
|
||||
# Получаем ID заявок, у которых в истории был статус 'planned' в периоде
|
||||
history_planned_qs = SourceRequestStatusHistory.objects.filter(
|
||||
new_status='planned'
|
||||
)
|
||||
if date_from:
|
||||
history_qs = history_qs.filter(changed_at__date__gte=date_from)
|
||||
history_planned_qs = history_planned_qs.filter(changed_at__date__gte=date_from)
|
||||
if date_to:
|
||||
history_qs = history_qs.filter(changed_at__date__lte=date_to)
|
||||
history_planned_qs = history_planned_qs.filter(changed_at__date__lte=date_to)
|
||||
|
||||
planned_request_ids = set(history_qs.values_list('source_request_id', flat=True))
|
||||
planned_request_ids = set(history_planned_qs.values_list('source_request_id', flat=True))
|
||||
|
||||
# Также добавляем заявки, которые были созданы со статусом 'planned' в периоде
|
||||
# (для случаев, когда заявка создана сразу с этим статусом без истории)
|
||||
created_planned_qs = SourceRequest.objects.filter(status='planned')
|
||||
if date_from:
|
||||
created_planned_qs = created_planned_qs.filter(created_at__date__gte=date_from)
|
||||
@@ -354,35 +356,88 @@ class StatisticsView(PermissionRequiredMixin, TemplateView):
|
||||
|
||||
planned_count = len(planned_request_ids)
|
||||
|
||||
# Считаем статусы из истории для запланированных заявок
|
||||
# Считаем текущие статусы для запланированных заявок
|
||||
conducted_count = 0
|
||||
canceled_gso_count = 0
|
||||
canceled_kub_count = 0
|
||||
wait_exec_count = 0
|
||||
gso_fault_count = 0
|
||||
|
||||
if planned_request_ids:
|
||||
# Получаем историю статусов для запланированных заявок
|
||||
status_history = SourceRequestStatusHistory.objects.filter(
|
||||
source_request_id__in=planned_request_ids
|
||||
# Получаем текущие статусы запланированных заявок
|
||||
planned_requests = SourceRequest.objects.filter(id__in=planned_request_ids)
|
||||
|
||||
conducted_count = planned_requests.filter(status='conducted').count()
|
||||
canceled_gso_count = planned_requests.filter(status='canceled_gso').count()
|
||||
canceled_kub_count = planned_requests.filter(status='canceled_kub').count()
|
||||
wait_exec_count = planned_requests.filter(status='wait_exec').count()
|
||||
gso_fault_count = planned_requests.filter(status='gso_fault').count()
|
||||
|
||||
# === 2. ПРОВЕДЕНО ===
|
||||
# Получаем ID заявок, у которых в истории был статус 'conducted' в периоде
|
||||
history_conducted_qs = SourceRequestStatusHistory.objects.filter(
|
||||
new_status='conducted'
|
||||
)
|
||||
if date_from:
|
||||
status_history = status_history.filter(changed_at__date__gte=date_from)
|
||||
history_conducted_qs = history_conducted_qs.filter(changed_at__date__gte=date_from)
|
||||
if date_to:
|
||||
status_history = status_history.filter(changed_at__date__lte=date_to)
|
||||
history_conducted_qs = history_conducted_qs.filter(changed_at__date__lte=date_to)
|
||||
|
||||
# Считаем уникальные заявки по каждому статусу
|
||||
conducted_ids = set(status_history.filter(new_status='conducted').values_list('source_request_id', flat=True))
|
||||
canceled_gso_ids = set(status_history.filter(new_status='canceled_gso').values_list('source_request_id', flat=True))
|
||||
canceled_kub_ids = set(status_history.filter(new_status='canceled_kub').values_list('source_request_id', flat=True))
|
||||
conducted_request_ids = set(history_conducted_qs.values_list('source_request_id', flat=True))
|
||||
|
||||
conducted_count = len(conducted_ids)
|
||||
canceled_gso_count = len(canceled_gso_ids)
|
||||
canceled_kub_count = len(canceled_kub_ids)
|
||||
# Также добавляем заявки с текущим статусом 'conducted', созданные в периоде
|
||||
created_conducted_qs = SourceRequest.objects.filter(status='conducted')
|
||||
if date_from:
|
||||
created_conducted_qs = created_conducted_qs.filter(created_at__date__gte=date_from)
|
||||
if date_to:
|
||||
created_conducted_qs = created_conducted_qs.filter(created_at__date__lte=date_to)
|
||||
|
||||
conducted_request_ids.update(created_conducted_qs.values_list('id', flat=True))
|
||||
|
||||
total_conducted_count = len(conducted_request_ids)
|
||||
|
||||
# Считаем текущие статусы для проведённых заявок
|
||||
result_received_count = 0
|
||||
processing_count = 0
|
||||
no_correlation_count = 0
|
||||
error_gso_count = 0
|
||||
error_kub_count = 0
|
||||
|
||||
if conducted_request_ids:
|
||||
conducted_requests = SourceRequest.objects.filter(id__in=conducted_request_ids)
|
||||
|
||||
result_received_count = conducted_requests.filter(status='result_received').count()
|
||||
processing_count = conducted_requests.filter(status='processing').count()
|
||||
no_correlation_count = conducted_requests.filter(status='no_correlation').count()
|
||||
error_gso_count = conducted_requests.filter(status='error_gso').count()
|
||||
error_kub_count = conducted_requests.filter(status='error_kub').count()
|
||||
|
||||
# === 3. ПРЕДЛОЖЕНО ===
|
||||
suggested_qs = SourceRequest.objects.filter(status='suggested')
|
||||
if date_from:
|
||||
suggested_qs = suggested_qs.filter(created_at__date__gte=date_from)
|
||||
if date_to:
|
||||
suggested_qs = suggested_qs.filter(created_at__date__lte=date_to)
|
||||
|
||||
suggested_count = suggested_qs.count()
|
||||
|
||||
return {
|
||||
# Запланировано
|
||||
'planned_count': planned_count,
|
||||
'conducted_count': conducted_count,
|
||||
'canceled_gso_count': canceled_gso_count,
|
||||
'canceled_kub_count': canceled_kub_count,
|
||||
'wait_exec_count': wait_exec_count,
|
||||
'gso_fault_count': gso_fault_count,
|
||||
# Проведено
|
||||
'total_conducted_count': total_conducted_count,
|
||||
'result_received_count': result_received_count,
|
||||
'processing_count': processing_count,
|
||||
'no_correlation_count': no_correlation_count,
|
||||
'error_gso_count': error_gso_count,
|
||||
'error_kub_count': error_kub_count,
|
||||
# Предложено
|
||||
'suggested_count': suggested_count,
|
||||
}
|
||||
|
||||
def get_extended_statistics(self, date_from, date_to):
|
||||
|
||||
Reference in New Issue
Block a user