feat / AEB-66 create dashboard api

This commit is contained in:
Timofey
2025-10-13 12:06:23 +03:00
parent d0f1ae26a9
commit ea1f50c1b8
6 changed files with 194 additions and 76 deletions

View File

@@ -0,0 +1,19 @@
from rest_framework import serializers
from api.account.serializers.alert_serializers import AlertSerializer
class ChartDataSerializer(serializers.Serializer):
timestamp = serializers.DateTimeField()
value = serializers.IntegerField()
class DashboardSerializer(serializers.Serializer):
chart_data = ChartDataSerializer(many=True, required=False)
table_data = AlertSerializer(many=True, read_only=True)
def to_representation(self, instance):
return {
'chart_data': instance['chart_data'],
'table_data': AlertSerializer(instance['table_data'], many=True).data
}
class Meta:
fields = ('chart_data', 'table_data')

View File

@@ -3,6 +3,7 @@ from .views.UserDataView import UserDataView
from .views.objects_views import ObjectView
from .views.sensors_views import SensorView
from .views.alert_views import AlertView, ReportView
from .views.dashboard_views import DashboardView
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
@@ -33,4 +34,6 @@ urlpatterns = [
path("update-alert/<int:pk>/", AlertView.as_view({'patch': 'change_alert_status'}), name="update-alert"),
path("get-reports/", ReportView.as_view({'post': 'get_reports'}), name="reports"),
path("get-dashboard/", DashboardView.as_view(), name="dashboard"),
]

View File

@@ -0,0 +1,108 @@
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)