Files
dbstorage/dbapp/mainapp/views/source_requests.py

379 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Представления для управления заявками на источники.
"""
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import JsonResponse
from django.views import View
from django.views.generic import ListView, CreateView, UpdateView
from django.urls import reverse_lazy
from django.db.models import Q
from mainapp.models import SourceRequest, SourceRequestStatusHistory, Source
from mainapp.forms import SourceRequestForm
class SourceRequestListView(LoginRequiredMixin, ListView):
"""Список заявок на источники."""
model = SourceRequest
template_name = 'mainapp/source_request_list.html'
context_object_name = 'requests'
paginate_by = 50
def get_queryset(self):
queryset = SourceRequest.objects.select_related(
'source', 'source__info', 'source__ownership',
'created_by__user', 'updated_by__user'
).order_by('-created_at')
# Фильтр по статусу
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Фильтр по приоритету
priority = self.request.GET.get('priority')
if priority:
queryset = queryset.filter(priority=priority)
# Фильтр по источнику
source_id = self.request.GET.get('source_id')
if source_id:
queryset = queryset.filter(source_id=source_id)
# Фильтр по ГСО успешно
gso_success = self.request.GET.get('gso_success')
if gso_success == 'true':
queryset = queryset.filter(gso_success=True)
elif gso_success == 'false':
queryset = queryset.filter(gso_success=False)
# Фильтр по Кубсат успешно
kubsat_success = self.request.GET.get('kubsat_success')
if kubsat_success == 'true':
queryset = queryset.filter(kubsat_success=True)
elif kubsat_success == 'false':
queryset = queryset.filter(kubsat_success=False)
# Поиск
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(source__id__icontains=search) |
Q(comment__icontains=search)
)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['status_choices'] = SourceRequest.STATUS_CHOICES
context['priority_choices'] = SourceRequest.PRIORITY_CHOICES
context['current_status'] = self.request.GET.get('status', '')
context['current_priority'] = self.request.GET.get('priority', '')
context['search_query'] = self.request.GET.get('search', '')
context['form'] = SourceRequestForm()
return context
class SourceRequestCreateView(LoginRequiredMixin, CreateView):
"""Создание заявки на источник."""
model = SourceRequest
form_class = SourceRequestForm
template_name = 'mainapp/source_request_form.html'
success_url = reverse_lazy('mainapp:source_request_list')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
# Передаем source_id если он есть в GET параметрах
source_id = self.request.GET.get('source_id')
if source_id:
kwargs['source_id'] = source_id
return kwargs
def form_valid(self, form):
# Устанавливаем created_by
form.instance.created_by = getattr(self.request.user, 'customuser', None)
form.instance.updated_by = getattr(self.request.user, 'customuser', None)
response = super().form_valid(form)
# Создаем начальную запись в истории
SourceRequestStatusHistory.objects.create(
source_request=self.object,
old_status='',
new_status=self.object.status,
changed_by=form.instance.created_by,
)
# Если это AJAX запрос, возвращаем JSON
if self.request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return JsonResponse({
'success': True,
'message': 'Заявка успешно создана',
'request_id': self.object.id
})
return response
def form_invalid(self, form):
if self.request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return JsonResponse({
'success': False,
'errors': form.errors
}, status=400)
return super().form_invalid(form)
class SourceRequestUpdateView(LoginRequiredMixin, UpdateView):
"""Редактирование заявки на источник."""
model = SourceRequest
form_class = SourceRequestForm
template_name = 'mainapp/source_request_form.html'
success_url = reverse_lazy('mainapp:source_request_list')
def form_valid(self, form):
# Устанавливаем updated_by
form.instance.updated_by = getattr(self.request.user, 'customuser', None)
response = super().form_valid(form)
# Если это AJAX запрос, возвращаем JSON
if self.request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return JsonResponse({
'success': True,
'message': 'Заявка успешно обновлена',
'request_id': self.object.id
})
return response
def form_invalid(self, form):
if self.request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return JsonResponse({
'success': False,
'errors': form.errors
}, status=400)
return super().form_invalid(form)
class SourceRequestDeleteView(LoginRequiredMixin, View):
"""Удаление заявки на источник."""
def post(self, request, pk):
try:
source_request = SourceRequest.objects.get(pk=pk)
source_request.delete()
return JsonResponse({
'success': True,
'message': 'Заявка успешно удалена'
})
except SourceRequest.DoesNotExist:
return JsonResponse({
'success': False,
'error': 'Заявка не найдена'
}, status=404)
class SourceRequestAPIView(LoginRequiredMixin, View):
"""API для получения данных о заявках источника."""
def get(self, request, source_id):
try:
source = Source.objects.get(pk=source_id)
except Source.DoesNotExist:
return JsonResponse({'error': 'Источник не найден'}, status=404)
requests = SourceRequest.objects.filter(source=source).select_related(
'created_by__user', 'updated_by__user'
).prefetch_related('status_history__changed_by__user').order_by('-created_at')
data = []
for req in requests:
# Получаем историю статусов
history = []
for h in req.status_history.all().order_by('-changed_at'):
history.append({
'old_status': h.get_old_status_display() if h.old_status else '-',
'new_status': h.get_new_status_display(),
'changed_at': h.changed_at.strftime('%d.%m.%Y %H:%M') if h.changed_at else '-',
'changed_by': str(h.changed_by) if h.changed_by else '-',
})
data.append({
'id': req.id,
'status': req.status,
'status_display': req.get_status_display(),
'priority': req.priority,
'priority_display': req.get_priority_display(),
'planned_at': req.planned_at.strftime('%d.%m.%Y %H:%M') if req.planned_at else '-',
'request_date': req.request_date.strftime('%d.%m.%Y') if req.request_date else '-',
'status_updated_at': req.status_updated_at.strftime('%d.%m.%Y %H:%M') if req.status_updated_at else '-',
'gso_success': req.gso_success,
'kubsat_success': req.kubsat_success,
'comment': req.comment or '-',
'created_at': req.created_at.strftime('%d.%m.%Y %H:%M') if req.created_at else '-',
'created_by': str(req.created_by) if req.created_by else '-',
'history': history,
})
return JsonResponse({
'source_id': source_id,
'requests': data,
'count': len(data)
})
class SourceRequestDetailAPIView(LoginRequiredMixin, View):
"""API для получения детальной информации о заявке."""
def get(self, request, pk):
try:
req = SourceRequest.objects.select_related(
'source', 'source__info', 'source__ownership',
'created_by__user', 'updated_by__user'
).prefetch_related(
'status_history__changed_by__user',
'source__source_objitems__parameter_obj__modulation',
'source__source_objitems__geo_obj'
).get(pk=pk)
except SourceRequest.DoesNotExist:
return JsonResponse({'error': 'Заявка не найдена'}, status=404)
# Получаем историю статусов
history = []
for h in req.status_history.all().order_by('-changed_at'):
history.append({
'old_status': h.get_old_status_display() if h.old_status else '-',
'new_status': h.get_new_status_display(),
'changed_at': h.changed_at.strftime('%d.%m.%Y %H:%M') if h.changed_at else '-',
'changed_by': str(h.changed_by) if h.changed_by else '-',
})
# Получаем данные из первой точки источника (имя, модуляция, символьная скорость)
source_data = _get_source_extra_data(req.source)
# Координаты из заявки или из источника
coords_lat = None
coords_lon = None
if req.coords:
coords_lat = req.coords.y
coords_lon = req.coords.x
elif req.source.coords_average:
coords_lat = req.source.coords_average.y
coords_lon = req.source.coords_average.x
data = {
'id': req.id,
'source_id': req.source_id,
'status': req.status,
'status_display': req.get_status_display(),
'priority': req.priority,
'priority_display': req.get_priority_display(),
'planned_at': req.planned_at.isoformat() if req.planned_at else None,
'planned_at_display': req.planned_at.strftime('%d.%m.%Y %H:%M') if req.planned_at else '-',
'request_date': req.request_date.isoformat() if req.request_date else None,
'request_date_display': req.request_date.strftime('%d.%m.%Y') if req.request_date else '-',
'status_updated_at': req.status_updated_at.strftime('%d.%m.%Y %H:%M') if req.status_updated_at else '-',
'gso_success': req.gso_success,
'kubsat_success': req.kubsat_success,
'comment': req.comment or '',
'created_at': req.created_at.strftime('%d.%m.%Y %H:%M') if req.created_at else '-',
'created_by': str(req.created_by) if req.created_by else '-',
'history': history,
# Дополнительные данные
'coords_lat': coords_lat,
'coords_lon': coords_lon,
'points_count': req.points_count,
'objitem_name': source_data['objitem_name'],
'modulation': source_data['modulation'],
'symbol_rate': source_data['symbol_rate'],
}
return JsonResponse(data)
def _get_source_extra_data(source):
"""Получает дополнительные данные из первой точки источника."""
objitem_name = '-'
modulation = '-'
symbol_rate = '-'
if source:
# Получаем первую точку источника (сортируем по дате ГЛ)
objitems = source.source_objitems.select_related(
'parameter_obj__modulation', 'geo_obj'
).order_by('geo_obj__timestamp')
first_objitem = objitems.first()
if first_objitem:
objitem_name = first_objitem.name or '-'
if first_objitem.parameter_obj:
if first_objitem.parameter_obj.modulation:
modulation = first_objitem.parameter_obj.modulation.name
if first_objitem.parameter_obj.bod_velocity and first_objitem.parameter_obj.bod_velocity > 0:
symbol_rate = str(int(first_objitem.parameter_obj.bod_velocity))
return {
'objitem_name': objitem_name,
'modulation': modulation,
'symbol_rate': symbol_rate,
}
class SourceDataAPIView(LoginRequiredMixin, View):
"""API для получения данных источника (координаты, имя точки, модуляция, символьная скорость)."""
def get(self, request, source_id):
from mainapp.utils import calculate_mean_coords
from datetime import datetime
try:
source = Source.objects.select_related('info', 'ownership').prefetch_related(
'source_objitems__parameter_obj__modulation',
'source_objitems__geo_obj'
).get(pk=source_id)
except Source.DoesNotExist:
return JsonResponse({'error': 'Источник не найден', 'found': False}, status=404)
# Получаем данные из точек источника
source_data = _get_source_extra_data(source)
# Рассчитываем усреднённые координаты из всех точек (сортируем по дате ГЛ)
objitems = source.source_objitems.select_related('geo_obj').order_by('geo_obj__timestamp')
avg_coords = None
points_count = 0
for objitem in objitems:
if hasattr(objitem, 'geo_obj') and objitem.geo_obj and objitem.geo_obj.coords:
coord = (float(objitem.geo_obj.coords.x), float(objitem.geo_obj.coords.y))
points_count += 1
if avg_coords is None:
avg_coords = coord
else:
avg_coords, _ = calculate_mean_coords(avg_coords, coord)
# Если нет координат из точек, берём из источника
coords_lat = None
coords_lon = None
if avg_coords:
coords_lon = avg_coords[0]
coords_lat = avg_coords[1]
elif source.coords_average:
coords_lat = source.coords_average.y
coords_lon = source.coords_average.x
data = {
'found': True,
'source_id': source_id,
'coords_lat': coords_lat,
'coords_lon': coords_lon,
'points_count': points_count,
'objitem_name': source_data['objitem_name'],
'modulation': source_data['modulation'],
'symbol_rate': source_data['symbol_rate'],
'info': source.info.name if source.info else '-',
'ownership': source.ownership.name if source.ownership else '-',
}
return JsonResponse(data)