采用python3.12 +django5.1 结合 RabbitMQ 和发送邮件功能,实现一个简单的告警系统 前后端分离 vue-element

一、开发环境搭建和配置

#mac环境
brew install python@3.12
python3.12 --version
python3.12 -m pip install --upgrade pip
python3.12 -m pip install Django==5.1
python3.12 -m django --version
#用于检索系统信息和进程管理
python3.12 -m pip install psutil
#集成 pika 用于 RabbitMQ
python3.12 -m pip install pika#要在 Docker 中安装 RabbitMQ 并开启 WebSocket 端口 15674
docker run -d --name rabbitmq \
-p 5672:5672 \
-p 15672:15672 \
-p 15674:15674 \
rabbitmq:3-management#进入容器内部
docker exec -it rabbitmq bash#在容器内部,启用 WebSocket 插件:
rabbitmq-plugins enable rabbitmq_web_stomp

二、构建django应用

# 创建 monitor-plat 项目
django-admin startproject operation#项目结构
operation
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-313.pyc
│   ├── settings.cpython-313.pyc
│   ├── urls.cpython-313.pyc
│   └── wsgi.cpython-313.pyc
├── asgi.py
├── common
│   ├── __init__.py
│   ├── __pycache__
│   │   └── __init__.cpython-313.pyc
│   ├── enum
│   │   ├── EventTypesEnum.py
│   │   ├── OperatorTypeEnum.py
│   │   ├── ResponeCodeEnum.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── EventTypesEnum.cpython-313.pyc
│   │       ├── OperatorTypeEnum.cpython-313.pyc
│   │       ├── ResponeCodeEnum.cpython-313.pyc
│   │       └── __init__.cpython-313.pyc
│   ├── exception
│   │   ├── BusinessException.py
│   │   ├── __init__.py
│   │   └── __pycache__
│   │       ├── BusinessException.cpython-313.pyc
│   │       └── __init__.cpython-313.pyc
│   └── utils
│       ├── CommonResult.py
│       ├── PageUtils.py
│       ├── Serializers.py
│       ├── __init__.py
│       └── __pycache__
│           ├── CommonResult.cpython-313.pyc
│           ├── PageUtils.cpython-313.pyc
│           ├── Serializers.cpython-313.pyc
│           └── __init__.cpython-313.pyc
├── settings.py
├── urls.py
└── wsgi.py
log
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-313.pyc
│   ├── admin.cpython-313.pyc
│   ├── apps.cpython-313.pyc
│   ├── models.cpython-313.pyc
│   └── views.cpython-313.pyc
├── admin.py
├── apps.py
├── migrations
│   ├── 0001_initial.py
│   ├── __init__.py
│   └── __pycache__
│       ├── 0001_initial.cpython-313.pyc
│       └── __init__.cpython-313.pyc
├── models.py
├── tests.py
└── views.py
dbOperations
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-313.pyc
│   ├── admin.cpython-313.pyc
│   ├── apps.cpython-313.pyc
│   ├── models.cpython-313.pyc
│   └── views.cpython-313.pyc
├── admin.py
├── apps.py
├── migrations
│   ├── __init__.py
│   └── __pycache__
│       └── __init__.cpython-313.pyc
├── models.py
├── tests.py
└── views.py
user
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-313.pyc
│   ├── admin.cpython-313.pyc
│   ├── apps.cpython-313.pyc
│   ├── models.cpython-313.pyc
│   └── views.cpython-313.pyc
├── admin.py
├── apps.py
├── migrations
│   ├── 0001_initial.py
│   ├── __init__.py
│   └── __pycache__
│       ├── 0001_initial.cpython-313.pyc
│       └── __init__.cpython-313.pyc
├── models.py
├── tests.py
└── views.py
monitor
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-313.pyc
│   ├── admin.cpython-313.pyc
│   ├── apps.cpython-313.pyc
│   ├── models.cpython-313.pyc
│   ├── signals.cpython-313.pyc
│   ├── tasks.cpython-313.pyc
│   └── views.cpython-313.pyc
├── admin.py
├── apps.py
├── migrations
│   ├── 0001_initial.py
│   ├── __init__.py
│   └── __pycache__
│       ├── 0001_initial.cpython-313.pyc
│       └── __init__.cpython-313.pyc
├── models.py
├── signals.py
├── tasks.py
├── tests.py
└── views.py

三、监控,告警相关代码 

