diff --git a/apps/enm/urls.py b/apps/enm/urls.py index eb5239ac..f5777809 100644 --- a/apps/enm/urls.py +++ b/apps/enm/urls.py @@ -1,18 +1,19 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.enm.views import (MpointViewSet, MpLogxViewSet, MpointStatViewSet, - EnStatViewSet, EnStat2ViewSet, XscriptViewSet) +from apps.enm.views import (MpointViewSet, MpointStatViewSet, + EnStatViewSet, EnStat2ViewSet, XscriptViewSet, MpLogxAPIView) API_BASE_URL = 'api/enm/' HTML_BASE_URL = 'dhtml/enm/' router = DefaultRouter() router.register('mpoint', MpointViewSet, basename='mpoint') -router.register('mplogx', MpLogxViewSet, basename='mplogx') +# router.register('mplogx', MpLogxViewSet, basename='mplogx') router.register('mpointstat', MpointStatViewSet, basename='mpointstat') router.register('enstat', EnStatViewSet, basename='enstat') router.register('enstat2', EnStat2ViewSet, basename='enstat2') router.register('xscript', XscriptViewSet, basename='xscript') urlpatterns = [ path(API_BASE_URL, include(router.urls)), + path(f'{API_BASE_URL}mplogx/', MpLogxAPIView.as_view(), name='mplogx_list'), ] \ No newline at end of file diff --git a/apps/enm/views.py b/apps/enm/views.py index 337ddebe..49d4c5a2 100644 --- a/apps/enm/views.py +++ b/apps/enm/views.py @@ -12,6 +12,7 @@ from apps.enm.tasks import cal_mpointstat_manual from rest_framework.response import Response from rest_framework.serializers import Serializer from rest_framework.decorators import action +from rest_framework.views import APIView from apps.enm.tasks import cal_mpointstats_duration from apps.enm.services import king_sync, MpointCache from django.db import transaction @@ -21,7 +22,13 @@ from apps.enm.services import get_analyse_data_mgroups_duration from django.db.models import Sum import logging from django.core.cache import cache +from apps.utils.sql import query_one_dict, query_all_dict +from drf_yasg import openapi +from drf_yasg.utils import swagger_auto_schema +from django.utils import timezone + myLogger = logging.getLogger('log') + class MpointViewSet(CustomModelViewSet): """ list:测点 @@ -166,6 +173,97 @@ class XscriptViewSet(CustomModelViewSet): # select_related_fields = ['mpoint'] # filterset_fields = ['mpoint', 'mpoint__mgroup', 'mpoint__mgroup__belong_dept'] +class MpLogxAPIView(APIView): + """ + list:测点采集数据 + + 测点采集数据 + """ + perms_map = {"get": "*"} + + @swagger_auto_schema(manual_parameters=[ + openapi.Parameter('mpoint', openapi.IN_QUERY, description='测点ID', type=openapi.TYPE_STRING), + openapi.Parameter('timex__gte', openapi.IN_QUERY, description='开始时间', type=openapi.TYPE_STRING), + openapi.Parameter('timex__lte', openapi.IN_QUERY, description='结束时间', type=openapi.TYPE_STRING), + openapi.Parameter('page', openapi.IN_QUERY, description='页码', type=openapi.TYPE_INTEGER), + openapi.Parameter('page_size', openapi.IN_QUERY, description='每页数量', type=openapi.TYPE_INTEGER), + openapi.Parameter('ordering', openapi.IN_QUERY, description='排序字段,如 -timex', type=openapi.TYPE_STRING), + openapi.Parameter('fields', openapi.IN_QUERY, description='返回字段,如 timex,val_float,val_int', type=openapi.TYPE_STRING), + ]) + def get(self, request, *args, **kwargs): + mpoint = request.query_params.get("mpoint", None) + timex__gte_str = request.query_params.get("timex__gte", None) + timex__lte_str = request.query_params.get("timex__lte", None) + page = int(request.query_params.get("page", 1)) + page_size = int(request.query_params.get("page_size", 20)) + fields = request.query_params.get("fields", None) + if page < 0 and page_size < 0: + raise ParseError("page, page_size must be positive") + ordering = request.query_params.get("ordering", "-timex") # 默认倒序 + + if mpoint is None or timex__gte_str is None: + raise ParseError("mpoint, timex__gte are required") + + # 处理时间 + timex__gte = timezone.make_aware(datetime.strptime(timex__gte_str, "%Y-%m-%d %H:%M:%S")) + timex__lte = timezone.make_aware(datetime.strptime(timex__lte_str, "%Y-%m-%d %H:%M:%S")) if timex__lte_str else timezone.now() + + # 统计总数 + count_sql = """SELECT COUNT(*) AS total_count FROM enm_mplogx + WHERE mpoint_id=%s AND timex >= %s AND timex <= %s""" + count_data = query_one_dict(count_sql, [mpoint, timex__gte, timex__lte], with_time_format=True) + + # 排序白名单 + allowed_fields = {"timex", "val_mrs", "val_int", "val_float"} # 根据表字段修改 + order_fields = [] + for field in ordering.split(","): + field = field.strip() + if not field: + continue + desc = field.startswith("-") + field_name = field[1:] if desc else field + if field_name in allowed_fields: + order_fields.append(f"{field_name} {'DESC' if desc else 'ASC'}") + + # 如果没有合法字段,使用默认排序 + if not order_fields: + order_fields = ["timex DESC"] + + order_clause = "ORDER BY " + ", ".join(order_fields) + + # 构造 SQL + if page == 0: + if fields: + # 过滤白名单,避免非法列 + fields = [f for f in fields.split(",") if f in allowed_fields] + if not fields: + fields = ["timex", "val_float", "val_int"] # 默认列 + select_clause = ", ".join(fields) + else: + select_clause = "timex, val_float, val_int" # 默认列 + page_sql = f"""SELECT {select_clause} FROM enm_mplogx + WHERE mpoint_id=%s AND timex >= %s AND timex <= %s + {order_clause}""" + page_params = [mpoint, timex__gte, timex__lte] + else: + page_sql = f"""SELECT * FROM enm_mplogx + WHERE mpoint_id=%s AND timex >= %s AND timex <= %s + {order_clause} LIMIT %s OFFSET %s""" + page_params = [mpoint, timex__gte, timex__lte, page_size, (page-1)*page_size] + + page_data = query_all_dict(page_sql, page_params, with_time_format=True) + + if page == 0: + return Response(page_data) + + return Response({ + "count": count_data["total_count"], + "page": page, + "page_size": page_size, + "results": page_data + }) + + class MpLogxViewSet(CustomListModelMixin, CustomGenericViewSet): """