commit
665895f477
|
@ -8,6 +8,8 @@ version: "3"
|
||||||
services:
|
services:
|
||||||
dvadmin-ui:
|
dvadmin-ui:
|
||||||
container_name: dvadmin-ui
|
container_name: dvadmin-ui
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
build:
|
build:
|
||||||
context: ./
|
context: ./
|
||||||
dockerfile: ./docker_env/vue-ui/Dockerfile
|
dockerfile: ./docker_env/vue-ui/Dockerfile
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -51,6 +51,7 @@ INSTALLED_APPS = [
|
||||||
'apps.vadmin.op_drf',
|
'apps.vadmin.op_drf',
|
||||||
'apps.vadmin.system',
|
'apps.vadmin.system',
|
||||||
'apps.vadmin.celery',
|
'apps.vadmin.celery',
|
||||||
|
'apps.vadmin.monitor',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
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)
|
||||||
|
INTERFACE_PERMISSION = {locals().get("INTERFACE_PERMISSION", False)}
|
||||||
|
DJANGO_CELERY_BEAT_TZ_AWARE = False
|
||||||
|
|
|
@ -22,7 +22,7 @@ from django.urls import re_path, include
|
||||||
from django.views.static import serve
|
from django.views.static import serve
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from vadmin.utils.response import SuccessResponse
|
from apps.vadmin.utils.response import SuccessResponse
|
||||||
|
|
||||||
|
|
||||||
class CaptchaRefresh(APIView):
|
class CaptchaRefresh(APIView):
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class MonitorConfig(AppConfig):
|
||||||
|
name = 'vadmin.monitor'
|
||||||
|
verbose_name = "系统监控"
|
|
@ -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__'
|
|
@ -0,0 +1,3 @@
|
||||||
|
from ..models.monitor import Monitor
|
||||||
|
from ..models.server import Server
|
||||||
|
from ..models.sys_files import SysFiles
|
|
@ -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}监控信息"
|
|
@ -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}"
|
|
@ -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}"
|
|
@ -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__'
|
|
@ -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}天前数据")
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
|
@ -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<pk>.*)/', MonitorModelViewSet.as_view({'get': 'get_monitor_info'})),
|
||||||
|
re_path('monitor/rate/(?P<pk>.*)/', 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
|
|
@ -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="清空成功")
|
|
@ -1,3 +1,4 @@
|
||||||
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import SET_NULL
|
from django.db.models import SET_NULL
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ class CoreModel(models.Model):
|
||||||
增加审计字段, 覆盖字段时, 字段名称请勿修改, 必须统一审计字段名称
|
增加审计字段, 覆盖字段时, 字段名称请勿修改, 必须统一审计字段名称
|
||||||
"""
|
"""
|
||||||
description = DescriptionField() # 描述
|
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) # 创建者
|
verbose_name='创建者', on_delete=SET_NULL, db_constraint=False) # 创建者
|
||||||
modifier = ModifierCharField() # 修改者
|
modifier = ModifierCharField() # 修改者
|
||||||
dept_belong_id = models.CharField(max_length=64, verbose_name="数据归属部门", null=True, blank=True)
|
dept_belong_id = models.CharField(max_length=64, verbose_name="数据归属部门", null=True, blank=True)
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import django_filters
|
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
|
from ..utils.model_util import get_dept
|
||||||
|
|
||||||
|
UserProfile = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class MenuFilter(django_filters.rest_framework.FilterSet):
|
class MenuFilter(django_filters.rest_framework.FilterSet):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ class Command(BaseCommand):
|
||||||
parser.add_argument('-N', nargs='*')
|
parser.add_argument('-N', nargs='*')
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
user_name = "_".join(settings.AUTH_USER_MODEL.lower().split("."))
|
||||||
init_dict = {
|
init_dict = {
|
||||||
'system_dictdata': [os.path.join('system', 'system_dictdata.sql'), '字典管理', 'system_dictdata'],
|
'system_dictdata': [os.path.join('system', 'system_dictdata.sql'), '字典管理', 'system_dictdata'],
|
||||||
'system_dictdetails': [os.path.join('system', 'system_dictdetails.sql'), '字典详情', 'system_dictdetails'],
|
'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'), '角色管理',
|
'permission_role': [os.path.join('permission', 'permission_role.sql'), '角色管理',
|
||||||
','.join(['permission_role', 'permission_role_dept', 'permission_role_menu'])],
|
','.join(['permission_role', 'permission_role_dept', 'permission_role_menu'])],
|
||||||
'permission_userprofile': [os.path.join('permission', 'permission_userprofile.sql'), '用户管理', ','.join(
|
'permission_userprofile': [os.path.join('permission', 'permission_userprofile.sql'), '用户管理', ','.join(
|
||||||
['permission_userprofile_groups', 'permission_userprofile', 'permission_userprofile_role',
|
[f'{user_name}_groups', f'{user_name}', f'{user_name}_role', f'{user_name}_post'])]
|
||||||
'permission_userprofile_post'])]
|
|
||||||
}
|
}
|
||||||
init_name = options.get('init_name')
|
init_name = options.get('init_name')
|
||||||
is_yes = None
|
is_yes = None
|
||||||
|
|
|
@ -11,7 +11,7 @@ class Dept(CoreModel):
|
||||||
phone = CharField(max_length=32, verbose_name="联系电话", null=True, blank=True)
|
phone = CharField(max_length=32, verbose_name="联系电话", null=True, blank=True)
|
||||||
email = 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)
|
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)
|
db_constraint=False, null=True, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -18,8 +18,8 @@ class Role(CoreModel):
|
||||||
admin = BooleanField(default=False, verbose_name="是否为admin")
|
admin = BooleanField(default=False, verbose_name="是否为admin")
|
||||||
dataScope = CharField(max_length=8,default='1', choices=DATASCOPE_CHOICES, verbose_name="权限范围",)
|
dataScope = CharField(max_length=8,default='1', choices=DATASCOPE_CHOICES, verbose_name="权限范围",)
|
||||||
remark = TextField(verbose_name="备注", help_text="备注", null=True, blank=True)
|
remark = TextField(verbose_name="备注", help_text="备注", null=True, blank=True)
|
||||||
dept = ManyToManyField(to='Dept', verbose_name='数据权限-关联部门', db_constraint=False)
|
dept = ManyToManyField(to='permission.Dept', verbose_name='数据权限-关联部门', db_constraint=False)
|
||||||
menu = ManyToManyField(to='Menu', verbose_name='关联菜单权限', db_constraint=False)
|
menu = ManyToManyField(to='permission.Menu', verbose_name='关联菜单权限', db_constraint=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '角色管理'
|
verbose_name = '角色管理'
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import UserManager, AbstractUser
|
from django.contrib.auth.models import UserManager, AbstractUser
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db.models import IntegerField, ForeignKey, CharField, TextField, ManyToManyField, CASCADE
|
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)
|
gender = CharField(max_length=8, verbose_name="性别", null=True, blank=True)
|
||||||
remark = TextField(verbose_name="备注", null=True)
|
remark = TextField(verbose_name="备注", null=True)
|
||||||
user_type = IntegerField(default=0, verbose_name="用户类型")
|
user_type = IntegerField(default=0, verbose_name="用户类型")
|
||||||
post = ManyToManyField(to='Post', verbose_name='关联岗位', db_constraint=False)
|
post = ManyToManyField(to='permission.Post', verbose_name='关联岗位', db_constraint=False)
|
||||||
role = ManyToManyField(to='Role', verbose_name='关联角色', db_constraint=False)
|
role = ManyToManyField(to='permission.Role', verbose_name='关联角色', db_constraint=False)
|
||||||
dept = ForeignKey(to='Dept', verbose_name='归属部门', on_delete=CASCADE, db_constraint=False, null=True, blank=True)
|
dept = ForeignKey(to='permission.Dept', verbose_name='归属部门', on_delete=CASCADE, db_constraint=False, null=True, blank=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_user_interface_dict(self):
|
def get_user_interface_dict(self):
|
||||||
|
@ -51,6 +52,7 @@ class UserProfile(AbstractUser, CoreModel):
|
||||||
return cache.delete(f'permission_interface_dict_{self.username}')
|
return cache.delete(f'permission_interface_dict_{self.username}')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
abstract = settings.AUTH_USER_MODEL != 'permission.UserProfile'
|
||||||
verbose_name = '用户管理'
|
verbose_name = '用户管理'
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.validators import UniqueValidator
|
from rest_framework.validators import UniqueValidator
|
||||||
|
|
||||||
from ..op_drf.serializers import CustomModelSerializer
|
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
|
from ..system.models import MessagePush
|
||||||
|
|
||||||
|
UserProfile = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ************** 菜单管理 序列化器 ************** #
|
# ************** 菜单管理 序列化器 ************** #
|
||||||
|
|
|
@ -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.request import Request
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ from .permissions import CommonPermission, DeptDestroyPermission
|
||||||
from ..op_drf.filters import DataLevelPermissionsFilter
|
from ..op_drf.filters import DataLevelPermissionsFilter
|
||||||
from ..op_drf.viewsets import CustomModelViewSet
|
from ..op_drf.viewsets import CustomModelViewSet
|
||||||
from ..permission.filters import MenuFilter, DeptFilter, PostFilter, RoleFilter, UserProfileFilter
|
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, \
|
from ..permission.serializers import UserProfileSerializer, MenuSerializer, RoleSerializer, \
|
||||||
MenuCreateUpdateSerializer, DeptSerializer, DeptCreateUpdateSerializer, PostSerializer, PostCreateUpdateSerializer, \
|
MenuCreateUpdateSerializer, DeptSerializer, DeptCreateUpdateSerializer, PostSerializer, PostCreateUpdateSerializer, \
|
||||||
RoleCreateUpdateSerializer, DeptTreeSerializer, MenuTreeSerializer, UserProfileCreateUpdateSerializer, \
|
RoleCreateUpdateSerializer, DeptTreeSerializer, MenuTreeSerializer, UserProfileCreateUpdateSerializer, \
|
||||||
|
@ -15,6 +15,8 @@ from ..permission.serializers import UserProfileSerializer, MenuSerializer, Role
|
||||||
from ..system.models import DictDetails
|
from ..system.models import DictDetails
|
||||||
from ..utils.response import SuccessResponse, ErrorResponse
|
from ..utils.response import SuccessResponse, ErrorResponse
|
||||||
|
|
||||||
|
UserProfile = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class GetUserProfileView(APIView):
|
class GetUserProfileView(APIView):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
def getSql(filename):
|
def getSql(filename):
|
||||||
"""
|
"""
|
||||||
|
@ -9,6 +11,10 @@ def getSql(filename):
|
||||||
"""
|
"""
|
||||||
abspath = os.path.abspath(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))
|
abspath = os.path.abspath(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))
|
||||||
pwd = os.path.join(abspath, 'scripts', filename)
|
pwd = os.path.join(abspath, 'scripts', filename)
|
||||||
with open(pwd,'rb') as fp:
|
with open(pwd, 'rb') as fp:
|
||||||
content = fp.read().decode('utf8')
|
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(' ')]
|
return [ele for ele in content.split('\n') if not ele.startswith('--') and ele.strip(' ')]
|
||||||
|
|
|
@ -9,7 +9,7 @@ class DictDetails(CoreModel):
|
||||||
is_default = BooleanField(verbose_name="是否默认", default=False)
|
is_default = BooleanField(verbose_name="是否默认", default=False)
|
||||||
status = CharField(max_length=2, verbose_name="字典状态")
|
status = CharField(max_length=2, verbose_name="字典状态")
|
||||||
sort = CharField(max_length=256, 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)
|
remark = CharField(max_length=256, verbose_name="备注", null=True, blank=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import *
|
from django.db.models import *
|
||||||
|
|
||||||
from ...op_drf.fields import UpdateDateTimeField, CreateDateTimeField
|
from ...op_drf.fields import UpdateDateTimeField, CreateDateTimeField
|
||||||
from ...op_drf.models import CoreModel
|
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="是否审核")
|
is_reviewed = BooleanField(default=True, verbose_name="是否审核")
|
||||||
status = CharField(max_length=8, verbose_name="通知状态")
|
status = CharField(max_length=8, verbose_name="通知状态")
|
||||||
to_path = CharField(max_length=256, verbose_name="跳转路径", null=True, blank=True, )
|
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',
|
related_name="user", related_query_name="user_query", through='MessagePushUser',
|
||||||
through_fields=('message_push', 'user'))
|
through_fields=('message_push', 'user'))
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class MessagePushUser(models.Model):
|
||||||
related_name="messagepushuser_message_push",
|
related_name="messagepushuser_message_push",
|
||||||
verbose_name='消息通知', help_text='消息通知')
|
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",
|
related_name="messagepushuser_user",
|
||||||
verbose_name='用户', help_text='用户')
|
verbose_name='用户', help_text='用户')
|
||||||
is_read = BooleanField(default=False, verbose_name="是否已读")
|
is_read = BooleanField(default=False, verbose_name="是否已读")
|
||||||
|
|
|
@ -3,7 +3,7 @@ from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
from ..system.views import DictDataModelViewSet, DictDetailsModelViewSet, \
|
from ..system.views import DictDataModelViewSet, DictDetailsModelViewSet, \
|
||||||
ConfigSettingsModelViewSet, SaveFileModelViewSet, MessagePushModelViewSet, LoginInforModelViewSet, \
|
ConfigSettingsModelViewSet, SaveFileModelViewSet, MessagePushModelViewSet, LoginInforModelViewSet, \
|
||||||
OperationLogModelViewSet, CeleryLogModelViewSet
|
OperationLogModelViewSet, CeleryLogModelViewSet, SystemInfoApiView
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register(r'dict/type', DictDataModelViewSet)
|
router.register(r'dict/type', DictDataModelViewSet)
|
||||||
|
@ -48,6 +48,7 @@ urlpatterns = [
|
||||||
re_path('celery_log/export/', CeleryLogModelViewSet.as_view({'get': 'export', })),
|
re_path('celery_log/export/', CeleryLogModelViewSet.as_view({'get': 'export', })),
|
||||||
# 清除废弃文件
|
# 清除废弃文件
|
||||||
re_path('clearsavefile/', SaveFileModelViewSet.as_view({'post': 'clearsavefile', })),
|
re_path('clearsavefile/', SaveFileModelViewSet.as_view({'post': 'clearsavefile', })),
|
||||||
|
# 获取系统信息cpu、内存、硬盘
|
||||||
|
re_path('sys/info/', SystemInfoApiView.as_view())
|
||||||
]
|
]
|
||||||
urlpatterns += router.urls
|
urlpatterns += router.urls
|
||||||
|
|
|
@ -4,6 +4,7 @@ from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from .models import LoginInfor, OperationLog, CeleryLog
|
from .models import LoginInfor, OperationLog, CeleryLog
|
||||||
from ..op_drf.filters import DataLevelPermissionsFilter
|
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.export_excel import export_excel_save_model
|
||||||
from ..utils.file_util import get_all_files, remove_empty_dir, delete_files
|
from ..utils.file_util import get_all_files, remove_empty_dir, delete_files
|
||||||
from ..utils.response import SuccessResponse
|
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):
|
class DictDataModelViewSet(CustomModelViewSet):
|
||||||
|
@ -329,3 +331,21 @@ class CeleryLogModelViewSet(CustomModelViewSet):
|
||||||
"""
|
"""
|
||||||
self.get_queryset().delete()
|
self.get_queryset().delete()
|
||||||
return SuccessResponse(msg="清空成功")
|
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
|
||||||
|
})
|
||||||
|
|
|
@ -54,5 +54,6 @@ urlpatterns = [
|
||||||
re_path(r'^permission/', include('apps.vadmin.permission.urls')),
|
re_path(r'^permission/', include('apps.vadmin.permission.urls')),
|
||||||
re_path(r'^system/', include('apps.vadmin.system.urls')),
|
re_path(r'^system/', include('apps.vadmin.system.urls')),
|
||||||
re_path(r'^celery/', include('apps.vadmin.celery.urls')),
|
re_path(r'^celery/', include('apps.vadmin.celery.urls')),
|
||||||
|
re_path(r'^monitor/', include('apps.vadmin.monitor.urls')),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,6 +4,27 @@
|
||||||
import psutil as psutil
|
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():
|
def get_cpu_used_percent():
|
||||||
"""
|
"""
|
||||||
获取CPU运行情况
|
获取CPU运行情况
|
||||||
|
@ -31,7 +52,5 @@ def get_disk_used_percent():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
get_cpu_used_percent()
|
get_disk_used_percent()
|
|
@ -3,7 +3,7 @@ ENV = 'development'
|
||||||
|
|
||||||
# 若依管理系统/开发环境
|
# 若依管理系统/开发环境
|
||||||
# VUE_APP_BASE_API = 'https://api.django-vue-admin.com'
|
# 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
|
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||||
|
|
|
@ -41,14 +41,16 @@
|
||||||
"axios": "0.21.0",
|
"axios": "0.21.0",
|
||||||
"clipboard": "2.0.6",
|
"clipboard": "2.0.6",
|
||||||
"core-js": "3.8.1",
|
"core-js": "3.8.1",
|
||||||
"echarts": "4.9.0",
|
"echarts": "^4.9.0",
|
||||||
"element-ui": "2.15.0",
|
"element-ui": "2.15.0",
|
||||||
|
"eslint-loader": "^4.0.2",
|
||||||
"file-saver": "2.0.4",
|
"file-saver": "2.0.4",
|
||||||
"fuse.js": "6.4.3",
|
"fuse.js": "6.4.3",
|
||||||
"highlight.js": "9.18.5",
|
"highlight.js": "9.18.5",
|
||||||
"js-beautify": "1.13.0",
|
"js-beautify": "1.13.0",
|
||||||
"js-cookie": "2.2.1",
|
"js-cookie": "2.2.1",
|
||||||
"jsencrypt": "3.0.0-rc.1",
|
"jsencrypt": "3.0.0-rc.1",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"quill": "1.3.7",
|
"quill": "1.3.7",
|
||||||
|
@ -58,6 +60,7 @@
|
||||||
"vue-count-to": "1.0.13",
|
"vue-count-to": "1.0.13",
|
||||||
"vue-cropper": "0.5.5",
|
"vue-cropper": "0.5.5",
|
||||||
"vue-router": "3.4.9",
|
"vue-router": "3.4.9",
|
||||||
|
"vue-types": "^2.0.3",
|
||||||
"vuedraggable": "2.24.3",
|
"vuedraggable": "2.24.3",
|
||||||
"vuex": "3.6.0"
|
"vuex": "3.6.0"
|
||||||
},
|
},
|
||||||
|
@ -65,6 +68,7 @@
|
||||||
"@vue/cli-plugin-babel": "4.4.6",
|
"@vue/cli-plugin-babel": "4.4.6",
|
||||||
"@vue/cli-plugin-eslint": "4.4.6",
|
"@vue/cli-plugin-eslint": "4.4.6",
|
||||||
"@vue/cli-service": "4.4.6",
|
"@vue/cli-service": "4.4.6",
|
||||||
|
"@vue/composition-api": "^1.0.0-rc.6",
|
||||||
"babel-eslint": "10.1.0",
|
"babel-eslint": "10.1.0",
|
||||||
"chalk": "4.1.0",
|
"chalk": "4.1.0",
|
||||||
"connect": "3.6.6",
|
"connect": "3.6.6",
|
||||||
|
|
|
@ -3,7 +3,7 @@ import request from '@/utils/request'
|
||||||
// 获取路由
|
// 获取路由
|
||||||
export const getRouters = () => {
|
export const getRouters = () => {
|
||||||
return request({
|
return request({
|
||||||
url: '/admin/getRouters',
|
url: '/admin/getRouters/',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import request from '@/utils/request'
|
||||||
// 查询在线用户列表
|
// 查询在线用户列表
|
||||||
export function list(query) {
|
export function list(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/monitor/online/list',
|
url: '/admin/monitor/online/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
})
|
})
|
||||||
|
@ -12,7 +12,7 @@ export function list(query) {
|
||||||
// 强退用户
|
// 强退用户
|
||||||
export function forceLogout(tokenId) {
|
export function forceLogout(tokenId) {
|
||||||
return request({
|
return request({
|
||||||
url: '/monitor/online/' + tokenId,
|
url: '/admin/monitor/online/' + tokenId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,65 @@
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
// 查询服务器详细
|
// 查询服务器信息详细
|
||||||
export function getServer() {
|
export function getServerList(params) {
|
||||||
return request({
|
return request({
|
||||||
url: '/monitor/server',
|
url: 'admin/monitor/server/',
|
||||||
|
params,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改服务器信息
|
||||||
|
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'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -24,11 +24,28 @@ const permission = {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
// 向后端请求路由数据
|
// 向后端请求路由数据
|
||||||
getRouters().then(res => {
|
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 sdata = JSON.parse(JSON.stringify(data))
|
||||||
const rdata = JSON.parse(JSON.stringify(data))
|
const rdata = JSON.parse(JSON.stringify(data))
|
||||||
const sidebarRoutes = filterAsyncRouter(sdata)
|
const sidebarRoutes = filterAsyncRouter(sdata)
|
||||||
|
// console.log(sidebarRoutes)
|
||||||
const rewriteRoutes = filterAsyncRouter(rdata, false, true)
|
const rewriteRoutes = filterAsyncRouter(rdata, false, true)
|
||||||
|
// console.log(rewriteRoutes)
|
||||||
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
|
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
|
||||||
commit('SET_ROUTES', rewriteRoutes)
|
commit('SET_ROUTES', rewriteRoutes)
|
||||||
commit('SET_SIDEBAR_ROUTERS', sidebarRoutes)
|
commit('SET_SIDEBAR_ROUTERS', sidebarRoutes)
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
<template>
|
||||||
|
<div class="instrument-board">
|
||||||
|
<div v-if="showTopTitle && haveMultipleData" class="instrument-board-title">
|
||||||
|
<el-select :value="topTitle"
|
||||||
|
@change="chooseDisplayInstrumentBoardData"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(item,index) in instrumentBoardData"
|
||||||
|
:key="index"
|
||||||
|
:label="item.name || item['dir_name']"
|
||||||
|
:value="index"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div v-else-if="showTopTitle" class="instrument-board-title">
|
||||||
|
{{ topTitle }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :id="ringGraphId" class="instrument-board-body"></div>
|
||||||
|
<div v-if="showSubTitle"
|
||||||
|
class="instrument-board-subtitle"
|
||||||
|
:title="subTitle.title"
|
||||||
|
>{{ subTitle.content }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import VueTypes from 'vue-types'
|
||||||
|
// 引入基本模板,按需加载
|
||||||
|
const echarts = require('echarts/lib/echarts')
|
||||||
|
require('echarts/lib/chart/gauge')
|
||||||
|
|
||||||
|
// 仪表盘颜色范围
|
||||||
|
const NORMAL_COLOR = {
|
||||||
|
color: '#28BCFE',
|
||||||
|
itemColor: ['#25bfff', '#5284de', '#2a95f9']
|
||||||
|
}
|
||||||
|
const WARNING_COLOR = {
|
||||||
|
color: '#e6a23c',
|
||||||
|
itemColor: ['#e6a23c', '#cc8b1d', '#ffaf18']
|
||||||
|
}
|
||||||
|
const DANGER_COLOR = {
|
||||||
|
color: '#F56C6C',
|
||||||
|
itemColor: ['#fd666d', '#cf1717', '#b31212']
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'InstrumentBoard',
|
||||||
|
props: {
|
||||||
|
// 组件key
|
||||||
|
ringGraphKey: VueTypes.string.isRequired,
|
||||||
|
// 上标题
|
||||||
|
showTopTitle: VueTypes.bool.def(false),
|
||||||
|
// 下标题
|
||||||
|
showSubTitle: VueTypes.bool.def(false),
|
||||||
|
// top title 配置映射
|
||||||
|
topTitleKeyToNameMapping: VueTypes.object.def({
|
||||||
|
cpu: 'CPU使用率',
|
||||||
|
memory: '内存使用率'
|
||||||
|
}),
|
||||||
|
instrumentBoardData: VueTypes.any.isRequired
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 当前显示的数据
|
||||||
|
currentInstrumentBoardData: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 仪表盘是否存在多个数据
|
||||||
|
haveMultipleData() {
|
||||||
|
return this.instrumentBoardData instanceof Array && this.instrumentBoardData.length > 0
|
||||||
|
},
|
||||||
|
// 使用率
|
||||||
|
ringRate() {
|
||||||
|
let ringRate = this.currentInstrumentBoardData.rate
|
||||||
|
return ringRate < 1 ? ringRate * 100 : ringRate
|
||||||
|
},
|
||||||
|
// 仪表盘id
|
||||||
|
ringGraphId() {
|
||||||
|
return `${this.ringGraphKey}UsingRate`
|
||||||
|
},
|
||||||
|
// 上方标题
|
||||||
|
topTitle() {
|
||||||
|
return this.currentInstrumentBoardData['dir_name'] || this.topTitleKeyToNameMapping[this.ringGraphKey] || this.ringGraphKey
|
||||||
|
},
|
||||||
|
// 下方标题
|
||||||
|
subTitle() {
|
||||||
|
let used = this.currentInstrumentBoardData['used'] ? this.currentInstrumentBoardData['used'] + '/' : ''
|
||||||
|
let total = this.currentInstrumentBoardData['total'] ? this.currentInstrumentBoardData['total'] : ''
|
||||||
|
let unit = this.currentInstrumentBoardData['unit'] ? ` (${this.currentInstrumentBoardData['unit']})` : ''
|
||||||
|
let content = `${used}${total}${unit} `
|
||||||
|
let title = (this.currentInstrumentBoardData['used'] ? '已用/' : '') + '总量(单位)'
|
||||||
|
return { content, title }
|
||||||
|
},
|
||||||
|
// 使用率样式配置
|
||||||
|
usingRateStyle() {
|
||||||
|
return {
|
||||||
|
fontSize: 18,
|
||||||
|
...this.getCircleColor(this.ringRate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.haveMultipleData) {
|
||||||
|
this.currentInstrumentBoardData = this.instrumentBoardData[0]
|
||||||
|
} else {
|
||||||
|
this.currentInstrumentBoardData = this.instrumentBoardData
|
||||||
|
}
|
||||||
|
this.drawBar()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
drawBar() {
|
||||||
|
let currentRate = [this.ringRate]
|
||||||
|
// 基于dom,初始化echarts实例
|
||||||
|
let RingGraph = echarts.init(document.getElementById(this.ringGraphId))
|
||||||
|
|
||||||
|
let option = {
|
||||||
|
title: {
|
||||||
|
text: currentRate + '%',
|
||||||
|
textStyle: this.usingRateStyle,
|
||||||
|
itemGap: 10,
|
||||||
|
left: 'center',
|
||||||
|
top: '45%'
|
||||||
|
},
|
||||||
|
angleAxis: {
|
||||||
|
max: 100,
|
||||||
|
clockwise: true, // 逆时针
|
||||||
|
// 隐藏刻度线
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
radiusAxis: {
|
||||||
|
type: 'category',
|
||||||
|
show: true,
|
||||||
|
axisLabel: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
polar: {
|
||||||
|
center: ['50%', '50%'], // 坐标中心位置
|
||||||
|
radius: '100%' //图形大小
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
type: 'bar',
|
||||||
|
data: currentRate,
|
||||||
|
showBackground: true,
|
||||||
|
backgroundStyle: {
|
||||||
|
color: '#BDEBFF' // 底圈颜色
|
||||||
|
},
|
||||||
|
coordinateSystem: 'polar',
|
||||||
|
roundCap: true,
|
||||||
|
barWidth: 15,
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
opacity: 1,
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||||
|
offset: 0,
|
||||||
|
color: this.usingRateStyle.itemColor[0] || '#25BFFF'
|
||||||
|
}, {
|
||||||
|
offset: 1,
|
||||||
|
color: this.usingRateStyle.itemColor[1] || '#5284DE'
|
||||||
|
}]),
|
||||||
|
shadowBlur: 1,
|
||||||
|
shadowColor: this.usingRateStyle.itemColor[2] || '#2A95F9'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
// 绘制图表
|
||||||
|
RingGraph.setOption(option)
|
||||||
|
},
|
||||||
|
// 仪表盘样式-颜色
|
||||||
|
getCircleColor(usingRate) {
|
||||||
|
if (usingRate < 60) {
|
||||||
|
return NORMAL_COLOR
|
||||||
|
} else if (usingRate > 60 && usingRate < 80) {
|
||||||
|
return WARNING_COLOR
|
||||||
|
} else if (usingRate > 80) {
|
||||||
|
return DANGER_COLOR
|
||||||
|
}
|
||||||
|
return NORMAL_COLOR
|
||||||
|
},
|
||||||
|
chooseDisplayInstrumentBoardData(index) {
|
||||||
|
this.currentInstrumentBoardData = this.instrumentBoardData[index]
|
||||||
|
this.drawBar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.instrument-board-title {
|
||||||
|
font-weight: bolder;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instrument-board-body {
|
||||||
|
min-height: 200px;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instrument-board-subtitle {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,181 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="line-chart-title">
|
||||||
|
<div class="line-chart-name">{{ chartTitle }}</div>
|
||||||
|
<div class="line-chart-time-radio">
|
||||||
|
<el-radio-group v-model="timeLimit" @change="changeTimeLimit">
|
||||||
|
<el-radio-button
|
||||||
|
v-for="item in Object.keys(TIME_LIMIT_SETTING)"
|
||||||
|
:label="TIME_LIMIT_SETTING[item].name"
|
||||||
|
:key="TIME_LIMIT_SETTING[item].key"
|
||||||
|
></el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div :id="lineChartId" class="line-chart-body"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import VueTypes from 'vue-types'
|
||||||
|
// 引入基本模板,按需加载
|
||||||
|
import echarts from 'echarts'
|
||||||
|
import moment from 'moment'
|
||||||
|
import { getMonitorLogs } from '@/api/vadmin/monitor/server'
|
||||||
|
|
||||||
|
const MONTH = moment().month()
|
||||||
|
const YEAR = moment().year()
|
||||||
|
const TODAY = moment().format('YYYY-MM-DD')
|
||||||
|
const YESTERDAY = moment().subtract(1, 'days').format('YYYY-MM-DD')
|
||||||
|
const LAST_SEVEN_DAYS = moment().subtract(7, 'days').format('YYYY-MM-DD')
|
||||||
|
const LAST_THIRTY_DAYS = moment().subtract(30, 'days').format('YYYY-MM-DD')
|
||||||
|
|
||||||
|
// 时间段筛选配置
|
||||||
|
const TIME_LIMIT_SETTING = {
|
||||||
|
'yesterday': {
|
||||||
|
key: 'yesterday',
|
||||||
|
name: '昨天',
|
||||||
|
timeRange: [
|
||||||
|
`${YESTERDAY} 00:00:00`,
|
||||||
|
`${YESTERDAY} 23:59:59`
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'today': {
|
||||||
|
key: 'today',
|
||||||
|
name: '今天',
|
||||||
|
timeRange: [
|
||||||
|
`${TODAY} 00:00:00`,
|
||||||
|
`${TODAY} 23:59:59`
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'latestWeek': {
|
||||||
|
key: 'latestWeek',
|
||||||
|
name: '最近7天',
|
||||||
|
timeRange: [
|
||||||
|
`${LAST_SEVEN_DAYS} 00:00:00`,
|
||||||
|
`${TODAY} 23:59:59`
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'latestMonth': {
|
||||||
|
key: 'latestMonth',
|
||||||
|
name: '最近30天',
|
||||||
|
timeRange: [
|
||||||
|
`${LAST_THIRTY_DAYS} 00:00:00`,
|
||||||
|
`${TODAY} 23:59:59`
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 默认显示时间
|
||||||
|
const DEFAULT_TIME = '今天'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'LineChart',
|
||||||
|
props: {
|
||||||
|
serverInfo: VueTypes.object.isRequired,
|
||||||
|
lineChartKey: VueTypes.string.isRequired,
|
||||||
|
chartTitle: VueTypes.string.isRequired,
|
||||||
|
chartData: VueTypes.array.isRequired
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
TIME_LIMIT_SETTING,
|
||||||
|
timeLimit: DEFAULT_TIME,
|
||||||
|
lineChartId: this.lineChartKey + 'Chart',
|
||||||
|
lineChartData: this.chartData
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.drawBar()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
timeLimitNames() {
|
||||||
|
return Object.keys(TIME_LIMIT_SETTING).map(item => {
|
||||||
|
return TIME_LIMIT_SETTING[item].name
|
||||||
|
})
|
||||||
|
},
|
||||||
|
currentDateIndex() {
|
||||||
|
return this.timeLimitNames.indexOf(this.timeLimit)
|
||||||
|
},
|
||||||
|
currentTimeLimitSetting() {
|
||||||
|
return TIME_LIMIT_SETTING[Object.keys(TIME_LIMIT_SETTING)[this.currentDateIndex]]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
drawBar() {
|
||||||
|
// 基于dom,初始化echarts实例
|
||||||
|
let barGraph = echarts.init(document.getElementById(this.lineChartId))
|
||||||
|
// 绘制图表
|
||||||
|
barGraph.setOption({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{a} <br/>{b} : {c}'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
left: 'center',
|
||||||
|
data: [],
|
||||||
|
bottom: 0
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
name: 'x',
|
||||||
|
splitLine: { show: false },
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '1%',
|
||||||
|
right: '2%',
|
||||||
|
bottom: '8%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '使用率',
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '使用率',
|
||||||
|
type: 'line',
|
||||||
|
data: this.lineChartData
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
changeTimeLimit(value) {
|
||||||
|
this.timeLimit = value
|
||||||
|
this.getCurrentServerMonitorLogs()
|
||||||
|
},
|
||||||
|
getCurrentServerMonitorLogs() {
|
||||||
|
getMonitorLogs(this.serverInfo.id,{ as: { 'create_datetime__range': this.currentTimeLimitSetting.timeRange } }).then(results => {
|
||||||
|
this.lineChartData = results.data[this.lineChartKey]
|
||||||
|
this.drawBar()
|
||||||
|
}).catch(error => {
|
||||||
|
this.$message.warning(error.msg || `获取${this.chartTitle}数据失败!`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.line-chart-name {
|
||||||
|
font-weight: bolder;
|
||||||
|
width: 20%;
|
||||||
|
min-width: 30px;
|
||||||
|
text-align: left;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-chart-time-radio {
|
||||||
|
font-weight: bolder;
|
||||||
|
width: 80%;
|
||||||
|
min-width: 200px;
|
||||||
|
text-align: right;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-chart-body {
|
||||||
|
min-height: 300px;
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,210 +1,493 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<el-row>
|
<!-- 监控控制 -->
|
||||||
<el-col :span="12" class="card-box">
|
<div class="server-monitor-control">
|
||||||
<el-card>
|
<!-- 监控启用开关 -->
|
||||||
<div slot="header"><span>CPU</span></div>
|
<div class="control-server-monitor same-block">
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
开启监控:
|
||||||
<table cellspacing="0" style="width: 100%;">
|
<el-switch
|
||||||
<thead>
|
v-model="isOpeningMonitor"
|
||||||
<tr>
|
active-color="#13ce66"
|
||||||
<th class="is-leaf"><div class="cell">属性</div></th>
|
inactive-color="#ff4949"
|
||||||
<th class="is-leaf"><div class="cell">值</div></th>
|
title="控制所有监控项"
|
||||||
</tr>
|
@change="changeMonitorStatus"
|
||||||
</thead>
|
>
|
||||||
<tbody>
|
</el-switch>
|
||||||
<tr>
|
</div>
|
||||||
<td><div class="cell">核心数</div></td>
|
<!-- 更新频率设置 -->
|
||||||
<td><div class="cell" v-if="server.cpu">{{ server.cpu.cpuNum }}</div></td>
|
<div class="monitor-update-interval same-block">
|
||||||
</tr>
|
监控频率:
|
||||||
<tr>
|
<el-input-number v-model="monitorUpdateInterval"
|
||||||
<td><div class="cell">用户使用率</div></td>
|
label=""
|
||||||
<td><div class="cell" v-if="server.cpu">{{ server.cpu.used }}%</div></td>
|
class="monitor-update-interval-blank"
|
||||||
</tr>
|
controls-position="right"
|
||||||
<tr>
|
:min="minMonitorUpdateInterval"
|
||||||
<td><div class="cell">系统使用率</div></td>
|
@input="handleIntervalChange"
|
||||||
<td><div class="cell" v-if="server.cpu">{{ server.cpu.sys }}%</div></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><div class="cell">当前空闲率</div></td>
|
|
||||||
<td><div class="cell" v-if="server.cpu">{{ server.cpu.free }}%</div></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="12" class="card-box">
|
></el-input-number>
|
||||||
<el-card>
|
<el-select v-model="intervalType"
|
||||||
<div slot="header"><span>内存</span></div>
|
class="monitor-update-interval-unit"
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
@change="selectIntervalType"
|
||||||
<table cellspacing="0" style="width: 100%;">
|
>
|
||||||
<thead>
|
<el-option
|
||||||
<tr>
|
v-for="item in Object.keys(INTERVAL_ID_TO_TYPE_MAPPING)"
|
||||||
<th class="is-leaf"><div class="cell">属性</div></th>
|
:key="INTERVAL_ID_TO_TYPE_MAPPING[item].type"
|
||||||
<th class="is-leaf"><div class="cell">内存</div></th>
|
:label="INTERVAL_ID_TO_TYPE_MAPPING[item].name"
|
||||||
<th class="is-leaf"><div class="cell">JVM</div></th>
|
:value="INTERVAL_ID_TO_TYPE_MAPPING[item].name">
|
||||||
</tr>
|
</el-option>
|
||||||
</thead>
|
</el-select>
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><div class="cell">总内存</div></td>
|
|
||||||
<td><div class="cell" v-if="server.mem">{{ server.mem.total }}G</div></td>
|
|
||||||
<td><div class="cell" v-if="server.jvm">{{ server.jvm.total }}M</div></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><div class="cell">已用内存</div></td>
|
|
||||||
<td><div class="cell" v-if="server.mem">{{ server.mem.used}}G</div></td>
|
|
||||||
<td><div class="cell" v-if="server.jvm">{{ server.jvm.used}}M</div></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><div class="cell">剩余内存</div></td>
|
|
||||||
<td><div class="cell" v-if="server.mem">{{ server.mem.free }}G</div></td>
|
|
||||||
<td><div class="cell" v-if="server.jvm">{{ server.jvm.free }}M</div></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><div class="cell">使用率</div></td>
|
|
||||||
<td><div class="cell" v-if="server.mem" :class="{'text-danger': server.mem.usage > 80}">{{ server.mem.usage }}%</div></td>
|
|
||||||
<td><div class="cell" v-if="server.jvm" :class="{'text-danger': server.jvm.usage > 80}">{{ server.jvm.usage }}%</div></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="24" class="card-box">
|
</div>
|
||||||
<el-card>
|
<!-- 监控日志保存时间 -->
|
||||||
<div slot="header">
|
<div class="monitor-log-save-time same-block">
|
||||||
<span>服务器信息</span>
|
保存天数:
|
||||||
</div>
|
<el-input v-model="monitorLogSavingDays" class=" same-block" style="width: 120px;"></el-input>
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
<el-button type="primary"
|
||||||
<table cellspacing="0" style="width: 100%;">
|
class="same-block"
|
||||||
<tbody>
|
title="只有提交更改才会生效"
|
||||||
<tr>
|
@click="updateMonitorStatusSettingsInfo"
|
||||||
<td><div class="cell">服务器名称</div></td>
|
>更改
|
||||||
<td><div class="cell" v-if="server.sys">{{ server.sys.computerName }}</div></td>
|
</el-button>
|
||||||
<td><div class="cell">操作系统</div></td>
|
</div>
|
||||||
<td><div class="cell" v-if="server.sys">{{ server.sys.osName }}</div></td>
|
<!-- 清空记录 -->
|
||||||
</tr>
|
<div class="clean-monitor-log same-block">
|
||||||
<tr>
|
<el-button class="same-block"
|
||||||
<td><div class="cell">服务器IP</div></td>
|
type="warning"
|
||||||
<td><div class="cell" v-if="server.sys">{{ server.sys.computerIp }}</div></td>
|
title="清空所有监控记录"
|
||||||
<td><div class="cell">系统架构</div></td>
|
@click="cleanMonitorLogsInfo"
|
||||||
<td><div class="cell" v-if="server.sys">{{ server.sys.osArch }}</div></td>
|
>清空记录
|
||||||
</tr>
|
</el-button>
|
||||||
</tbody>
|
</div>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="24" class="card-box">
|
<div class="server-monitor-top">
|
||||||
<el-card>
|
<!-- 左侧服务器信息 -->
|
||||||
<div slot="header">
|
<el-card class="box-card server-information">
|
||||||
<span>Java虚拟机信息</span>
|
<div slot="header" class="clearfix">
|
||||||
|
<div class="server-info-item">服务器</div>
|
||||||
|
<el-select filterable
|
||||||
|
:value="currentServerName"
|
||||||
|
class="server-info-item"
|
||||||
|
placeholder="请选择服务器"
|
||||||
|
@change="chooseServerInfo"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(item,index) in allServerInfo"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="index"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-button type="primary"
|
||||||
|
class="server-info-item"
|
||||||
|
title="只有提交更改才会生效"
|
||||||
|
@click="updateServerInfo"
|
||||||
|
>更改
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="server-info-detail">
|
||||||
|
<div v-for="(key,index) in currentServerInfoKeys" :key="index" class="server-info-detail-line text item">
|
||||||
|
<div class="server-info-detail-item">
|
||||||
|
<div style="width: 30%;display: inline-block;">{{ SERVER_KEY_TO_NAME_MAPPING[key] }}:</div>
|
||||||
|
<div v-if="CHANGEABLE_SERVER_FIELDS.indexOf(key) > -1" style="display: inline-block;">
|
||||||
|
<el-input style="display: inline-block; width: 90%;" v-model="currentServer[key]"></el-input>
|
||||||
|
</div>
|
||||||
|
<div v-else style="display: inline-block; "> {{ currentServer[key] }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
</div>
|
||||||
<table cellspacing="0" style="width: 100%;">
|
</el-card>
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><div class="cell">Java名称</div></td>
|
|
||||||
<td><div class="cell" v-if="server.jvm">{{ server.jvm.name }}</div></td>
|
|
||||||
<td><div class="cell">Java版本</div></td>
|
|
||||||
<td><div class="cell" v-if="server.jvm">{{ server.jvm.version }}</div></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><div class="cell">启动时间</div></td>
|
|
||||||
<td><div class="cell" v-if="server.jvm">{{ server.jvm.startTime }}</div></td>
|
|
||||||
<td><div class="cell">运行时长</div></td>
|
|
||||||
<td><div class="cell" v-if="server.jvm">{{ server.jvm.runTime }}</div></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="1"><div class="cell">安装路径</div></td>
|
|
||||||
<td colspan="3"><div class="cell" v-if="server.jvm">{{ server.jvm.home }}</div></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="1"><div class="cell">项目路径</div></td>
|
|
||||||
<td colspan="3"><div class="cell" v-if="server.sys">{{ server.sys.userDir }}</div></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="24" class="card-box">
|
<!-- 右侧仪表盘 -->
|
||||||
<el-card>
|
<el-card class="box-card information-instrument-panel"
|
||||||
<div slot="header">
|
v-for="(key, index) of Object.keys(instrumentBoardData)"
|
||||||
<span>磁盘状态</span>
|
:key="`${index}-${key}`">
|
||||||
</div>
|
<instrument-board
|
||||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
:show-top-title="true"
|
||||||
<table cellspacing="0" style="width: 100%;">
|
:show-sub-title="true"
|
||||||
<thead>
|
:ring-graph-key="key"
|
||||||
<tr>
|
:instrument-board-data="instrumentBoardData[key]"
|
||||||
<th class="is-leaf"><div class="cell">盘符路径</div></th>
|
:top-title-key-to-name-mapping="INSTRUMENT_BOARD_KEY_TO_NAME_MAPPING"
|
||||||
<th class="is-leaf"><div class="cell">文件系统</div></th>
|
></instrument-board>
|
||||||
<th class="is-leaf"><div class="cell">盘符类型</div></th>
|
</el-card>
|
||||||
<th class="is-leaf"><div class="cell">总大小</div></th>
|
</div>
|
||||||
<th class="is-leaf"><div class="cell">可用大小</div></th>
|
<!-- 下方折线图 -->
|
||||||
<th class="is-leaf"><div class="cell">已用大小</div></th>
|
<div class="server-monitor-bottom">
|
||||||
<th class="is-leaf"><div class="cell">已用百分比</div></th>
|
<!-- 折线图 -->
|
||||||
</tr>
|
<el-card class="box-card server-monitor-line-chart" v-for="(key, index) in Object.keys(lineChartData)"
|
||||||
</thead>
|
:key="`${index}-${key}`">
|
||||||
<tbody v-if="server.sysFiles">
|
<line-chart :line-chart-key="key"
|
||||||
<tr v-for="sysFile in server.sysFiles">
|
:server-info="currentServer"
|
||||||
<td><div class="cell">{{ sysFile.dirName }}</div></td>
|
:chart-title="CHART_KEY_NAME_MAPPING[key]"
|
||||||
<td><div class="cell">{{ sysFile.sysTypeName }}</div></td>
|
:chart-data="lineChartData[key]"
|
||||||
<td><div class="cell">{{ sysFile.typeName }}</div></td>
|
></line-chart>
|
||||||
<td><div class="cell">{{ sysFile.total }}</div></td>
|
</el-card>
|
||||||
<td><div class="cell">{{ sysFile.free }}</div></td>
|
</div>
|
||||||
<td><div class="cell">{{ sysFile.used }}</div></td>
|
|
||||||
<td><div class="cell" :class="{'text-danger': sysFile.usage > 80}">{{ sysFile.usage }}%</div></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getServer } from "@/api/vadmin/monitor/server";
|
import {
|
||||||
|
cleanMonitorLog,
|
||||||
|
getMonitorLogs,
|
||||||
|
getMonitorStatusInfo,
|
||||||
|
getServerLatestLog,
|
||||||
|
getServerList,
|
||||||
|
updateMonitorStatusInfo,
|
||||||
|
updateServerInfo
|
||||||
|
} from '@/api/vadmin/monitor/server'
|
||||||
|
import InstrumentBoard from '@/views/vadmin/monitor/server/components/InstrumentBoard'
|
||||||
|
import LineChart from '@/views/vadmin/monitor/server/components/LineChart'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
const debounce = require('lodash/debounce')
|
||||||
|
|
||||||
|
// 要展示的信息,key -> name
|
||||||
|
const SERVER_KEY_TO_NAME_MAPPING = {
|
||||||
|
ip: '服务器IP',
|
||||||
|
name: '服务器名称',
|
||||||
|
os: '操作系统',
|
||||||
|
remark: '备注'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新频率类型映射
|
||||||
|
const INTERVAL_ID_TO_TYPE_MAPPING = {
|
||||||
|
0: {
|
||||||
|
type: 0,
|
||||||
|
name: '秒',
|
||||||
|
key: 'seconds',
|
||||||
|
second: 1
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
type: 1,
|
||||||
|
name: '分钟',
|
||||||
|
key: 'minutes',
|
||||||
|
second: 60
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
type: 2,
|
||||||
|
name: '小时',
|
||||||
|
key: 'hours',
|
||||||
|
second: 60 * 60
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
type: 3,
|
||||||
|
name: '天',
|
||||||
|
key: 'days',
|
||||||
|
second: 24 * 60 * 60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const defaultUpdateInterval = INTERVAL_ID_TO_TYPE_MAPPING['0']
|
||||||
|
|
||||||
|
// 图表字段映射
|
||||||
|
const CHART_KEY_NAME_MAPPING = {
|
||||||
|
cpu: 'CPU',
|
||||||
|
memory: '内存',
|
||||||
|
disk: '磁盘'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 仪表盘字段映射
|
||||||
|
const INSTRUMENT_BOARD_KEY_TO_NAME_MAPPING = {
|
||||||
|
cpu: 'CPU使用率',
|
||||||
|
memory: '内存使用率'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务器信息可修改字段
|
||||||
|
const CHANGEABLE_SERVER_FIELDS = ['name', 'remark']
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Server",
|
name: 'Server',
|
||||||
|
components: {
|
||||||
|
InstrumentBoard,
|
||||||
|
LineChart
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
SERVER_KEY_TO_NAME_MAPPING,
|
||||||
|
INTERVAL_ID_TO_TYPE_MAPPING,
|
||||||
|
CHART_KEY_NAME_MAPPING,
|
||||||
|
CHANGEABLE_SERVER_FIELDS,
|
||||||
|
INSTRUMENT_BOARD_KEY_TO_NAME_MAPPING,
|
||||||
|
timeRange: [
|
||||||
|
`${moment().format('YYYY-MM-DD')} 00:00:00`,
|
||||||
|
`${moment().format('YYYY-MM-DD')} 23:59:59`
|
||||||
|
],
|
||||||
// 加载层信息
|
// 加载层信息
|
||||||
loading: [],
|
loading: [],
|
||||||
// 服务器信息
|
// 所有服务器信息
|
||||||
server: []
|
allServerInfo: [],
|
||||||
};
|
// 当前展示的服务器名称
|
||||||
|
currentServerName: '',
|
||||||
|
// 当前展示的服务器信息
|
||||||
|
currentServer: {},
|
||||||
|
// 当前展示的服务器信息索引,更新服务器信息时用
|
||||||
|
currentServerIndex: 0,
|
||||||
|
// 开启监控控制按钮
|
||||||
|
isOpeningMonitor: false,
|
||||||
|
// 数据更新频率
|
||||||
|
monitorUpdateInterval: 60,
|
||||||
|
// 最小更新频率值
|
||||||
|
minMonitorUpdateInterval: 0,
|
||||||
|
// 更新频率类型
|
||||||
|
intervalType: defaultUpdateInterval.name,
|
||||||
|
// 更新频率单位对应秒
|
||||||
|
intervalTypeUnits: defaultUpdateInterval.second,
|
||||||
|
// 监控日志保存天数
|
||||||
|
monitorLogSavingDays: 30,
|
||||||
|
// 折线图数据
|
||||||
|
lineChartData: {},
|
||||||
|
// 仪表盘数据
|
||||||
|
instrumentBoardData: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
currentServerInfoKeys() {
|
||||||
|
return Object.keys(this.currentServer).filter(key => {
|
||||||
|
if (SERVER_KEY_TO_NAME_MAPPING[key]) {
|
||||||
|
return { [key]: SERVER_KEY_TO_NAME_MAPPING[key] }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
intervalNameToSecondMapping() {
|
||||||
|
let intervalNameToSecondMapping = {}
|
||||||
|
Object.values(INTERVAL_ID_TO_TYPE_MAPPING).forEach(item => {
|
||||||
|
intervalNameToSecondMapping[item.name] = item.second
|
||||||
|
})
|
||||||
|
return intervalNameToSecondMapping
|
||||||
|
},
|
||||||
|
monitorStatusInfo() {
|
||||||
|
return {
|
||||||
|
enabled: this.isOpeningMonitor ? 1 : 0,
|
||||||
|
save_days: this.monitorLogSavingDays,
|
||||||
|
interval: this.monitorUpdateInterval * this.intervalTypeUnits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
currentServer(newServerInfo) {
|
||||||
|
if (newServerInfo) {
|
||||||
|
// 更新最新监控信息
|
||||||
|
this.getServerLatestLogInfo(newServerInfo.id)
|
||||||
|
// 获取监控日志信息
|
||||||
|
this.getCurrentServerMonitorLogs()
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getList();
|
this.openLoading()
|
||||||
this.openLoading();
|
// 获取所有服务器信息
|
||||||
|
this.getServerList(this.currentServerIndex)
|
||||||
|
// 获取服务器监控频率设置
|
||||||
|
this.getMonitorStatusSettingsInfo()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 查询服务器信息 */
|
/** 查询所有服务器基础信息 */
|
||||||
getList() {
|
getServerList(serverIndex) {
|
||||||
getServer().then(response => {
|
getServerList({ pageNum: 'all' }).then(response => {
|
||||||
this.server = response.data;
|
this.allServerInfo = response.data
|
||||||
this.loading.close();
|
if (this.allServerInfo.length > 0) {
|
||||||
});
|
this.currentServer = this.allServerInfo[serverIndex || this.currentServerIndex]
|
||||||
|
this.currentServerName = this.currentServer.name
|
||||||
|
}
|
||||||
|
this.loading.close()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
/**修改服务器信息*/
|
||||||
|
updateServerInfo() {
|
||||||
|
updateServerInfo(this.currentServer.id, this.currentServer).then(() => {
|
||||||
|
this.msgSuccess('修改服务器信息成功!')
|
||||||
|
}).catch(error => {
|
||||||
|
this.$message.error(error.msg || '提交修改服务器信息出错!')
|
||||||
|
}).finally(() => {
|
||||||
|
this.getServerList()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 获取服务器最新监控信息 */
|
||||||
|
getServerLatestLogInfo(serverId) {
|
||||||
|
getServerLatestLog(serverId).then(results => {
|
||||||
|
this.instrumentBoardData = results.data
|
||||||
|
}).catch(error => {
|
||||||
|
this.msgError(error.msg || '获取服务器最新监控信息错误!')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 获取监控日志信息 */
|
||||||
|
getCurrentServerMonitorLogs() {
|
||||||
|
getMonitorLogs(this.currentServer.id, { as: { 'create_datetime__range': this.timeRange } }).then(results => {
|
||||||
|
this.lineChartData = results.data
|
||||||
|
}).catch(error => {
|
||||||
|
this.msgError(error.msg || '获取监控日志信息出错误!')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 清除监控日志 */
|
||||||
|
cleanMonitorLogsInfo() {
|
||||||
|
this.$confirm('此操作将删除所有的监控记录,是否继续?', '提示', {
|
||||||
|
confirmButtonText: '确定删除',
|
||||||
|
cancelButtonText: '放弃'
|
||||||
|
}).then(() => {
|
||||||
|
cleanMonitorLog().then(results => {
|
||||||
|
this.msgSuccess( '清除记录成功!')
|
||||||
|
}).catch(error => {
|
||||||
|
this.$message.warning(error.msg || '清除记录失败,请重试!')
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 获取监控配置信息 */
|
||||||
|
getMonitorStatusSettingsInfo() {
|
||||||
|
getMonitorStatusInfo().then(results => {
|
||||||
|
let { enabled, interval, save_days } = results.data
|
||||||
|
this.isOpeningMonitor = enabled
|
||||||
|
this.monitorLogSavingDays = parseInt(save_days)
|
||||||
|
this.formatInterval(parseInt(interval))
|
||||||
|
}).catch(error => {
|
||||||
|
this.msgError(error.msg || '获取服务器监控配置信息出错误!')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 更新监控配置信息 */
|
||||||
|
updateMonitorStatusSettingsInfo() {
|
||||||
|
updateMonitorStatusInfo(this.monitorStatusInfo).then(() => {
|
||||||
|
this.msgSuccess('更新配置成功!')
|
||||||
|
}).catch((error) => {
|
||||||
|
this.msgError(error.msg || '更新服务器监控配置信息出错误!')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
// 打开加载层
|
// 打开加载层
|
||||||
openLoading() {
|
openLoading() {
|
||||||
this.loading = this.$loading({
|
this.loading = this.$loading({
|
||||||
lock: true,
|
lock: true,
|
||||||
text: "拼命读取中",
|
text: '拼命读取中',
|
||||||
spinner: "el-icon-loading",
|
spinner: 'el-icon-loading',
|
||||||
background: "rgba(0, 0, 0, 0.7)"
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
});
|
})
|
||||||
|
},
|
||||||
|
// 选择展示的服务器信息
|
||||||
|
chooseServerInfo(index) {
|
||||||
|
this.currentServerIndex = index
|
||||||
|
this.currentServer = this.allServerInfo[index]
|
||||||
|
this.currentServerName = this.currentServer.name
|
||||||
|
},
|
||||||
|
// 更改更新频率(周期)数值
|
||||||
|
handleIntervalChange: debounce(function(value) {
|
||||||
|
this.monitorUpdateInterval = value
|
||||||
|
}, 500),
|
||||||
|
// 选择更新频率(周期) 单位
|
||||||
|
selectIntervalType(value) {
|
||||||
|
this.intervalType = value
|
||||||
|
this.intervalTypeUnits = this.intervalNameToSecondMapping[value]
|
||||||
|
},
|
||||||
|
// 修改监控状态
|
||||||
|
changeMonitorStatus(value) {
|
||||||
|
this.isOpeningMonitor = value
|
||||||
|
},
|
||||||
|
// 监控周期时间转换
|
||||||
|
formatInterval(intervalTime) {
|
||||||
|
let biggerInterval = 0
|
||||||
|
for (let interval of Object.values(INTERVAL_ID_TO_TYPE_MAPPING)) {
|
||||||
|
if (interval.second > biggerInterval && interval.second < intervalTime) {
|
||||||
|
biggerInterval = interval.second
|
||||||
|
this.monitorUpdateInterval = intervalTime / interval.second
|
||||||
|
this.intervalType = interval.name
|
||||||
|
this.intervalTypeUnits = interval.second
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.el-button--medium {
|
||||||
|
margin: 2px;
|
||||||
|
padding: 10px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-monitor-top {
|
||||||
|
padding: 0 10px;
|
||||||
|
text-align: justify-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-monitor-bottom {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-information {
|
||||||
|
width: 20%;
|
||||||
|
min-width: 400px;
|
||||||
|
min-height: 300px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.information-instrument-panel {
|
||||||
|
display: inline-block;
|
||||||
|
min-height: 300px;
|
||||||
|
min-width: 400px;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-info-item {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-info-detail {
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-info-detail-line {
|
||||||
|
margin: 5px;
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-info-detail-item {
|
||||||
|
text-align: justify;
|
||||||
|
line-height: 40px;
|
||||||
|
margin: 4px 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-monitor-control {
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
line-height: 60px;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-update-interval {
|
||||||
|
margin: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.same-block {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-update-interval-blank {
|
||||||
|
width: 100px;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-update-interval-unit {
|
||||||
|
width: 80px;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-log-save-time {
|
||||||
|
width: 280px;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clean-monitor-log {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.server-monitor-line-chart {
|
||||||
|
height: 400px;
|
||||||
|
width: 45%;
|
||||||
|
min-width: 500px;
|
||||||
|
margin: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
</span>
|
</span>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<el-dropdown-item v-for="(role,index) in scope.row.role" :key="index">{{role.roleName}}</el-dropdown-item>
|
<el-dropdown-item v-for="role in scope.row.role">{{role.roleName}}</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</template>
|
</template>
|
||||||
|
@ -576,7 +576,7 @@
|
||||||
password: undefined,
|
password: undefined,
|
||||||
mobile: undefined,
|
mobile: undefined,
|
||||||
email: undefined,
|
email: undefined,
|
||||||
gender: this.selectDictDefault(this.sexOptions),
|
gender: undefined,
|
||||||
is_active: false,
|
is_active: false,
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
postIds: [],
|
postIds: [],
|
||||||
|
@ -648,7 +648,6 @@
|
||||||
this.$refs['form'].validate(valid => {
|
this.$refs['form'].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.form.id != undefined) {
|
if (this.form.id != undefined) {
|
||||||
this.form.creator = undefined
|
|
||||||
updateUser(this.form).then(response => {
|
updateUser(this.form).then(response => {
|
||||||
this.msgSuccess('修改成功')
|
this.msgSuccess('修改成功')
|
||||||
this.open = false
|
this.open = false
|
||||||
|
|
Loading…
Reference in New Issue