monitor
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-313.pyc
│   ├── admin.cpython-313.pyc
│   ├── apps.cpython-313.pyc
│   ├── models.cpython-313.pyc
│   ├── signals.cpython-313.pyc
│   ├── tasks.cpython-313.pyc
│   └── views.cpython-313.pyc
#=========================tasks.py=========================
import logging
import multiprocessingimport pika
import json
import psutil
import time
from monitor.models import ServerSecurityEventLog
from operation import settings
from operation.common.enum.EventTypesEnum import EventTypesEnum"""监控服务器 性能  """
def send_memory_data():connection = Nonechannel = None#获取 rabbitmq配置rabbitmq_config = settings.RABBITMQ_CONFIGtry:connection = pika.BlockingConnection(pika.ConnectionParameters(host=rabbitmq_config['host'],port=rabbitmq_config['port'],virtual_host=rabbitmq_config['virtual_host'],credentials=pika.PlainCredentials(rabbitmq_config['user'], rabbitmq_config['password'])))channel = connection.channel()channel.queue_declare(queue='virtual_queue',durable=True)print("连接成功")logging.info("连接成功")except pika.exceptions.AMQPConnectionError as e:logging.error(f"无法连接到AMQP服务器: {e}")return  # 如果连接失败,直接返回,避免后续代码执行try:while True:cpu_usage = psutil.cpu_percent(interval=1)cup_num = multiprocessing.cpu_count()memory_usage = psutil.virtual_memory()use_memory_usage = round(memory_usage.percent / (1024 * 1024 * 1024), 2)  # 获取已使用的内存memory_usage_total = round(memory_usage.total / (1024 * 1024 * 1024), 2)  # 获取总内存free_usage = round(memory_usage.active / (1024 * 1024 * 1024), 2)  # 获取 空闲内存disk_usage = psutil.disk_usage('/')  # 获取根目录的磁盘使用情况disk_usage_total = round(disk_usage.total / (1024 * 1024 * 1024), 2)  # 获取磁盘总容量free_disk_usage = round(disk_usage.free / (1024 * 1024 * 1024), 2)  # 获取磁盘剩余容量network_io = psutil.net_io_counters()#告警逻辑 保存event事件save_serverSecurity_event(cpu_usage, memory_usage.percent, disk_usage.percent, network_io)memory_usage_data = {'cpu_usage': cpu_usage,  # CPU的使用率。百分比'cup_num': cup_num,'use_memory_usage': use_memory_usage,  # 内存的使用情况。通以字节(bytes)或更常见的单位(如MB、GB)表示'memory_usage_total': memory_usage_total,'free_usage': free_usage,  # 空闲内存'disk_usage': disk_usage,  # 磁盘的使用情况。通常以字节(bytes)'disk_usage_total': disk_usage_total,  # 获取磁盘总容量'free_disk_usage': free_disk_usage,  # 获取磁盘剩余容量'network_io': network_io  # 表示网络输入/输出的情况 通常以字节(bytes)}# 发送rabbitmqchannel.basic_publish(exchange='',routing_key='virtual_queue',body=json.dumps(memory_usage_data))logging.info("数据发送成功")time.sleep(5)  # 每5秒发送一次except Exception as e:logging.error(f"数据发送失败: {e}")finally:if connection and connection.is_open:connection.close()"""保存告警逻辑 
"""
def save_serverSecurity_event(cpu_usage,memory_usage,disk_usage,network_io):logging.info("保存告警逻辑=====================================")# 告警逻辑if (cpu_usage > settings.CPU_THRESHOLD ormemory_usage > settings.MEMORY_THRESHOLD ordisk_usage > settings.DISK_THRESHOLD ornetwork_io.packets_recv == settings.PACKET_RECV_THRESHOLD ornetwork_io.packets_sent == settings.PACKETS_SENT_THRESHOLD):event_type = Noneevent_details = ""# 当cpu使用率大于90%时 记录cpuif cpu_usage > settings.CPU_THRESHOLD:logging.info(f'CPU使用率超过90%')event_type = EventTypesEnum.CPU_OVERLOAD.valueevent_details = f'CPU使用率超过90%: {cpu_usage}%'elif memory_usage > settings.MEMORY_THRESHOLD:logging.info(f'内存使用率超过80%')event_type = EventTypesEnum.MEMORY_OVERLOAD.valueevent_details = f'内存使用率超过80%: 1.15MB%'elif disk_usage > settings.DISK_THRESHOLD:logging.info(f'磁盘使用率超过90%')event_type = EventTypesEnum.DISK_OVERLOAD.valueevent_details = f'磁盘使用率超过90%: {disk_usage}%'elif network_io.packets_recv == settings.PACKET_RECV_THRESHOLD or network_io.packets_sent == settings.PACKETS_SENT_THRESHOLD:logging.info(f'网络异常,接收或发送的数据包为0')event_type = EventTypesEnum.NETWORK_ANOMALY.valueevent_details = '网络异常,接收或发送的数据包为0'# 保存告警信息到数据库ServerSecurityEventLog.objects.create(event_type=event_type,event_details=event_details)
#========================signals.py========================="""
处理告警逻辑:
"""
import logging
import time
from datetime import datetimefrom django.core.mail import send_mail
from django.db.models.signals import post_save
from django.dispatch import receiverfrom monitor.models import ServerSecurityEventLog
from operation import settings"""发送告警邮件 
"""# 设置告警邮件的发送频率,单位为秒
ALERT_EMAIL_INTERVAL = 60 * 5  # 5分钟# 上次发送告警邮件的时间
last_alert_email_time = 0@receiver(post_save, sender=ServerSecurityEventLog)
def send_alert_email(sender, instance, **kwargs):#global 关键字: 在函数内部使用 global 关键字声明变量时,表示该变量是全局变量,# 而不是函数内部的局部变量。这样可以在函数内部修改全局变量的值。global last_alert_email_time#获取当前时间current_time = time.time()if current_time - last_alert_email_time >= ALERT_EMAIL_INTERVAL:logging.info("发送告警邮件====================")subject = '服务器告警'# 格式化时间为目标格式formatted_time = instance.event_time.strftime("%Y-%m-%d %H:%M:%S")message = (f'服务器状态异常,请立即检查!\n'f'事件类型: {instance.event_type}\n'f'事件详情: {instance.event_details}\n'f'触发时间: {formatted_time}\n')from_email = settings.DEFAULT_FROM_EMAILrecipient_list = ['xxxxxxxx@qq.com']try:send_mail(subject, message, from_email, recipient_list)logging.info("邮件发送成功")last_alert_email_time = current_time  # 更新上次发送告警邮件的时间except Exception as e:logging.error(f"发送邮件失败 {e}")

    

#======================apps.py======================
from django.apps import AppConfigclass MonitorConfig(AppConfig):default_auto_field = 'django.db.models.BigAutoField'name = 'monitor'"""ready 方法: 这是 AppConfig 类中的一个特殊方法,在 Django 应用启动时会被调用。通常用于执行一些初始化操作"""def ready(self):# 注册信号  导入 monitor.signals 模块,用于注册 Django 信号。信号是 Django 中一种用于在特定事件发生时触发操作的机制。#@receiver(post_save, sender=ServerSecurityEventLog)  再做ServerSecurityEventLog 保存操作时 会 触发操作的机制。import monitor.signals# 导入任务函数: 从 tasks 模块中导入 send_memory_data 函数。from .tasks import send_memory_data#创建并启动线程: 使用 threading.Thread 创建一个新线程,#并将 send_memory_data 函数作为目标函数传递给线程。然后调用 thread.start() 启动线程。from threading import Threadthread = Thread(target=send_memory_data)thread.start()
#==========================models.py==========================from django.db import models# Create your models here.#告警 models
class ServerSecurityEventLog(models.Model):EVENT_TYPES = (('cpu_overload', 'CPU过载'),('memory_overload', '内存过载'),('disk_overload', '磁盘过载'),('network_anomaly', '网络异常'),)event_type = models.CharField(max_length=50, choices=EVENT_TYPES)event_time = models.DateTimeField(auto_now_add=True)event_details = models.TextField()is_resolved = models.BooleanField(default=False)def __str__(self):return f"{self.event_type} - {self.event_time}"class Meta:db_table = 'server_security_events_log'  # 指定表名def to_dict(self):return {'id': self.id,'event_type':self.event_type,'event_details':self.event_details,'event_time':self.event_time,'is_resolved':self.is_resolved}
#=========================views.py=========================#用于前端展示
import json
import multiprocessingimport psutil
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exemptfrom monitor.models import ServerSecurityEventLog
from operation.common.enum.ResponeCodeEnum import ResponseCodeEnum
from operation.common.exception.BusinessException import BusinessException
from operation.common.utils.CommonResult import CommonResult
from operation.common.utils.PageUtils import paginate_querysetdef getSystemInfo(request):try:if request.method != "GET":raise BusinessException(ResponseCodeEnum.METHOD_ERROR.message,ResponseCodeEnum.METHOD_ERROR.code)cpu_usage = psutil.cpu_percent(interval=1)cup_count = multiprocessing.cpu_count()memory_usage = psutil.virtual_memory()use_memory_usage = round(memory_usage.percent/(1024 * 1024 * 1024),2) #获取已使用的内存memory_usage_total = round(memory_usage.total/(1024 * 1024 * 1024),2) #获取总内存free_usage = round(memory_usage.active/(1024 * 1024 * 1024),2)      #获取 空闲内存存disk_usage = psutil.disk_usage('/')     #获取根目录的磁盘使用情况disk_usage_total = round(disk_usage.total/(1024 * 1024 * 1024),2)     #获取磁盘总容量free_disk_usage = round(disk_usage.free /(1024 * 1024 * 1024),2)     #获取磁盘剩余容量network_io = psutil.net_io_counters()data = {'cpu_usage': cpu_usage,    #CPU的使用率。百分比'cup_count':cup_count,'use_memory_usage': use_memory_usage, #内存的使用情况。通以字节(bytes)或更常见的单位(如MB、GB)表示'memory_usage_total':memory_usage_total,'free_usage':free_usage,   #空闲内存'disk_usage': disk_usage,   #磁盘的使用情况。通常以字节(bytes)'disk_usage_total':disk_usage_total, #获取磁盘总容量'free_disk_usage':free_disk_usage,  #获取磁盘剩余容量'network_io': network_io    #表示网络输入/输出的情况 通常以字节(bytes)}return JsonResponse(CommonResult.success_data(data), json_dumps_params={'ensure_ascii': False})except BusinessException as e:return JsonResponse(CommonResult.error(e.code,e.message), json_dumps_params={'ensure_ascii': False})"""获取告警列表
"""
@csrf_exempt
def getAlarmList(request):if request.method == 'POST':json_data = request.bodydata = json.loads(json_data)page = data.get('page', 1)page_size = data.get('page_size', 10)serverSecurityEventLogs = ServerSecurityEventLog.objects.all().order_by('event_time')event_list, pagination_info = paginate_queryset(serverSecurityEventLogs, page, page_size)event_lists = [ServerSecurityEventLog.to_dict() for ServerSecurityEventLog in event_list]return JsonResponse(CommonResult.success_pagination(event_lists, pagination_info), json_dumps_params={'ensure_ascii': False})else:return JsonResponse(CommonResult.success_data(), json_dumps_params={'ensure_ascii': False})
#==============================EventTypesEnum工具类==============================##############################EventTypesEnum##############################"""('cpu_overload', 'CPU过载'),('memory_overload', '内存过载'),('disk_overload', '磁盘过载'),('network_anomaly', '网络异常'),
"""
from enum import Enumclass EventTypesEnum(Enum):CPU_OVERLOAD = ('cpu_overload', 'CPU过载')MEMORY_OVERLOAD = ('memory_overload', '内存过载')DISK_OVERLOAD = ('disk_overload', '磁盘过载')NETWORK_ANOMALY = ('network_anomaly', '网络异常')"""Enum 的成员值不能直接是元组可以使用 Enum 的 __new__ 方法来自定义枚举成员的创建过程。 __value: 私有变量__value__: 双下划线前后缀通常用于定义Python的特殊方法(也称为魔术方法)。这些方法有特定的用途,例如 __init__ 用于初始化对象,__str__ 用于定义对象的字符串表示等。_value_: 双下划线前后缀通常用于避免与Python的特殊方法或内置函数命名冲突。这种命名方式并不常见,通常是为了避免与Python的保留字或特殊方法名冲突。_value:单个下划线前缀通常用于表示一个变量是“内部使用”的。虽然Python没有真正的私有变量,但这种命名约定告诉其他开发者这个变量不应该被直接访问。"""def __new__(cls,code,message):obj = object.__new__(cls)obj._value_ = codeobj.message = messagereturn obj@propertydef get_message(self):return self.message##############################OperatorTypeEnum##############################
import logging
from enum import Enum"""
操作类别(0其它 1后台用户 2手机端用户) other,backend,mobile
"""
from enum import Enumclass OperatorTypeEnum(Enum):# 元组OPERATOR_TYPE_OTHER = (0, "其它")OPERATOR_TYPE_BACKEND = (1, "后台用户")OPERATOR_TYPE_MOBILE = (2, "手机端用户")# def __init__(self, code, value):#     self.code = code#     self.message = value#     logging.info("执行OperatorTypeEnum 初始化 code %s,value %s================"%(self.code,self.value))"""cls:表示类的本身(以便在类方法中访问枚举类的成员变量。)self:表示实例"""@classmethoddef get_value_by_id(cls,code):for operator in cls:if operator.value[0] == code:return operator.value[1]return None##############################ResponseCodeEnum##############################
from enum import Enumclass ResponseCodeEnum(Enum):SUCCESS = (200, "操作成功!")PARAMS_ERROR = (400, "参数解析失败,请核对参数!")UNAUTHORIZED = (401, "未认证(签名错误)")FORBIDDEN = (402, "请求错误")  # 返回失败业务公共codeMEDIA_TYPE_ERROR = (403, "不支持的媒体异常,请核对contentType!")URL_REQ_NULL = (404, "请求路径不存在")METHOD_ERROR = (405, "不支持当前请求方法,请核对请求方法!")INTERNAL_SERVER_ERROR = (500, "服务器内部错误!")  # 系统异常公共codeNULL_POINTER_ERROR = (600, "请核对必填字段是否为空!")NUMBER_FORMAT_ERROR = (601, "数据类型不一致!")PARAMS_TYPE_ERROR = (602, "参数类型错误!")TIMEOUT_ERROR = (603, "token失效连接超时!")TIMEOUT_EXPIRE_ERROR = (604, "token登录过期!")TOKEN_ILLEGAL = (605, "非法token!")USER_LOGIN_FAIL = (1001,"用户登录失败!")def __init__(self, code, message):self.code = codeself.message = message#@property 是 Python 中用于将类的方法转换为属性访问的装饰器。# 使用 @property 装饰器,你可以像访问属性一样访问方法,而不需要调用它@propertydef status_code(self):return self.code@propertydef error_message(self):return self.message#<class 'enum.EnumType'> 枚举类
# print(type(ResponseCodeEnum))
#<enum 'ResponseCodeEnum'> SUCCESS 是 ResponseCodeEnum 枚举类的一个实例。
# print(type(ResponseCodeEnum.SUCCESS))##############################BusinessException##############################class BusinessException(Exception):def __init__(self,message,code):self.message = messageself.code = code##############################CommonResult##############################
from typing import Any, Optionalfrom operation.common.enum.ResponeCodeEnum import ResponseCodeEnumclass CommonResult:"""res: ResponseCodeEnum 这个定义表示 res 参数的类型是 ResponseCodeEnum,即 res 必须是 ResponseCodeEnum 的枚举值之一。这种定义方式有助于提高代码的类型安全性和可读性。"""def __init__(self, res: ResponseCodeEnum, data: Any, pagination: Optional[dict] = None):self.ResponseCodeEnum = ResponseCodeEnumself.data = dataself.pagination = pagination"""表态方法定义 直接通过 CommonResult.success  类名.静态方法名@staticmethod 不能访问或修改类或实例的属性。"""@staticmethoddef success_pagination(data: Any, pagination: Optional[dict] = None):return {'code': ResponseCodeEnum.SUCCESS.status_code,'message': ResponseCodeEnum.SUCCESS.message,'data': data,  # 将 QuerySet 序列化为 JSON,'pagination': pagination}@staticmethoddef error(code,message):return {'code': code,'message': message,'data': None,  # 将 QuerySet 序列化为 JSON,'pagination': None}@staticmethoddef success_data(data: Any):return {'code': ResponseCodeEnum.SUCCESS.status_code,'message': ResponseCodeEnum.SUCCESS.message,'data': data,  # 将 QuerySet 序列化为 JSON,}##############################PageUtils##############################from django.core.paginator import Paginator, EmptyPage, PageNotAnIntegerdef paginate_queryset(queryset, page, page_size):"""分页封装函数:param queryset: 查询集:param page: 页码:param page_size: 每页记录数:return: 分页后的数据和分页信息"""paginator = Paginator(queryset, page_size)try:page_obj = paginator.page(page)except PageNotAnInteger:page_obj = paginator.page(1)except EmptyPage:page_obj = paginator.page(paginator.num_pages)pagination_info = {'total_pages': paginator.num_pages,'current_page': page_obj.number,'has_next': page_obj.has_next(),'has_previous': page_obj.has_previous(),'next_page_number': page_obj.next_page_number() if page_obj.has_next() else None,'previous_page_number': page_obj.previous_page_number() if page_obj.has_previous() else None,'total': paginator.count}return page_obj.object_list, pagination_info##############################Serializer############################### db_operations/serializers.py
from rest_framework import serializersclass SQLExecutionSerializer(serializers.Serializer):sql = serializers.CharField()

四、 settings.py配置

#数据库 连接配置 mysql
DATABASES = {'default': {# 数据库引擎'ENGINE': 'django.db.backends.mysql',# 'ENGINE': 'sqlalchemy.create_engine',# 数据库名字'NAME': 'xxx',# 数据库用户名'USER': 'xx',# 数据库密码'PASSWORD': 'xx',# 数据库主机地址'HOST': 'xxx.xxx.xxx.xxx',# 数据库端口号'PORT': 'xxx'}
}LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'console': {'class': 'logging.StreamHandler',},},'root': {'handlers': ['console'],'level': 'INFO',},'loggers': {'django': {'handlers': ['console'],'level': 'INFO','propagate': False,},},
}INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','log','monitor','user','dbOperations'
]# 告警 邮箱配置  需要开通 smtp 权限 在qq邮箱中 配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qq.com'  # QQ邮箱的SMTP服务器
EMAIL_PORT = 465  # QQ邮箱的SMTP端口
EMAIL_USE_SSL = True  # 使用SSL加密
EMAIL_HOST_USER = 'xx'  # 你的QQ邮箱
EMAIL_HOST_PASSWORD = 'xx'  # 你的QQ邮箱密码或授权码
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER# RabbitMQ 配置
RABBITMQ_CONFIG = {'host': 'xx.xx.xx.xx','port': xx,'virtual_host': '/','user': 'xx','password': 'xx',
}

五、  创建和应用迁移


#创建数据库迁移文件并应用
python manage.py makemigrations
python manage.py migrate

六、  注册前端请求路由

from django.contrib import admin
from django.urls import pathfrom log import views as log_views
from monitor import views as monitor_views
from user import views as user_views
from dbOperations import views as db_views"""说明:这个路径将 /admin/ 开头的 URL 映射到 Django 自带的管理后台。admin.site.urls 是 Django 管理后台的 URL 配置,包含了管理后台的所有功能和页面。这个路径将 /log/ 开头的 URL 映射到 log 应用中的 getLogList 视图函数。name='log' 为这个 URL 路径定义了一个名称,可以在模板或其他地方通过这个名称来引用这个 URL。
"""
urlpatterns = [path('admin/', admin.site.urls),path('log/getLogList', log_views.getLogList, name='log_list'),path('log/getDebugLogList', log_views.getDebugLogList,name='debug_log_list'),path('monitor/getSystemInfo', monitor_views.getSystemInfo,name='system_info'),path('monitor/getAlarmList', monitor_views.getAlarmList, name='alarm_list'),path('user/login',user_views.login, name='login'),path('dbOperations/executeSQLView', db_views.executeSQLView,name='execute_sql_view')
]

七、  启动项目

#打开终端 cd 到根目录 
python manage.py runserver

八、  效果

#启动 前端 项目
npm run dev#==========================前端部分代码  alarmPage.vue==========================<template><div class="app-container"><el-card shadow="always"><el-form ref="searchForm" :inline="true" :model="searchMap" style="margin-top: 20px"><el-form-item><el-button type="primary" icon="el-icon-search" @click="searchLog('searchForm')">搜索</el-button><el-button type="primary" icon="el-icon-clear" @click="resetForm('searchForm')">重置</el-button></el-form-item></el-form></el-card><el-card shadow="always"><div><el-table ref="multipleTable" v-loading="listLoading" :data="alarmListDto" border fit highlight-current-row style="width: 100%;" class="tb-edit"><el-table-column label="操作ID" prop="id" width="180px" align="center" /><el-table-column label="事件类型" prop="event_type" width="380px" align="center" /><el-table-column label="事件详情" prop="event_details" width="380px" align="center" /><!-- <el-table-column label="是否已解决" prop="is_resolved" width="180px" align="center" /> --><el-table-column label="触发时间" prop="event_time" width="180px" align="center" /></el-table></div><div class="block"><el-pagination :current-page="currentPage" :page-sizes="[5, 10, 15, 20]" :page-size="5" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /></div></el-card></div>
</template><script>import {getAlarmList} from '@/api/monitors/monitors-request'export default {data() {return {total: 0,currentPage: 1,searchMap: {},listLoading: true,params: {page: 1, // 当前页码page_size: 5 // 每页显示数目},alarmListDto: [],error: ''}},mounted() {this.getAlarmList()},methods: {handleSizeChange(val) {console.log(`每页 ${val} 条`)this.params.page_size = valthis.getAlarmList()},handleCurrentChange(val) {console.log(`当前页: ${val}`)this.params.page = valthis.getAlarmList()},// 重置功能,element ui 提供的功能resetForm(formName) {console.log(this.$refs[formName].resetFields)this.$refs[formName].resetFields()this.getAlarmList()},searchLog(formName) {console.log(this.searchMap)this.getAlarmList()},getAlarmList() {this.dataLoading = trueconsole.log('请求参数:' + this.params)getAlarmList(this.params).then((res) => {console.log('响应:', res.data.data)alert(JSON.stringify(res.data.data))this.alarmListDto = res.data.datathis.total = res.data.pagination.totalsetTimeout(() => { // 超过指定超时时间  关闭查询的转圈的loading加载动画this.listLoading = false}, 1.5 * 1000)})}}}
</script><style>
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/477304.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【H2O2|全栈】JS进阶知识(八)ES6(4)

目录 前言 开篇语 准备工作 浅拷贝和深拷贝 浅拷贝 概念 常见方法 弊端 案例 深拷贝 概念 常见方法 弊端 逐层拷贝 原型 构造函数 概念 形式 成员 弊端 显式原型和隐式原型 概念 形式 constructor 概念 形式 原型链 概念 形式 结束语 前言 开篇语…

订单日记为“惠采科技”提供全方位的进销存管理支持

感谢温州惠采科技有限责任公司选择使用订单日记&#xff01; 温州惠采科技有限责任公司&#xff0c;成立于2024年&#xff0c;位于浙江省温州市&#xff0c;是一家以从事销售电气辅材为主的企业。 在业务不断壮大的过程中&#xff0c;想使用一种既能提升运营效率又能节省成本…

【Isaac Sim】配置 Nucleus 本地服务器

Omniverse 提供了本地&#xff08;局域&#xff09;服务器 Nucleus&#xff0c;可以将资产上传到该服务器&#xff0c;Nucleus 能够高效地存储和管理大量三维模型和其他资产&#xff0c;确保用户可以轻松访问这些资源。它还支持多用户环境下的实时协作&#xff0c;使得不同地理…

递归-迭代

24. 两两交换链表中的节点 Leetcode 24 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 递归解法 // 注意&#xff1a;cpp …

小蒋聊技术:大数据驱动决策——技术落地与业务深度融合

时间&#xff1a;2024年 10月 23日 作者&#xff1a;小蒋聊技术 邮箱&#xff1a;wei_wei10163.com 音频: 喜马拉雅 一.数据决策&#xff0c;真的是企业的“未来”吗&#xff1f; 大家好&#xff0c;欢迎来到“小蒋聊技术”&#xff01;今天&#xff0c;我们继续聊一个让企业关…

无插件直播流媒体音视频播放器EasyPlayer.js播放器的g711系列的音频,听起来为什么都是杂音

在数字化时代&#xff0c;流媒体播放器已成为信息传播和娱乐消遣的重要工具。随着技术的进步&#xff0c;流媒体播放器的核心技术和发展趋势不断演变&#xff0c;以满足用户对于无缝播放、低延迟和高画质的需求。 EasyPlayer播放器属于一款高效、精炼、稳定且免费的流媒体播放…

UVM 验证方法学之interface学习系列文章(七)高级 《bind 操作》(4)级联

在 SystemVerilog 中,bind 操作符用于将一个模块或接口实例绑定到另一个模块或接口的层次结构中。这在很多情况下非常有用,尤其是当你需要在不修改原始模块代码的情况下,添加或替换某些组件时。bind 操作符常用于仿真和测试平台中,以便灵活地组织测试环境。 前面的文章,我…

Vue3+SpringBoot3+Sa-Token+Redis+mysql8通用权限系统

sa-token支持分布式token 前后端代码&#xff0c;地球号: bright12389

Ansys Zemax Optical Studio 中的近视眼及矫正

近视&#xff0c;通常称为近视眼&#xff0c;是一种眼睛屈光不正&#xff0c;导致远处物体模糊&#xff0c;而近处物体清晰。这是一种常见的视力问题&#xff0c;通常发生在眼球过长或角膜&#xff08;眼睛前部清晰的部分&#xff09;过于弯曲时。因此&#xff0c;进入眼睛的光…

利用FileZilla搭建ftp服务器

一 利用windows自带的ftp服务搭建服务器&#xff0c;要复杂一些&#xff0c;好处是无需借用外部软件。 也有一些好的工具&#xff0c;如FileZilla的Server版&#xff0c;构建过程简单&#xff0c;好用。 下面看看。 二 安装FileZilla Server 当前下载版本是0.9.43&#xf…

2022 年中高职组“网络安全”赛项-海南省省竞赛任务书-1-B模块B-1-Windows操作系统渗透测试

前言 本章节我将带领大家一起重新模拟操作一次Windows渗透测试模块&#xff0c;并加固的流程。 任务概览 环境部署 我的实验复现环境&#xff1a; 服务器Windows server 2008 R2 攻击机Kali Linux 场景操作系统Windows 7 额外还有台交换机支持&#xff1a; 这里我使用的是…

【滑动窗口】变种题目:leetcode76:最小覆盖子串

前言 滑动窗口是算法的数组部分中非常重要的一个内容&#xff0c;关于滑动窗口的题目&#xff0c;我已经发布过相关的变种题目文章&#xff0c;链接如下&#xff0c;欢迎访问&#xff1a; 【滑动窗口】相关题目分析讲解:leetcode209,leetcode904 如果你不了解什么是滑动窗口&a…

蚁群算法(Ant Colony Optimization, ACO)

简介 蚁群算法&#xff08;Ant Colony Optimization, ACO&#xff09;是一种基于自然启发的优化算法&#xff0c;由意大利学者马可多里戈&#xff08;Marco Dorigo&#xff09;在1992年首次提出。它受自然界中蚂蚁觅食行为的启发&#xff0c;用于解决离散优化问题。 在自然界…

1-测试go-redis缓存数据

1-测试go-redis缓存数据 1.go-redis缓存数据测试效果 a.测试页面 测试页面&#xff1a;--这里使用 Postman 来做测试 http://127.0.0.1:8000/article/getone/3 http://127.0.0.1:8000/article/getone/4 http://127.0.0.1:8000/article/getone/5b.测试效果 查看终端&#xf…

计算机毕业设计SparkStreaming+Kafka图书推荐系统 豆瓣图书数据分析可视化大屏 豆瓣图书爬虫 知识图谱 图书大数据 大数据毕业设计 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

字符串的常用函数

目录 一、引入 二、13个字符串的常用函数 总结 一、引入 在C语言中&#xff0c;字符串被视为字符数组的序列&#xff0c;以空字符\0结尾。这个空字符不是数字0&#xff0c;而是一个特殊的控制字符&#xff0c;用于标记字符串的结束。例如&#xff0c;声明char name[7] {R,…

丹摩|重返丹摩(下)

目录 四.模型构建与训练 1.模型选择 (1). 机器学习模型 (2). 深度学习模型 (3). AutoML 功能 2.参数配置 (1). 模型参数 (2). 数据划分 (3). 超参数优化 3.模型训练与评估 (1). 训练模型 (2). 查看训练结果 (3). 模型评估 五.模型部署与应用 1.模型部署 (1). 直…

浪潮信息自动驾驶框架AutoDRRT 2.0,赋能高阶自动驾驶

随着自动驾驶技术的迅猛进步&#xff0c;BEVTransformer的感知模式为高阶自动驾驶带来了前所未有的精度、泛化能力和多模态融合效果&#xff0c;已成为众多顶尖汽车制造商的首选方案。然而&#xff0c;当前自动驾驶方案中的大模型算法参数规模剧增&#xff0c;对算力、数据IO及…

【电源专题】BUCK电源SW电压的平均值为什么等于输出电压?

在Buck电源测试过程中,我们会去测试SW开关节点的波形。那么从SW波形中我们能看出什么呢? 首先查看SW波形一般会看SW频率,通过SW波形的频率知道目前芯片的运行状态是什么。比如PSM还是PWM模式。 此外,还会看SW波形的占空比,通过占空比我们可以知道目前输出的状态是怎么样的…

微信分账系统供应链分润微信支付 (亲测源码)

搭建环境&#xff1a;nginxphp7.2mysql5.7 1.上传源码到网站根目录并解压 2.导入数据库文件到数据库 3.修改数据库链接文件/.env 4.设置运行目录为/public 5.伪静态设置成tp 6.后台地址&#xff1a;域名/zh9025.php 源码下载&#xff1a;https://download.csdn.net/down…