diff --git a/docker-compose.yml b/docker-compose.yml index a61dab7..05fa521 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,8 @@ version: "3" services: dvadmin-ui: container_name: dvadmin-ui + ports: + - "8080:8080" build: context: ./ dockerfile: ./docker_env/vue-ui/Dockerfile diff --git a/dvadmin-backend/application/__init__.py b/dvadmin-backend/application/__init__.py index 8b13789..e69de29 100644 --- a/dvadmin-backend/application/__init__.py +++ b/dvadmin-backend/application/__init__.py @@ -1 +0,0 @@ - diff --git a/dvadmin-backend/application/settings.py b/dvadmin-backend/application/settings.py index 7a6fae6..7e19586 100644 --- a/dvadmin-backend/application/settings.py +++ b/dvadmin-backend/application/settings.py @@ -51,6 +51,7 @@ INSTALLED_APPS = [ 'apps.vadmin.op_drf', 'apps.vadmin.system', 'apps.vadmin.celery', + 'apps.vadmin.monitor', ] MIDDLEWARE = [ @@ -328,3 +329,5 @@ CELERYBEAT_SCHEDULER = 'django_celery_beat.schedulers.DatabaseScheduler' # Back # ================================================= # # 接口权限 INTERFACE_PERMISSION = locals().get("INTERFACE_PERMISSION", False) +INTERFACE_PERMISSION = {locals().get("INTERFACE_PERMISSION", False)} +DJANGO_CELERY_BEAT_TZ_AWARE = False diff --git a/dvadmin-backend/application/urls.py b/dvadmin-backend/application/urls.py index 1bd1ed6..2a3a0ae 100644 --- a/dvadmin-backend/application/urls.py +++ b/dvadmin-backend/application/urls.py @@ -22,7 +22,7 @@ from django.urls import re_path, include from django.views.static import serve from rest_framework.views import APIView -from vadmin.utils.response import SuccessResponse +from apps.vadmin.utils.response import SuccessResponse class CaptchaRefresh(APIView): diff --git a/dvadmin-backend/apps/vadmin/monitor/__init__.py b/dvadmin-backend/apps/vadmin/monitor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dvadmin-backend/apps/vadmin/monitor/admin.py b/dvadmin-backend/apps/vadmin/monitor/admin.py new file mode 100644 index 0000000..e69de29 diff --git a/dvadmin-backend/apps/vadmin/monitor/apps.py b/dvadmin-backend/apps/vadmin/monitor/apps.py new file mode 100644 index 0000000..13ee922 --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MonitorConfig(AppConfig): + name = 'vadmin.monitor' + verbose_name = "系统监控" diff --git a/dvadmin-backend/apps/vadmin/monitor/filters.py b/dvadmin-backend/apps/vadmin/monitor/filters.py new file mode 100644 index 0000000..e80748e --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/filters.py @@ -0,0 +1,23 @@ +import django_filters + +from .models import Server, Monitor + + +class ServerFilter(django_filters.rest_framework.FilterSet): + """ + 服务器信息 简单过滤器 + """ + + class Meta: + model = Server + fields = '__all__' + + +class MonitorFilter(django_filters.rest_framework.FilterSet): + """ + 服务器监控信息 简单过滤器 + """ + + class Meta: + model = Monitor + fields = '__all__' diff --git a/dvadmin-backend/apps/vadmin/monitor/migrations/__init__.py b/dvadmin-backend/apps/vadmin/monitor/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dvadmin-backend/apps/vadmin/monitor/models/__init__.py b/dvadmin-backend/apps/vadmin/monitor/models/__init__.py new file mode 100644 index 0000000..0f0d1f8 --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/models/__init__.py @@ -0,0 +1,3 @@ +from ..models.monitor import Monitor +from ..models.server import Server +from ..models.sys_files import SysFiles diff --git a/dvadmin-backend/apps/vadmin/monitor/models/monitor.py b/dvadmin-backend/apps/vadmin/monitor/models/monitor.py new file mode 100644 index 0000000..7cf2bb5 --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/models/monitor.py @@ -0,0 +1,19 @@ +from django.db.models import CharField, ForeignKey, CASCADE + +from ...op_drf.models import CoreModel + + +class Monitor(CoreModel): + cpu_num = CharField(max_length=8, verbose_name='CPU核数') + cpu_sys = CharField(max_length=8, verbose_name='CPU已使用率') + mem_num = CharField(max_length=32, verbose_name='内存总数(KB)') + mem_sys = CharField(max_length=32, verbose_name='内存已使用大小(KB)') + seconds = CharField(max_length=32, verbose_name='系统已运行时间') + server = ForeignKey(to='monitor.Server', on_delete=CASCADE, verbose_name="关联服务器信息", db_constraint=False) + + class Meta: + verbose_name = '服务器监控信息' + verbose_name_plural = verbose_name + + def __str__(self): + return f"{self.server and self.server.name and self.server.ip}监控信息" diff --git a/dvadmin-backend/apps/vadmin/monitor/models/server.py b/dvadmin-backend/apps/vadmin/monitor/models/server.py new file mode 100644 index 0000000..d05140f --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/models/server.py @@ -0,0 +1,20 @@ +from django.db import models +from django.db.models import CharField + +from apps.vadmin.op_drf.fields import UpdateDateTimeField, CreateDateTimeField + + +class Server(models.Model): + name = CharField(max_length=256, verbose_name='服务器名称', null=True, blank=True) + ip = CharField(max_length=32, verbose_name="ip地址") + os = CharField(max_length=32, verbose_name="操作系统") + remark = CharField(max_length=256, verbose_name="备注", null=True, blank=True) + update_datetime = UpdateDateTimeField() # 修改时间 + create_datetime = CreateDateTimeField() # 创建时间 + + class Meta: + verbose_name = '服务器信息' + verbose_name_plural = verbose_name + + def __str__(self): + return f"{self.name and self.ip}" diff --git a/dvadmin-backend/apps/vadmin/monitor/models/sys_files.py b/dvadmin-backend/apps/vadmin/monitor/models/sys_files.py new file mode 100644 index 0000000..41557cf --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/models/sys_files.py @@ -0,0 +1,19 @@ +from django.db.models import CharField, ForeignKey, CASCADE + +from ...op_drf.models import CoreModel + + +class SysFiles(CoreModel): + dir_name = CharField(max_length=32, verbose_name='磁盘路径') + sys_type_name = CharField(max_length=400, verbose_name='系统文件类型') + type_name = CharField(max_length=32, verbose_name='盘符类型') + total = CharField(max_length=32, verbose_name='磁盘总大小(KB)') + disk_sys = CharField(max_length=32, verbose_name='已使用大小(KB)') + monitor = ForeignKey(to='monitor.Monitor', on_delete=CASCADE, verbose_name="关联服务器监控信息", db_constraint=False) + + class Meta: + verbose_name = '系统磁盘' + verbose_name_plural = verbose_name + + def __str__(self): + return f"{self.creator and self.creator.name}" diff --git a/dvadmin-backend/apps/vadmin/monitor/serializers.py b/dvadmin-backend/apps/vadmin/monitor/serializers.py new file mode 100644 index 0000000..69d789e --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/serializers.py @@ -0,0 +1,40 @@ +from .models import Server, Monitor +from ..op_drf.serializers import CustomModelSerializer + + +# ================================================= # +# ************** 服务器信息 序列化器 ************** # +# ================================================= # + +class ServerSerializer(CustomModelSerializer): + """ + 服务器信息 简单序列化器 + """ + + class Meta: + model = Server + fields = ("id", "ip", "name", "os", "remark") + + +class UpdateServerSerializer(CustomModelSerializer): + """ + 服务器信息 简单序列化器 + """ + + class Meta: + model = Server + fields = ("name", "remark") + + +# ================================================= # +# ************** 服务器监控信息 序列化器 ************** # +# ================================================= # + +class MonitorSerializer(CustomModelSerializer): + """ + 服务器监控信息 简单序列化器 + """ + + class Meta: + model = Monitor + fields = '__all__' diff --git a/dvadmin-backend/apps/vadmin/monitor/tasks.py b/dvadmin-backend/apps/vadmin/monitor/tasks.py new file mode 100644 index 0000000..ba734f7 --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/tasks.py @@ -0,0 +1,89 @@ +import datetime +import logging +import sys +import time + +import psutil + +from ..monitor.models import Server, Monitor, SysFiles +from ..op_drf.response import SuccessResponse +from ..system.models import ConfigSettings +from ..utils.decorators import BaseCeleryApp + +logger = logging.getLogger(__name__) +from platform import platform + + +def getIP(): + """获取ipv4地址""" + dic = psutil.net_if_addrs() + ipv4_list = [] + for adapter in dic: + snicList = dic[adapter] + for snic in snicList: + if snic.family.name == 'AF_INET': + ipv4 = snic.address + if ipv4 != '127.0.0.1': + ipv4_list.append(ipv4) + if len(ipv4_list) >= 1: + return ipv4_list[0] + else: + return None + + +@BaseCeleryApp(name='apps.vadmin.monitor.tasks.get_monitor_info') +def get_monitor_info(): + """ + 定时获取系统监控信息 + :return: + """ + # 获取服务器 + ip = getIP() + if not ip: + logger.error("无法获取到IP") + return + server_obj, create = Server.objects.get_or_create(ip=ip) + if create: + server_obj.name = ip + terse = ('terse' in sys.argv or '--terse' in sys.argv) + aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv) + server_obj.os = platform(aliased, terse) + server_obj.save() + + # 获取CPU和内存信息 + mem = psutil.virtual_memory() + monitor_obj = Monitor() + monitor_obj.cpu_num = psutil.cpu_count() + monitor_obj.cpu_sys = float(psutil.cpu_percent(0.1)) + monitor_obj.mem_num = int(mem.total / 1024) + monitor_obj.mem_sys = int(mem.used / 1024) + monitor_obj.seconds = time.strftime("%d天 %H 小时 %M 分 %S 秒", time.gmtime(int(time.time()) - int(psutil.boot_time()))) + monitor_obj.server = server_obj + monitor_obj.save() + + # 保存磁盘信息 + for ele in psutil.disk_partitions(): + disk = psutil.disk_usage('/') + + sys_files_obj = SysFiles() + sys_files_obj.dir_name = ele.mountpoint + sys_files_obj.sys_type_name = ele.opts + sys_files_obj.type_name = ele.fstype + sys_files_obj.total = disk.total + sys_files_obj.disk_sys = disk.used + sys_files_obj.monitor = monitor_obj + sys_files_obj.save() + + return SuccessResponse(msg="") + + +@BaseCeleryApp(name='apps.vadmin.monitor.tasks.clean_surplus_monitor_info') +def clean_surplus_monitor_info(): + """ + 定时清理多余 系统监控信息 + :return: + """ + config_settings_obj = ConfigSettings.objects.filter(configKey='sys.monitor.info.save_days').first() + Monitor.objects.filter( + update_datetime__lt=datetime.timedelta(days=int(config_settings_obj.configValue or 30))).delete() + logger.info(f"成功清空{config_settings_obj.configValue}天前数据") diff --git a/dvadmin-backend/apps/vadmin/monitor/tests.py b/dvadmin-backend/apps/vadmin/monitor/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/dvadmin-backend/apps/vadmin/monitor/urls.py b/dvadmin-backend/apps/vadmin/monitor/urls.py new file mode 100644 index 0000000..49feeef --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/urls.py @@ -0,0 +1,16 @@ +from django.urls import re_path +from rest_framework.routers import DefaultRouter + +from .views import ServerModelViewSet, MonitorModelViewSet + +router = DefaultRouter() +router.register(r'server', ServerModelViewSet) +router.register(r'monitor', MonitorModelViewSet) + +urlpatterns = [ + re_path('monitor/info/(?P.*)/', MonitorModelViewSet.as_view({'get': 'get_monitor_info'})), + re_path('monitor/rate/(?P.*)/', MonitorModelViewSet.as_view({'get': 'get_rate_info'})), + re_path('monitor/enabled/', MonitorModelViewSet.as_view({'get': 'enabled_monitor_info'})), + re_path('monitor/clean/', MonitorModelViewSet.as_view({'get': 'clean_all'})), +] +urlpatterns += router.urls diff --git a/dvadmin-backend/apps/vadmin/monitor/views.py b/dvadmin-backend/apps/vadmin/monitor/views.py new file mode 100644 index 0000000..417ffc4 --- /dev/null +++ b/dvadmin-backend/apps/vadmin/monitor/views.py @@ -0,0 +1,181 @@ +from django_celery_beat.models import PeriodicTask, IntervalSchedule, CrontabSchedule +from rest_framework.request import Request + +from .filters import ServerFilter, MonitorFilter +from .models import Server, Monitor, SysFiles +from .serializers import ServerSerializer, MonitorSerializer, UpdateServerSerializer +from ..op_drf.response import SuccessResponse, ErrorResponse +from ..op_drf.viewsets import CustomModelViewSet +from ..permission.permissions import CommonPermission +from ..system.models import ConfigSettings + + +class ServerModelViewSet(CustomModelViewSet): + """ + 服务器信息 模型的CRUD视图 + """ + queryset = Server.objects.all() + serializer_class = ServerSerializer + update_serializer_class = UpdateServerSerializer + # extra_filter_backends = [DataLevelPermissionsFilter] + filter_class = ServerFilter + update_extra_permission_classes = (CommonPermission,) + destroy_extra_permission_classes = (CommonPermission,) + create_extra_permission_classes = (CommonPermission,) + ordering = '-create_datetime' # 默认排序 + + +class MonitorModelViewSet(CustomModelViewSet): + """ + 服务器监控信息 模型的CRUD视图 + """ + queryset = Monitor.objects.all() + serializer_class = MonitorSerializer + # extra_filter_backends = [DataLevelPermissionsFilter] + filter_class = MonitorFilter + update_extra_permission_classes = (CommonPermission,) + destroy_extra_permission_classes = (CommonPermission,) + create_extra_permission_classes = (CommonPermission,) + ordering = '-create_datetime' # 默认排序 + + def get_rate_info(self, request: Request, *args, **kwargs): + """ + 获取使用率 监控信息 + :param request: + :param args: + :param kwargs: + :return: + """ + pk = kwargs.get("pk") + queryset = self.filter_queryset(self.get_queryset()) + queryset = queryset.filter(server__id=pk).order_by("-create_datetime") + # 间隔取值 + queryset_count = queryset.count() + Interval_num = 1 if queryset_count < 200 else int(queryset_count / 100) + queryset = queryset.values('cpu_sys', 'mem_num', 'mem_sys')[::Interval_num][:100] + data = { + "cpu": [], + "memory": [], + } + for ele in queryset: + data["cpu"].append(float(ele.get('cpu_sys', 0))) + data["memory"].append(float(ele.get('mem_num', 0)) and round(float(ele.get('mem_sys', 0)) / + float(ele.get('mem_num', 0)), 4)) + return SuccessResponse(data=data) + + def get_monitor_info(self, request: Request, *args, **kwargs): + """ + 最新的服务器状态信息 + :param request: + :param args: + :param kwargs: + :return: + """ + pk = kwargs.get("pk") + instance = Monitor.objects.filter(server__id=pk).order_by("-create_datetime").first() + if not instance: + return ErrorResponse(msg="未找到服务器信息id") + serializer = self.get_serializer(instance) + data = serializer.data + return SuccessResponse(data={ + "cpu": { + "total": int(data.get('cpu_num'), 0), + "used": "", # cpu核心 可不传,如指cpu当前主频,该值可以传 + "rate": float(data.get('cpu_sys', 0)) / 100, + "unit": "核心", # 默认单位 核心 + }, + "memory": { + "total": int(int(data.get('mem_num', 0)) / 1024), + "used": int(int(data.get('mem_sys', 0)) / 1024), + "rate": int(data.get('mem_num', 0)) and round(int(data.get('mem_sys', 0)) / + int(data.get('mem_num', 0)), 4), + "unit": "MB", # 默认单位 MB + }, + "disk": [{ + "dir_name": ele.get('dir_name'), + "total": int(int(ele.get('total', 0)) / 1024 / 1024 / 1024), + "used": int(int(ele.get('disk_sys', 0)) / 1024 / 1024 / 1024), + "rate": int(ele.get('total', 0)) and round(int(ele.get('disk_sys', 0)) / int(ele.get('total', 0)), + 4), + "unit": "GB", # 默认单位 GB + } for ele in SysFiles.objects.filter(monitor=instance).values('dir_name', 'total', 'disk_sys')] + }) + + def enabled_monitor_info(self, request: Request, *args, **kwargs): + """ + 更新和获取监控信息 + :param request: + :param args: + :param kwargs: + :return: + """ + enabled = request.query_params.get('enabled', None) + save_days = request.query_params.get('save_days', None) + interval = request.query_params.get('interval', None) + # 定时获取系统监控信息 + periodictask_obj = PeriodicTask.objects.filter(task='apps.vadmin.monitor.tasks.get_monitor_info').first() + if not periodictask_obj: + intervalschedule_obj, _ = IntervalSchedule.objects.get_or_create(every=5, period="seconds") + periodictask_obj = PeriodicTask() + periodictask_obj.task = "apps.vadmin.monitor.tasks.get_monitor_info" + periodictask_obj.name = "定时获取系统监控信息" + periodictask_obj.interval = intervalschedule_obj + periodictask_obj.enabled = False + periodictask_obj.save() + + # 定时清理多余 系统监控信息 + clean_task_obj = PeriodicTask.objects.filter( + task='apps.vadmin.monitor.tasks.clean_surplus_monitor_info').first() + if not clean_task_obj: + crontab_obj, _ = CrontabSchedule.objects.get_or_create(day_of_month="*", day_of_week="*", hour="1", + minute="0", month_of_year="*") + clean_task_obj = PeriodicTask() + clean_task_obj.task = "apps.vadmin.monitor.tasks.clean_surplus_monitor_info" + clean_task_obj.name = "定时清理多余-系统监控信息" + clean_task_obj.crontab = crontab_obj + clean_task_obj.enabled = True + clean_task_obj.save() + # 配置添加 + config_obj = ConfigSettings.objects.filter(configKey='sys.monitor.info.save_days').first() + if not config_obj: + config_obj = ConfigSettings() + config_obj.configKey = "sys.monitor.info.save_days" + config_obj.configName = "定时清理多余系统监控信息" + config_obj.configValue = "30" + config_obj.configType = "Y" + config_obj.status = "1" + config_obj.remark = "定时清理多余-系统监控信息,默认30天" + config_obj.save() + + if enabled: + # 更新监控状态 + periodictask_obj.enabled = True if enabled == "1" else False + periodictask_obj.save() + + # 更新 定时清理多余 系统监控信息 状态 + clean_task_obj.enabled = True if enabled == "1" else False + clean_task_obj.save() + # 更新保留天数 + if save_days and config_obj: + config_obj.configValue = save_days + config_obj.save() + # 更新监控获取频率 + if interval: + periodictask_obj.interval.every = interval + periodictask_obj.interval.save() + return SuccessResponse(data={ + "enabled": periodictask_obj.enabled, + "interval": periodictask_obj.interval.every, + "save_days": config_obj.configValue if config_obj else "30", + }) + + def clean_all(self, request: Request, *args, **kwargs): + """ + 清空监控信息 + :param request: + :param args: + :param kwargs: + :return: + """ + self.get_queryset().delete() + return SuccessResponse(msg="清空成功") diff --git a/dvadmin-backend/apps/vadmin/op_drf/models.py b/dvadmin-backend/apps/vadmin/op_drf/models.py index 1eead22..2bffdeb 100644 --- a/dvadmin-backend/apps/vadmin/op_drf/models.py +++ b/dvadmin-backend/apps/vadmin/op_drf/models.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.db import models from django.db.models import SET_NULL @@ -24,7 +25,7 @@ class CoreModel(models.Model): 增加审计字段, 覆盖字段时, 字段名称请勿修改, 必须统一审计字段名称 """ description = DescriptionField() # 描述 - creator = models.ForeignKey(to='permission.UserProfile', related_query_name='creator_query', null=True, + creator = models.ForeignKey(to=settings.AUTH_USER_MODEL, related_query_name='creator_query', null=True, verbose_name='创建者', on_delete=SET_NULL, db_constraint=False) # 创建者 modifier = ModifierCharField() # 修改者 dept_belong_id = models.CharField(max_length=64, verbose_name="数据归属部门", null=True, blank=True) diff --git a/dvadmin-backend/apps/vadmin/permission/filters.py b/dvadmin-backend/apps/vadmin/permission/filters.py index bf302b1..8f8d8da 100644 --- a/dvadmin-backend/apps/vadmin/permission/filters.py +++ b/dvadmin-backend/apps/vadmin/permission/filters.py @@ -1,8 +1,11 @@ import django_filters +from django.contrib.auth import get_user_model -from ..permission.models import Menu, Dept, Post, Role, UserProfile +from ..permission.models import Menu, Dept, Post, Role from ..utils.model_util import get_dept +UserProfile = get_user_model() + class MenuFilter(django_filters.rest_framework.FilterSet): """ diff --git a/dvadmin-backend/apps/vadmin/permission/management/commands/init.py b/dvadmin-backend/apps/vadmin/permission/management/commands/init.py index f749f31..3db4d21 100644 --- a/dvadmin-backend/apps/vadmin/permission/management/commands/init.py +++ b/dvadmin-backend/apps/vadmin/permission/management/commands/init.py @@ -1,6 +1,7 @@ import logging import os +from django.conf import settings from django.core.management.base import BaseCommand from django.db import connection @@ -75,6 +76,7 @@ class Command(BaseCommand): parser.add_argument('-N', nargs='*') def handle(self, *args, **options): + user_name = "_".join(settings.AUTH_USER_MODEL.lower().split(".")) init_dict = { 'system_dictdata': [os.path.join('system', 'system_dictdata.sql'), '字典管理', 'system_dictdata'], 'system_dictdetails': [os.path.join('system', 'system_dictdetails.sql'), '字典详情', 'system_dictdetails'], @@ -86,8 +88,7 @@ class Command(BaseCommand): 'permission_role': [os.path.join('permission', 'permission_role.sql'), '角色管理', ','.join(['permission_role', 'permission_role_dept', 'permission_role_menu'])], 'permission_userprofile': [os.path.join('permission', 'permission_userprofile.sql'), '用户管理', ','.join( - ['permission_userprofile_groups', 'permission_userprofile', 'permission_userprofile_role', - 'permission_userprofile_post'])] + [f'{user_name}_groups', f'{user_name}', f'{user_name}_role', f'{user_name}_post'])] } init_name = options.get('init_name') is_yes = None diff --git a/dvadmin-backend/apps/vadmin/permission/models/dept.py b/dvadmin-backend/apps/vadmin/permission/models/dept.py index f8b6631..a339650 100644 --- a/dvadmin-backend/apps/vadmin/permission/models/dept.py +++ b/dvadmin-backend/apps/vadmin/permission/models/dept.py @@ -11,7 +11,7 @@ class Dept(CoreModel): phone = CharField(max_length=32, verbose_name="联系电话", null=True, blank=True) email = CharField(max_length=32, verbose_name="邮箱", null=True, blank=True) status = CharField(max_length=8, verbose_name="部门状态", null=True, blank=True) - parentId = ForeignKey(to='Dept', on_delete=CASCADE, default=False, verbose_name="上级部门", + parentId = ForeignKey(to='permission.Dept', on_delete=CASCADE, default=False, verbose_name="上级部门", db_constraint=False, null=True, blank=True) class Meta: diff --git a/dvadmin-backend/apps/vadmin/permission/models/role.py b/dvadmin-backend/apps/vadmin/permission/models/role.py index dffa586..d34b91e 100644 --- a/dvadmin-backend/apps/vadmin/permission/models/role.py +++ b/dvadmin-backend/apps/vadmin/permission/models/role.py @@ -18,8 +18,8 @@ class Role(CoreModel): admin = BooleanField(default=False, verbose_name="是否为admin") dataScope = CharField(max_length=8,default='1', choices=DATASCOPE_CHOICES, verbose_name="权限范围",) remark = TextField(verbose_name="备注", help_text="备注", null=True, blank=True) - dept = ManyToManyField(to='Dept', verbose_name='数据权限-关联部门', db_constraint=False) - menu = ManyToManyField(to='Menu', verbose_name='关联菜单权限', db_constraint=False) + dept = ManyToManyField(to='permission.Dept', verbose_name='数据权限-关联部门', db_constraint=False) + menu = ManyToManyField(to='permission.Menu', verbose_name='关联菜单权限', db_constraint=False) class Meta: verbose_name = '角色管理' diff --git a/dvadmin-backend/apps/vadmin/permission/models/users.py b/dvadmin-backend/apps/vadmin/permission/models/users.py index 486f36c..b93849c 100644 --- a/dvadmin-backend/apps/vadmin/permission/models/users.py +++ b/dvadmin-backend/apps/vadmin/permission/models/users.py @@ -1,5 +1,6 @@ from uuid import uuid4 +from django.conf import settings from django.contrib.auth.models import UserManager, AbstractUser from django.core.cache import cache from django.db.models import IntegerField, ForeignKey, CharField, TextField, ManyToManyField, CASCADE @@ -22,9 +23,9 @@ class UserProfile(AbstractUser, CoreModel): gender = CharField(max_length=8, verbose_name="性别", null=True, blank=True) remark = TextField(verbose_name="备注", null=True) user_type = IntegerField(default=0, verbose_name="用户类型") - post = ManyToManyField(to='Post', verbose_name='关联岗位', db_constraint=False) - role = ManyToManyField(to='Role', verbose_name='关联角色', db_constraint=False) - dept = ForeignKey(to='Dept', verbose_name='归属部门', on_delete=CASCADE, db_constraint=False, null=True, blank=True) + post = ManyToManyField(to='permission.Post', verbose_name='关联岗位', db_constraint=False) + role = ManyToManyField(to='permission.Role', verbose_name='关联角色', db_constraint=False) + dept = ForeignKey(to='permission.Dept', verbose_name='归属部门', on_delete=CASCADE, db_constraint=False, null=True, blank=True) @property def get_user_interface_dict(self): @@ -51,6 +52,7 @@ class UserProfile(AbstractUser, CoreModel): return cache.delete(f'permission_interface_dict_{self.username}') class Meta: + abstract = settings.AUTH_USER_MODEL != 'permission.UserProfile' verbose_name = '用户管理' verbose_name_plural = verbose_name diff --git a/dvadmin-backend/apps/vadmin/permission/serializers.py b/dvadmin-backend/apps/vadmin/permission/serializers.py index 8fc641e..ac82342 100644 --- a/dvadmin-backend/apps/vadmin/permission/serializers.py +++ b/dvadmin-backend/apps/vadmin/permission/serializers.py @@ -1,10 +1,13 @@ +from django.contrib.auth import get_user_model from rest_framework import serializers from rest_framework.validators import UniqueValidator from ..op_drf.serializers import CustomModelSerializer -from ..permission.models import Menu, Dept, Post, Role, UserProfile +from ..permission.models import Menu, Dept, Post, Role from ..system.models import MessagePush +UserProfile = get_user_model() + # ================================================= # # ************** 菜单管理 序列化器 ************** # diff --git a/dvadmin-backend/apps/vadmin/permission/views.py b/dvadmin-backend/apps/vadmin/permission/views.py index 8ece4fa..f11def9 100644 --- a/dvadmin-backend/apps/vadmin/permission/views.py +++ b/dvadmin-backend/apps/vadmin/permission/views.py @@ -1,4 +1,4 @@ -from django.contrib.auth import authenticate +from django.contrib.auth import authenticate, get_user_model from rest_framework.request import Request from rest_framework.views import APIView @@ -6,7 +6,7 @@ from .permissions import CommonPermission, DeptDestroyPermission from ..op_drf.filters import DataLevelPermissionsFilter from ..op_drf.viewsets import CustomModelViewSet from ..permission.filters import MenuFilter, DeptFilter, PostFilter, RoleFilter, UserProfileFilter -from ..permission.models import Role, Menu, Dept, Post, UserProfile +from ..permission.models import Role, Menu, Dept, Post from ..permission.serializers import UserProfileSerializer, MenuSerializer, RoleSerializer, \ MenuCreateUpdateSerializer, DeptSerializer, DeptCreateUpdateSerializer, PostSerializer, PostCreateUpdateSerializer, \ RoleCreateUpdateSerializer, DeptTreeSerializer, MenuTreeSerializer, UserProfileCreateUpdateSerializer, \ @@ -15,6 +15,8 @@ from ..permission.serializers import UserProfileSerializer, MenuSerializer, Role from ..system.models import DictDetails from ..utils.response import SuccessResponse, ErrorResponse +UserProfile = get_user_model() + class GetUserProfileView(APIView): """ diff --git a/dvadmin-backend/apps/vadmin/scripts/__init__.py b/dvadmin-backend/apps/vadmin/scripts/__init__.py index fd9177f..e0d0cfa 100644 --- a/dvadmin-backend/apps/vadmin/scripts/__init__.py +++ b/dvadmin-backend/apps/vadmin/scripts/__init__.py @@ -1,5 +1,7 @@ import os +from django.conf import settings + def getSql(filename): """ @@ -9,6 +11,10 @@ def getSql(filename): """ abspath = os.path.abspath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) pwd = os.path.join(abspath, 'scripts', filename) - with open(pwd,'rb') as fp: + with open(pwd, 'rb') as fp: content = fp.read().decode('utf8') + if filename == "permission/permission_userprofile.sql": + user_name = "_".join(settings.AUTH_USER_MODEL.lower().split(".")) + content = content.replace("permission_userprofile", user_name). \ + replace("userprofile", settings.AUTH_USER_MODEL.lower().split(".")[-1]) return [ele for ele in content.split('\n') if not ele.startswith('--') and ele.strip(' ')] diff --git a/dvadmin-backend/apps/vadmin/system/models/dict_details.py b/dvadmin-backend/apps/vadmin/system/models/dict_details.py index 1db9b5c..8cf18ac 100644 --- a/dvadmin-backend/apps/vadmin/system/models/dict_details.py +++ b/dvadmin-backend/apps/vadmin/system/models/dict_details.py @@ -9,7 +9,7 @@ class DictDetails(CoreModel): is_default = BooleanField(verbose_name="是否默认", default=False) status = CharField(max_length=2, verbose_name="字典状态") sort = CharField(max_length=256, verbose_name="字典排序") - dict_data = ForeignKey(to='DictData', on_delete=CASCADE, verbose_name="关联字典", db_constraint=False) + dict_data = ForeignKey(to='system.DictData', on_delete=CASCADE, verbose_name="关联字典", db_constraint=False) remark = CharField(max_length=256, verbose_name="备注", null=True, blank=True) @classmethod diff --git a/dvadmin-backend/apps/vadmin/system/models/message_push.py b/dvadmin-backend/apps/vadmin/system/models/message_push.py index efbde44..37bc089 100644 --- a/dvadmin-backend/apps/vadmin/system/models/message_push.py +++ b/dvadmin-backend/apps/vadmin/system/models/message_push.py @@ -1,9 +1,9 @@ +from django.conf import settings from django.db import models from django.db.models import * from ...op_drf.fields import UpdateDateTimeField, CreateDateTimeField from ...op_drf.models import CoreModel -from ...permission.models import UserProfile """ 消息通知模型 @@ -17,7 +17,7 @@ class MessagePush(CoreModel): is_reviewed = BooleanField(default=True, verbose_name="是否审核") status = CharField(max_length=8, verbose_name="通知状态") to_path = CharField(max_length=256, verbose_name="跳转路径", null=True, blank=True, ) - user = ManyToManyField(to="permission.UserProfile", + user = ManyToManyField(to=settings.AUTH_USER_MODEL, related_name="user", related_query_name="user_query", through='MessagePushUser', through_fields=('message_push', 'user')) @@ -34,7 +34,7 @@ class MessagePushUser(models.Model): related_name="messagepushuser_message_push", verbose_name='消息通知', help_text='消息通知') - user = ForeignKey(UserProfile, on_delete=CASCADE, db_constraint=False, + user = ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=CASCADE, db_constraint=False, related_name="messagepushuser_user", verbose_name='用户', help_text='用户') is_read = BooleanField(default=False, verbose_name="是否已读") diff --git a/dvadmin-backend/apps/vadmin/system/urls.py b/dvadmin-backend/apps/vadmin/system/urls.py index 7084014..654bac5 100644 --- a/dvadmin-backend/apps/vadmin/system/urls.py +++ b/dvadmin-backend/apps/vadmin/system/urls.py @@ -3,7 +3,7 @@ from rest_framework.routers import DefaultRouter from ..system.views import DictDataModelViewSet, DictDetailsModelViewSet, \ ConfigSettingsModelViewSet, SaveFileModelViewSet, MessagePushModelViewSet, LoginInforModelViewSet, \ - OperationLogModelViewSet, CeleryLogModelViewSet + OperationLogModelViewSet, CeleryLogModelViewSet, SystemInfoApiView router = DefaultRouter() router.register(r'dict/type', DictDataModelViewSet) @@ -48,6 +48,7 @@ urlpatterns = [ re_path('celery_log/export/', CeleryLogModelViewSet.as_view({'get': 'export', })), # 清除废弃文件 re_path('clearsavefile/', SaveFileModelViewSet.as_view({'post': 'clearsavefile', })), - + # 获取系统信息cpu、内存、硬盘 + re_path('sys/info/', SystemInfoApiView.as_view()) ] urlpatterns += router.urls diff --git a/dvadmin-backend/apps/vadmin/system/views.py b/dvadmin-backend/apps/vadmin/system/views.py index ec4a38a..c2d716b 100644 --- a/dvadmin-backend/apps/vadmin/system/views.py +++ b/dvadmin-backend/apps/vadmin/system/views.py @@ -4,6 +4,7 @@ from django.conf import settings from django.core.cache import cache from django.db.models import Q from rest_framework.request import Request +from rest_framework.views import APIView from .models import LoginInfor, OperationLog, CeleryLog from ..op_drf.filters import DataLevelPermissionsFilter @@ -23,6 +24,7 @@ from ..system.serializers import DictDataSerializer, DictDataCreateUpdateSeriali from ..utils.export_excel import export_excel_save_model from ..utils.file_util import get_all_files, remove_empty_dir, delete_files from ..utils.response import SuccessResponse +from ..utils.system_info_utils import get_memory_used_percent, get_cpu_used_percent, get_disk_used_percent class DictDataModelViewSet(CustomModelViewSet): @@ -329,3 +331,21 @@ class CeleryLogModelViewSet(CustomModelViewSet): """ self.get_queryset().delete() return SuccessResponse(msg="清空成功") + + +class SystemInfoApiView(APIView): + """ + 系统服务监控视图 + """ + + def get(self, request, *args, **kwargs): + # 获取内存使用率 + memory_used_percent = get_memory_used_percent() + # 获取cpu使用率 + cpu_used_percent = get_cpu_used_percent() + # 获取硬盘使用率 + disk_used_percent = get_disk_used_percent() + return SuccessResponse(data={"memory_used_percent": memory_used_percent, + "cpu_used_percent": cpu_used_percent, + "disk_used_percent": disk_used_percent + }) diff --git a/dvadmin-backend/apps/vadmin/urls.py b/dvadmin-backend/apps/vadmin/urls.py index cf4051d..e1354f6 100644 --- a/dvadmin-backend/apps/vadmin/urls.py +++ b/dvadmin-backend/apps/vadmin/urls.py @@ -54,5 +54,6 @@ urlpatterns = [ re_path(r'^permission/', include('apps.vadmin.permission.urls')), re_path(r'^system/', include('apps.vadmin.system.urls')), re_path(r'^celery/', include('apps.vadmin.celery.urls')), + re_path(r'^monitor/', include('apps.vadmin.monitor.urls')), ] diff --git a/dvadmin-backend/utils/system_info_utils.py b/dvadmin-backend/apps/vadmin/utils/system_info_utils.py similarity index 69% rename from dvadmin-backend/utils/system_info_utils.py rename to dvadmin-backend/apps/vadmin/utils/system_info_utils.py index 69f34c9..88d9895 100644 --- a/dvadmin-backend/utils/system_info_utils.py +++ b/dvadmin-backend/apps/vadmin/utils/system_info_utils.py @@ -4,6 +4,27 @@ import psutil as psutil +def get_cpu_info(): + """ + 获取cpu所有信息 + """ + pass + + +def get_memory_info(): + """ + 获取内存所有信息 + """ + pass + + +def get_disk_info(): + """ + 获取硬盘所有信息 + """ + pass + + def get_cpu_used_percent(): """ 获取CPU运行情况 @@ -31,7 +52,5 @@ def get_disk_used_percent(): pass - - if __name__ == '__main__': - get_cpu_used_percent() + get_disk_used_percent() diff --git a/dvadmin-ui/.env.development b/dvadmin-ui/.env.development index 5acf1b3..8d9744e 100755 --- a/dvadmin-ui/.env.development +++ b/dvadmin-ui/.env.development @@ -3,7 +3,7 @@ ENV = 'development' # 若依管理系统/开发环境 # VUE_APP_BASE_API = 'https://api.django-vue-admin.com' -VUE_APP_BASE_API = 'http://127.0.0.1:8000' +VUE_APP_BASE_API = 'http://127.0.0.1:8888' # 路由懒加载 VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/dvadmin-ui/package.json b/dvadmin-ui/package.json index beaf7ec..f27a1ff 100755 --- a/dvadmin-ui/package.json +++ b/dvadmin-ui/package.json @@ -41,14 +41,16 @@ "axios": "0.21.0", "clipboard": "2.0.6", "core-js": "3.8.1", - "echarts": "4.9.0", + "echarts": "^4.9.0", "element-ui": "2.15.0", + "eslint-loader": "^4.0.2", "file-saver": "2.0.4", "fuse.js": "6.4.3", "highlight.js": "9.18.5", "js-beautify": "1.13.0", "js-cookie": "2.2.1", "jsencrypt": "3.0.0-rc.1", + "lodash": "^4.17.21", "moment": "^2.29.1", "nprogress": "0.2.0", "quill": "1.3.7", @@ -58,6 +60,7 @@ "vue-count-to": "1.0.13", "vue-cropper": "0.5.5", "vue-router": "3.4.9", + "vue-types": "^2.0.3", "vuedraggable": "2.24.3", "vuex": "3.6.0" }, @@ -65,6 +68,7 @@ "@vue/cli-plugin-babel": "4.4.6", "@vue/cli-plugin-eslint": "4.4.6", "@vue/cli-service": "4.4.6", + "@vue/composition-api": "^1.0.0-rc.6", "babel-eslint": "10.1.0", "chalk": "4.1.0", "connect": "3.6.6", diff --git a/dvadmin-ui/src/api/vadmin/menu.js b/dvadmin-ui/src/api/vadmin/menu.js index 9fc5b52..205e8dd 100755 --- a/dvadmin-ui/src/api/vadmin/menu.js +++ b/dvadmin-ui/src/api/vadmin/menu.js @@ -3,7 +3,7 @@ import request from '@/utils/request' // 获取路由 export const getRouters = () => { return request({ - url: '/admin/getRouters', + url: '/admin/getRouters/', method: 'get' }) } diff --git a/dvadmin-ui/src/api/vadmin/monitor/online.js b/dvadmin-ui/src/api/vadmin/monitor/online.js index bd22137..ca3348b 100755 --- a/dvadmin-ui/src/api/vadmin/monitor/online.js +++ b/dvadmin-ui/src/api/vadmin/monitor/online.js @@ -3,7 +3,7 @@ import request from '@/utils/request' // 查询在线用户列表 export function list(query) { return request({ - url: '/monitor/online/list', + url: '/admin/monitor/online/list', method: 'get', params: query }) @@ -12,7 +12,7 @@ export function list(query) { // 强退用户 export function forceLogout(tokenId) { return request({ - url: '/monitor/online/' + tokenId, + url: '/admin/monitor/online/' + tokenId, method: 'delete' }) } diff --git a/dvadmin-ui/src/api/vadmin/monitor/server.js b/dvadmin-ui/src/api/vadmin/monitor/server.js index feed783..e25be29 100755 --- a/dvadmin-ui/src/api/vadmin/monitor/server.js +++ b/dvadmin-ui/src/api/vadmin/monitor/server.js @@ -1,9 +1,65 @@ import request from '@/utils/request' -// 查询服务器详细 -export function getServer() { +// 查询服务器信息详细 +export function getServerList(params) { return request({ - url: '/monitor/server', + url: 'admin/monitor/server/', + params, method: 'get' }) -} \ No newline at end of file +} + +// 修改服务器信息 +export function updateServerInfo(id, data) { + let {name, remark} = data; + return request({ + url: `admin/monitor/server/${id}/`, + data: { + name, + remark + }, + method: 'PUT' + }) +} + +// 获取监控配置信息 +export function getMonitorStatusInfo() { + return request({ + url: 'admin/monitor/monitor/enabled/', + method: 'get' + }) +} + +// 更新监控配置信息 +export function updateMonitorStatusInfo(params) { + return request({ + url: 'admin/monitor/monitor/enabled/', + params, + method: 'get' + }) +} + +// 清空记录 +export function cleanMonitorLog() { + return request({ + url: 'admin/monitor/monitor/clean/', + method: 'delete' + }) +} + +// 获取监控记录 +export function getMonitorLogs(id, params) { + return request({ + url: `admin/monitor/monitor/rate/${id}/`, + params, + method: 'get' + }) +} + +// 获取服务器最新监控日志信息 +export function getServerLatestLog(id) { + return request({ + url: `admin/monitor/monitor/info/${id}/`, + method: 'get' + }) +} diff --git a/dvadmin-ui/src/store/modules/permission.js b/dvadmin-ui/src/store/modules/permission.js index 00d4194..3be95be 100755 --- a/dvadmin-ui/src/store/modules/permission.js +++ b/dvadmin-ui/src/store/modules/permission.js @@ -24,11 +24,28 @@ const permission = { return new Promise(resolve => { // 向后端请求路由数据 getRouters().then(res => { - const data = handleTree(res.data, "id"); + let tempData = handleTree(res.data, "id"); + tempData[2].children.push({ + component: "vadmin/monitor/server/index", + hidden: false, + id: 97, + meta: {title: "服务监控", icon: "server", noCache: false}, + name: "server", + orderNum: 3, + parentId: 66, + path: "server", + redirect: "server" + }) + const data = tempData + + + // console.log("handleTree:", data) const sdata = JSON.parse(JSON.stringify(data)) const rdata = JSON.parse(JSON.stringify(data)) const sidebarRoutes = filterAsyncRouter(sdata) + // console.log(sidebarRoutes) const rewriteRoutes = filterAsyncRouter(rdata, false, true) + // console.log(rewriteRoutes) rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true }) commit('SET_ROUTES', rewriteRoutes) commit('SET_SIDEBAR_ROUTERS', sidebarRoutes) diff --git a/dvadmin-ui/src/views/vadmin/monitor/server/components/InstrumentBoard.vue b/dvadmin-ui/src/views/vadmin/monitor/server/components/InstrumentBoard.vue new file mode 100644 index 0000000..9b8d182 --- /dev/null +++ b/dvadmin-ui/src/views/vadmin/monitor/server/components/InstrumentBoard.vue @@ -0,0 +1,215 @@ + + + + + diff --git a/dvadmin-ui/src/views/vadmin/monitor/server/components/LineChart.vue b/dvadmin-ui/src/views/vadmin/monitor/server/components/LineChart.vue new file mode 100644 index 0000000..e35aee1 --- /dev/null +++ b/dvadmin-ui/src/views/vadmin/monitor/server/components/LineChart.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/dvadmin-ui/src/views/vadmin/monitor/server/index.vue b/dvadmin-ui/src/views/vadmin/monitor/server/index.vue index 5a35767..e103444 100755 --- a/dvadmin-ui/src/views/vadmin/monitor/server/index.vue +++ b/dvadmin-ui/src/views/vadmin/monitor/server/index.vue @@ -1,210 +1,493 @@ + diff --git a/dvadmin-ui/src/views/vadmin/permission/user/index.vue b/dvadmin-ui/src/views/vadmin/permission/user/index.vue index 35caf58..5c0797e 100755 --- a/dvadmin-ui/src/views/vadmin/permission/user/index.vue +++ b/dvadmin-ui/src/views/vadmin/permission/user/index.vue @@ -161,7 +161,7 @@ - {{role.roleName}} + {{role.roleName}} @@ -576,7 +576,7 @@ password: undefined, mobile: undefined, email: undefined, - gender: this.selectDictDefault(this.sexOptions), + gender: undefined, is_active: false, remark: undefined, postIds: [], @@ -648,7 +648,6 @@ this.$refs['form'].validate(valid => { if (valid) { if (this.form.id != undefined) { - this.form.creator = undefined updateUser(this.form).then(response => { this.msgSuccess('修改成功') this.open = false