108 lines
4.8 KiB
Python
108 lines
4.8 KiB
Python
from rest_framework import status
|
||
from rest_framework.views import APIView
|
||
from rest_framework.permissions import IsAuthenticated
|
||
from rest_framework.response import Response
|
||
from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample, OpenApiParameter
|
||
from api.utils.decorators import handle_exceptions
|
||
from datetime import timedelta
|
||
from django.utils import timezone
|
||
from django.db.models import Count
|
||
from django.db.models.functions import TruncHour
|
||
from sitemanagement.models import Alert
|
||
from api.account.serializers.dashboard_serializers import DashboardSerializer
|
||
|
||
@extend_schema(tags=['Дашборд'])
|
||
class DashboardView(APIView):
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
@extend_schema(
|
||
summary="Получение статистики алертов",
|
||
description="Возвращает статистику алертов за выбранный период времени",
|
||
parameters=[OpenApiParameter(
|
||
name='time_period',
|
||
type=str,
|
||
location=OpenApiParameter.QUERY,
|
||
description='Период времени в часах',
|
||
required=False,
|
||
enum=['24', '72', '168', '720'],
|
||
default='168'
|
||
)],
|
||
responses = {
|
||
200: OpenApiResponse(response=DashboardSerializer, description="Данные для дашборда успешно получены",
|
||
examples=[OpenApiExample(
|
||
'Успешный ответ',
|
||
value={
|
||
"chart_data": [
|
||
{"timestamp": "2025-10-07T10:00:00+03:00", "value": 5},
|
||
{"timestamp": "2025-10-07T11:00:00+03:00", "value": 3}
|
||
],
|
||
"table_data": [
|
||
{
|
||
"id": 1,
|
||
"name": "GA-1",
|
||
"object": "Объект 1",
|
||
"metric_value": "23.5 °C",
|
||
"sensor_type_name": "Датчик температуры",
|
||
"message": "Превышение температуры",
|
||
"severity": "warning",
|
||
"created_at": "2025-10-07T10:30:00+03:00",
|
||
"resolved": False
|
||
}
|
||
]
|
||
}
|
||
)])
|
||
}
|
||
|
||
)
|
||
@handle_exceptions
|
||
def get(self, request):
|
||
time_period = request.query_params.get('time_period', '168')
|
||
|
||
if time_period not in ['720', '168', '72', '24']:
|
||
return Response(
|
||
{"error": "Неверный период. Допустимые значения: 720, 168, 72, 24"},
|
||
status=status.HTTP_400_BAD_REQUEST
|
||
)
|
||
|
||
# определяем начальную дату
|
||
start_date = timezone.now() - timedelta(hours=int(time_period))
|
||
|
||
# получаем все алерты за период с фронта
|
||
alerts = Alert.objects.filter(created_at__gte=start_date)
|
||
|
||
# данные для графиков (группировка по часам)
|
||
alerts_by_hour = alerts.annotate(
|
||
hour=TruncHour('created_at')
|
||
).values('hour').annotate(
|
||
count=Count('id')
|
||
).order_by('hour')
|
||
|
||
# !! обязательно локальное время
|
||
chart_data = []
|
||
for entry in alerts_by_hour:
|
||
local_time = timezone.localtime(entry['hour'])
|
||
chart_data.append({
|
||
"timestamp": local_time.isoformat(),
|
||
"value": entry['count']
|
||
})
|
||
|
||
# данные для таблицы с алертами
|
||
alerts_list = alerts.select_related(
|
||
'sensor',
|
||
'sensor_type',
|
||
'metric',
|
||
'sensor__signal_format'
|
||
).prefetch_related(
|
||
'sensor__zones',
|
||
'sensor__zones__object'
|
||
).order_by('-created_at')
|
||
|
||
|
||
dashboard_data = {
|
||
"chart_data": chart_data,
|
||
"table_data": alerts_list
|
||
}
|
||
|
||
serializer = DashboardSerializer(instance=dashboard_data)
|
||
|
||
return Response(serializer.data, status=status.HTTP_200_OK) |