Update: (步骤备份)完善系统监控
This commit is contained in:
@@ -2,7 +2,7 @@ from io import BytesIO
|
|||||||
|
|
||||||
from flask import session, make_response
|
from flask import session, make_response
|
||||||
|
|
||||||
from applications.common.utils.gen_captcha import vieCode
|
from applications.common.utils.captcha import vieCode
|
||||||
|
|
||||||
|
|
||||||
# 生成验证码
|
# 生成验证码
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
cache_dict = {}
|
||||||
|
|
||||||
|
|
||||||
|
def cache_set_internal(key, value, expired=5):
|
||||||
|
"""
|
||||||
|
程序内部实现的记录缓存,用于简单、体量不大的缓存记录,在程序结束后销毁。对于高速、体量大的环境请配置 Redis 等服务自行记录。
|
||||||
|
记录缓存,存储键值对,并记录当前时间作为缓存的时间戳。
|
||||||
|
|
||||||
|
:param key: 键
|
||||||
|
:param value: 值
|
||||||
|
:param expired: 过期时间(秒),默认5秒
|
||||||
|
"""
|
||||||
|
cache_dict[key] = {
|
||||||
|
'value': value,
|
||||||
|
'expired_time': time.time() + expired
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def cache_get_internal(key):
|
||||||
|
"""
|
||||||
|
获取缓存,根据键从缓存中获取值,并检查是否过期。
|
||||||
|
|
||||||
|
:param key: 键
|
||||||
|
:return: 如果缓存存在且未过期,返回缓存的值;否则返回 None
|
||||||
|
"""
|
||||||
|
if key in cache_dict:
|
||||||
|
cache_item = cache_dict[key]
|
||||||
|
if time.time() < cache_item['expired_time']:
|
||||||
|
return cache_item['value']
|
||||||
|
else:
|
||||||
|
# 如果缓存已过期,删除该缓存
|
||||||
|
del cache_dict[key]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def cache_auto_internal(key, call, expired=5):
|
||||||
|
"""
|
||||||
|
如果缓存存在直接返回缓存内容,缓存不存在或者过期执行 call 函数,并取得返回值记录并返回。
|
||||||
|
|
||||||
|
:param key: 键
|
||||||
|
:param call: 获取新值的地方
|
||||||
|
:param expired: 过期时间(秒),默认5秒
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = cache_get_internal(key)
|
||||||
|
|
||||||
|
if data is not None:
|
||||||
|
return data
|
||||||
|
|
||||||
|
data = call()
|
||||||
|
cache_set_internal(key, data, expired)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ class vieCode:
|
|||||||
__inCurve = True # 是否画干扰线
|
__inCurve = True # 是否画干扰线
|
||||||
__inNoise = True # 是否画干扰点
|
__inNoise = True # 是否画干扰点
|
||||||
__type = 2 # 验证码类型 1、纯字母 2、数字字母混合
|
__type = 2 # 验证码类型 1、纯字母 2、数字字母混合
|
||||||
__fontPatn = 'applications/common/utils/fonts/1.ttf' # 字体
|
__fontPatn = 'applications/common/utils/fonts/captcha.ttf' # 字体
|
||||||
|
|
||||||
def GetCodeImage(self, size=80, length=4):
|
def GetCodeImage(self, size=80, length=4):
|
||||||
'''获取验证码图片
|
'''获取验证码图片
|
||||||
@@ -11,7 +11,7 @@ def str_escape(s):
|
|||||||
|
|
||||||
|
|
||||||
between = validators.between
|
between = validators.between
|
||||||
'''
|
"""
|
||||||
验证数字是否介于最小值和/或最大值之间。
|
验证数字是否介于最小值和/或最大值之间。
|
||||||
这将适用于任何类似的类型,如浮点数、小数和日期,而不仅仅是整数。
|
这将适用于任何类似的类型,如浮点数、小数和日期,而不仅仅是整数。
|
||||||
between(value, min=None, max=None)
|
between(value, min=None, max=None)
|
||||||
@@ -35,10 +35,10 @@ between(value, min=None, max=None)
|
|||||||
... min=datetime(1999, 11, 11)
|
... min=datetime(1999, 11, 11)
|
||||||
... )
|
... )
|
||||||
True
|
True
|
||||||
'''
|
"""
|
||||||
|
|
||||||
domain = validators.domain
|
domain = validators.domain
|
||||||
'''
|
"""
|
||||||
返回给定值是否为有效域
|
返回给定值是否为有效域
|
||||||
如果值是有效域名,则此函数返回 True ,否则返回 ValidationFailure
|
如果值是有效域名,则此函数返回 True ,否则返回 ValidationFailure
|
||||||
domain(value)
|
domain(value)
|
||||||
@@ -49,10 +49,10 @@ domain(value)
|
|||||||
|
|
||||||
>>> domain('example.com/')
|
>>> domain('example.com/')
|
||||||
ValidationFailure(func=domain, ...)
|
ValidationFailure(func=domain, ...)
|
||||||
'''
|
"""
|
||||||
|
|
||||||
email = validators.email
|
email = validators.email
|
||||||
'''
|
"""
|
||||||
验证电子邮件地址。验证成功时返回 True ,验证失败时返回
|
验证电子邮件地址。验证成功时返回 True ,验证失败时返回
|
||||||
|
|
||||||
>>> email('someone@example.com')
|
>>> email('someone@example.com')
|
||||||
@@ -60,10 +60,10 @@ email = validators.email
|
|||||||
|
|
||||||
>>> email('bogus@@')
|
>>> email('bogus@@')
|
||||||
ValidationFailure(func=email, ...)
|
ValidationFailure(func=email, ...)
|
||||||
'''
|
"""
|
||||||
|
|
||||||
iban = validators.iban
|
iban = validators.iban
|
||||||
'''
|
"""
|
||||||
返回给定值是否为有效的IBAN代码。
|
返回给定值是否为有效的IBAN代码。
|
||||||
如果值是有效的IBAN,则此函数返回 True ,否则返回 ValidationFailure 。
|
如果值是有效的IBAN,则此函数返回 True ,否则返回 ValidationFailure 。
|
||||||
|
|
||||||
@@ -72,10 +72,10 @@ iban = validators.iban
|
|||||||
|
|
||||||
>>> iban('123456')
|
>>> iban('123456')
|
||||||
ValidationFailure(func=iban, ...)
|
ValidationFailure(func=iban, ...)
|
||||||
'''
|
"""
|
||||||
|
|
||||||
ipv4 = validators.ipv4
|
ipv4 = validators.ipv4
|
||||||
'''
|
"""
|
||||||
返回给定值是否为有效的IPv4地址。
|
返回给定值是否为有效的IPv4地址。
|
||||||
|
|
||||||
>>> ipv4('123.0.0.7')
|
>>> ipv4('123.0.0.7')
|
||||||
@@ -83,20 +83,20 @@ ipv4 = validators.ipv4
|
|||||||
|
|
||||||
>>> ipv4('900.80.70.11')
|
>>> ipv4('900.80.70.11')
|
||||||
ValidationFailure(func=ipv4, args={'value': '900.80.70.11'})
|
ValidationFailure(func=ipv4, args={'value': '900.80.70.11'})
|
||||||
'''
|
"""
|
||||||
|
|
||||||
ipv6 = validators.ipv6
|
ipv6 = validators.ipv6
|
||||||
'''
|
"""
|
||||||
返回给定值是否为有效的IP版本6地址。
|
返回给定值是否为有效的IP版本6地址。
|
||||||
>>> ipv6('abcd:ef::42:1')
|
>>> ipv6('abcd:ef::42:1')
|
||||||
True
|
True
|
||||||
|
|
||||||
>>> ipv6('abc.0.0.1')
|
>>> ipv6('abc.0.0.1')
|
||||||
ValidationFailure(func=ipv6, args={'value': 'abc.0.0.1'})
|
ValidationFailure(func=ipv6, args={'value': 'abc.0.0.1'})
|
||||||
'''
|
"""
|
||||||
|
|
||||||
length = validators.length
|
length = validators.length
|
||||||
'''
|
"""
|
||||||
返回给定字符串的长度是否在指定范围内。
|
返回给定字符串的长度是否在指定范围内。
|
||||||
>>> length('something', min=2)
|
>>> length('something', min=2)
|
||||||
True
|
True
|
||||||
@@ -106,10 +106,10 @@ length = validators.length
|
|||||||
|
|
||||||
>>> length('something', max=5)
|
>>> length('something', max=5)
|
||||||
ValidationFailure(func=length, ...)
|
ValidationFailure(func=length, ...)
|
||||||
'''
|
"""
|
||||||
|
|
||||||
mac_address = validators.mac_address
|
mac_address = validators.mac_address
|
||||||
'''
|
"""
|
||||||
返回给定值是否为有效MAC地址。
|
返回给定值是否为有效MAC地址。
|
||||||
如果该值是有效的MAC地址,则此函数返回 True ,否则返回 ValidationFailure 。
|
如果该值是有效的MAC地址,则此函数返回 True ,否则返回 ValidationFailure 。
|
||||||
|
|
||||||
@@ -118,10 +118,10 @@ mac_address = validators.mac_address
|
|||||||
|
|
||||||
>>> mac_address('00:00:00:00:00')
|
>>> mac_address('00:00:00:00:00')
|
||||||
ValidationFailure(func=mac_address, args={'value': '00:00:00:00:00'})
|
ValidationFailure(func=mac_address, args={'value': '00:00:00:00:00'})
|
||||||
'''
|
"""
|
||||||
|
|
||||||
slug = validators.slug
|
slug = validators.slug
|
||||||
'''
|
"""
|
||||||
验证给定值是否为有效的块。
|
验证给定值是否为有效的块。
|
||||||
有效的短信息只能包含字母数字字符、连字符和下划线。
|
有效的短信息只能包含字母数字字符、连字符和下划线。
|
||||||
>>> slug('my.slug')
|
>>> slug('my.slug')
|
||||||
@@ -129,15 +129,15 @@ slug = validators.slug
|
|||||||
|
|
||||||
>>> slug('my-slug-2134')
|
>>> slug('my-slug-2134')
|
||||||
True
|
True
|
||||||
'''
|
"""
|
||||||
|
|
||||||
#truthy = validators.truthy
|
#truthy = validators.truthy
|
||||||
'''
|
"""
|
||||||
验证给定值不是错误值。
|
验证给定值不是错误值。
|
||||||
'''
|
"""
|
||||||
|
|
||||||
url = validators.url
|
url = validators.url
|
||||||
'''
|
"""
|
||||||
返回给定值是否为有效URL。
|
返回给定值是否为有效URL。
|
||||||
如果值是有效URL,则此函数返回 True ,否则返回 ValidationFailure 。
|
如果值是有效URL,则此函数返回 True ,否则返回 ValidationFailure 。
|
||||||
|
|
||||||
@@ -152,10 +152,10 @@ url = validators.url
|
|||||||
|
|
||||||
>>> url('http://10.0.0.1', public=True)
|
>>> url('http://10.0.0.1', public=True)
|
||||||
ValidationFailure(func=url, ...)
|
ValidationFailure(func=url, ...)
|
||||||
'''
|
"""
|
||||||
|
|
||||||
uuid = validators.uuid
|
uuid = validators.uuid
|
||||||
'''
|
"""
|
||||||
返回给定值是否为有效UUID。
|
返回给定值是否为有效UUID。
|
||||||
如果值是有效的UUID,则此函数返回 True ,否则返回 ValidationFailure 。
|
如果值是有效的UUID,则此函数返回 True ,否则返回 ValidationFailure 。
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ uuid = validators.uuid
|
|||||||
|
|
||||||
>>> uuid('2bc1c94f 0deb-43e9-92a1-4775189ec9f8')
|
>>> uuid('2bc1c94f 0deb-43e9-92a1-4775189ec9f8')
|
||||||
ValidationFailure(func=uuid, ...)
|
ValidationFailure(func=uuid, ...)
|
||||||
'''
|
"""
|
||||||
|
|
||||||
|
|
||||||
@validator
|
@validator
|
||||||
@@ -172,7 +172,7 @@ def even(value):
|
|||||||
return not (value % 2)
|
return not (value % 2)
|
||||||
|
|
||||||
|
|
||||||
'''
|
"""
|
||||||
一个装饰器,它使给定的函数验证器
|
一个装饰器,它使给定的函数验证器
|
||||||
每当给定函数被调用并返回 False 值时,这个装饰器返回 ValidationFailure 对象。
|
每当给定函数被调用并返回 False 值时,这个装饰器返回 ValidationFailure 对象。
|
||||||
>>> @validator
|
>>> @validator
|
||||||
@@ -184,4 +184,4 @@ True
|
|||||||
|
|
||||||
>>> even(5)
|
>>> even(5)
|
||||||
ValidationFailure(func=even, args={'value': 5})
|
ValidationFailure(func=even, args={'value': 5})
|
||||||
'''
|
"""
|
||||||
|
|||||||
@@ -1,47 +1,33 @@
|
|||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import psutil
|
||||||
|
import platform
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import psutil
|
from flask import Blueprint, render_template
|
||||||
from flask import Blueprint, render_template, jsonify
|
|
||||||
|
|
||||||
|
from applications.common.utils.http import table_api, success_api
|
||||||
from applications.common.utils.rights import authorize
|
from applications.common.utils.rights import authorize
|
||||||
|
from applications.common.utils.cache import cache_auto_internal
|
||||||
|
|
||||||
|
|
||||||
bp = Blueprint('adminMonitor', __name__, url_prefix='/monitor')
|
bp = Blueprint('adminMonitor', __name__, url_prefix='/monitor')
|
||||||
|
|
||||||
|
|
||||||
# 系统监控
|
def get_disk_partitions_list():
|
||||||
@bp.get('/')
|
|
||||||
@authorize("system:monitor:main")
|
|
||||||
def main():
|
|
||||||
# 主机名称
|
|
||||||
hostname = platform.node()
|
|
||||||
# 系统版本
|
|
||||||
system_version = platform.platform()
|
|
||||||
# python版本
|
|
||||||
python_version = platform.python_version()
|
|
||||||
# 逻辑cpu数量
|
|
||||||
cpu_count = psutil.cpu_count()
|
|
||||||
# cpu使用率
|
|
||||||
cpus_percent = psutil.cpu_percent(interval=0.1, percpu=False) # percpu 获取主使用率
|
|
||||||
# 内存
|
|
||||||
memory_information = psutil.virtual_memory()
|
|
||||||
# 内存使用率
|
|
||||||
memory_usage = memory_information.percent
|
|
||||||
memory_used: int = memory_information.used
|
|
||||||
memory_total: int = memory_information.total
|
|
||||||
memory_free: int = memory_information.free
|
|
||||||
# 磁盘信息
|
|
||||||
|
|
||||||
disk_partitions_list = []
|
disk_partitions_list = []
|
||||||
# 判断是否在容器中
|
# 判断是否在容器中
|
||||||
if not os.path.exists('/.dockerenv'):
|
if not os.path.exists('/.dockerenv'):
|
||||||
disk_partitions = psutil.disk_partitions()
|
disk_partitions = psutil.disk_partitions()
|
||||||
for i in disk_partitions:
|
for i in disk_partitions:
|
||||||
|
try:
|
||||||
a = psutil.disk_usage(i.device)
|
a = psutil.disk_usage(i.device)
|
||||||
|
except PermissionError:
|
||||||
|
continue
|
||||||
|
|
||||||
disk_partitions_dict = {
|
disk_partitions_dict = {
|
||||||
'device': i.device,
|
'device': i.device,
|
||||||
'fstype': i.fstype,
|
'fstype': i.fstype,
|
||||||
@@ -51,30 +37,58 @@ def main():
|
|||||||
'percent': a.percent
|
'percent': a.percent
|
||||||
}
|
}
|
||||||
disk_partitions_list.append(disk_partitions_dict)
|
disk_partitions_list.append(disk_partitions_dict)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
usage = psutil.disk_usage('/')
|
||||||
|
except PermissionError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
disk_partitions_list.append({
|
||||||
|
'device': '/', # 设备名称(根文件系统)
|
||||||
|
'fstype': psutil.disk_partitions()[0].fstype, # 文件系统类型
|
||||||
|
'total': usage.total, # 总容量(字节)
|
||||||
|
'used': usage.used, # 已用空间(字节)
|
||||||
|
'free': usage.free, # 可用空间(字节)
|
||||||
|
'percent': usage.percent # 使用百分比
|
||||||
|
})
|
||||||
|
|
||||||
|
return disk_partitions_list
|
||||||
|
|
||||||
|
def get_basic_info():
|
||||||
|
# 主机名称
|
||||||
|
hostname = platform.node()
|
||||||
|
# 系统版本
|
||||||
|
system_version = platform.platform()
|
||||||
|
# Python 版本
|
||||||
|
python_version = platform.python_version()
|
||||||
|
|
||||||
# 开机时间
|
# 开机时间
|
||||||
boot_time = datetime.fromtimestamp(psutil.boot_time()).replace(microsecond=0)
|
boot_time = datetime.fromtimestamp(psutil.boot_time()).replace(microsecond=0)
|
||||||
up_time = datetime.now().replace(microsecond=0) - boot_time
|
up_time = datetime.now().replace(microsecond=0) - boot_time
|
||||||
up_time_list = re.split(r':', str(up_time))
|
up_time_list = re.split(r':', str(up_time))
|
||||||
up_time_format = " {} 小时{} 分钟{} 秒".format(up_time_list[0], up_time_list[1], up_time_list[2])
|
up_time_format = "{} 小时 {} 分钟 {} 秒".format(up_time_list[0], up_time_list[1], up_time_list[2])
|
||||||
|
up_time_format = up_time_format.replace("days,", "天")
|
||||||
|
|
||||||
|
return {
|
||||||
|
'hostname': hostname,
|
||||||
|
'system_version': system_version,
|
||||||
|
'python_version': python_version,
|
||||||
|
'boot_time': boot_time,
|
||||||
|
'up_time_format': up_time_format
|
||||||
|
}
|
||||||
|
|
||||||
|
# 系统监控
|
||||||
|
@bp.get('/')
|
||||||
|
@authorize("system:monitor:main")
|
||||||
|
def main():
|
||||||
|
|
||||||
|
|
||||||
# 当前时间
|
# 当前时间
|
||||||
time_now = time.strftime('%H:%M:%S ', time.localtime(time.time()))
|
time_now = time.strftime('%H:%M:%S ', time.localtime(time.time()))
|
||||||
return render_template(
|
return render_template(
|
||||||
'system/monitor.html',
|
'system/monitor.html',
|
||||||
hostname=hostname,
|
time_now=time_now,
|
||||||
system_version=system_version,
|
**get_basic_info()
|
||||||
python_version=python_version,
|
|
||||||
cpus_percent=cpus_percent,
|
|
||||||
memory_usage=memory_usage,
|
|
||||||
cpu_count=cpu_count,
|
|
||||||
memory_used=memory_used,
|
|
||||||
memory_total=memory_total,
|
|
||||||
memory_free=memory_free,
|
|
||||||
boot_time=boot_time,
|
|
||||||
up_time_format=up_time_format,
|
|
||||||
disk_partitions_list=disk_partitions_list,
|
|
||||||
time_now=time_now
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -82,19 +96,74 @@ def main():
|
|||||||
@bp.get('/polling')
|
@bp.get('/polling')
|
||||||
@authorize("system:monitor:main")
|
@authorize("system:monitor:main")
|
||||||
def ajax_polling():
|
def ajax_polling():
|
||||||
# 获取cpu使用率
|
# 获取 CPU 核心数
|
||||||
cpus_percent = psutil.cpu_percent(interval=0.1, percpu=False) # percpu 获取主使用率
|
cpu_count = cache_auto_internal('cpu_count', lambda: psutil.cpu_count(), expired=999999999)
|
||||||
# 获取内存使用率
|
|
||||||
memory_information = psutil.virtual_memory()
|
# 获取 CPU 使用率
|
||||||
|
cpus_percent = cache_auto_internal('cpus_percent',
|
||||||
|
lambda: psutil.cpu_percent(interval=1, percpu=False),
|
||||||
|
expired=5)
|
||||||
|
|
||||||
|
# 每个 CPU 的使用率
|
||||||
|
cpu_percent_per_core = cache_auto_internal('cpu_percent_per_core',
|
||||||
|
lambda: list(enumerate(psutil.cpu_percent(interval=1, percpu=True))),
|
||||||
|
expired=5)
|
||||||
|
|
||||||
|
# 获取空闲率、等待率
|
||||||
|
cpu_times_percent = cache_auto_internal('cpu_times_percent',
|
||||||
|
lambda: psutil.cpu_times_percent(interval=1, percpu=False),
|
||||||
|
expired=5)
|
||||||
|
|
||||||
|
# 内存信息
|
||||||
|
memory_information = cache_auto_internal('memory_information',
|
||||||
|
psutil.virtual_memory,
|
||||||
|
expired=5)
|
||||||
|
|
||||||
|
# 硬盘信息
|
||||||
|
disk_partitions_list = cache_auto_internal('disk_partitions_list',
|
||||||
|
get_disk_partitions_list,
|
||||||
|
expired=5)
|
||||||
|
|
||||||
|
# 系统信息
|
||||||
|
basic_info = cache_auto_internal('basic_info',
|
||||||
|
get_basic_info,
|
||||||
|
expired=5)
|
||||||
|
|
||||||
memory_usage = memory_information.percent
|
memory_usage = memory_information.percent
|
||||||
time_now = time.strftime('%H:%M:%S ', time.localtime(time.time()))
|
memory_used = memory_information.used
|
||||||
return jsonify(cups_percent=cpus_percent, memory_used=memory_usage, time_now=time_now)
|
memory_total = memory_information.total
|
||||||
|
memory_free = memory_information.free
|
||||||
|
|
||||||
|
cpu_idle_percent = cpu_times_percent.idle
|
||||||
|
if hasattr(cpu_times_percent, 'iowait'):
|
||||||
|
cpu_wait_percent = cpu_times_percent.iowait
|
||||||
|
else:
|
||||||
|
cpu_wait_percent = "-"
|
||||||
|
|
||||||
|
return table_api(msg="请求成功",
|
||||||
|
count=0,
|
||||||
|
data={
|
||||||
|
'cpu_count': cpu_count,
|
||||||
|
'cpus_percent': cpus_percent,
|
||||||
|
'cpu_idle_percent': cpu_idle_percent,
|
||||||
|
'cpu_wait_percent': cpu_wait_percent,
|
||||||
|
'cpu_percent_per_core': cpu_percent_per_core,
|
||||||
|
'memory_used': memory_used,
|
||||||
|
'memory_total': memory_total,
|
||||||
|
'memory_free': memory_free,
|
||||||
|
'memory_usage': memory_usage,
|
||||||
|
'disk_partitions_list': disk_partitions_list,
|
||||||
|
'time_now': time.strftime('%H:%M:%S', time.localtime(time.time())),
|
||||||
|
'basic_info': basic_info
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
# 关闭程序
|
# 关闭程序
|
||||||
@bp.get('/kill')
|
@bp.get('/kill')
|
||||||
@authorize("system:monitor:main")
|
@authorize("system:monitor:main")
|
||||||
def kill():
|
def kill():
|
||||||
|
# 注:若是多 worker 则不生效
|
||||||
|
return success_api(msg="关闭命令已发送,请修改代码以生效。")
|
||||||
for proc in psutil.process_iter():
|
for proc in psutil.process_iter():
|
||||||
if proc.pid == os.getpid():
|
if proc.pid == os.getpid():
|
||||||
proc.kill()
|
proc.kill()
|
||||||
|
|||||||
@@ -0,0 +1,187 @@
|
|||||||
|
.pear-container {
|
||||||
|
background-color: whitesmoke;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card {
|
||||||
|
width: 100%;
|
||||||
|
height: 66px;
|
||||||
|
background-color: #F8F8F8;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card:hover,
|
||||||
|
.pear-card2:hover {
|
||||||
|
box-shadow: 2px 0 8px 0 lightgray !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card2 {
|
||||||
|
width: 100%;
|
||||||
|
height: 90px;
|
||||||
|
background-color: #F8F8F8;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card2 i {
|
||||||
|
font-size: 30px;
|
||||||
|
height: 90px;
|
||||||
|
line-height: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card i {
|
||||||
|
font-size: 30px;
|
||||||
|
height: 66px;
|
||||||
|
line-height: 66px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layui-col-md3 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card-title {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person img {
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card2 .count {
|
||||||
|
color: var(--global-primary-color);
|
||||||
|
font-size: 30px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card2 .title {
|
||||||
|
color: gray;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card-status {
|
||||||
|
padding: 0 10px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card-status li {
|
||||||
|
position: relative;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-bottom: 1px solid #EEE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card-status li h3 {
|
||||||
|
padding-bottom: 5px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card-status li p {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
padding-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-card-status li > span {
|
||||||
|
color: #999;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pear-reply {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person .title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-left: 18px;
|
||||||
|
margin-top: 16px;
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person .desc {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-left: 115px;
|
||||||
|
margin-top: -30px;
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tooltip {
|
||||||
|
opacity: 0; /* 默认完全透明 */
|
||||||
|
transition: opacity 0.3s ease-in-out; /* 添加淡入淡出动画 */
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tooltip.show {
|
||||||
|
opacity: 1; /* 完全显示 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#tooltip .layui-card-body ul {
|
||||||
|
display: grid; /* 启用 Grid 布局 */
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); /* 自动填充列 */
|
||||||
|
gap: 5px; /* 设置子元素之间的间距 */
|
||||||
|
padding: 0; /* 移除默认的 ul 内边距 */
|
||||||
|
margin: 0; /* 移除默认的 ul 外边距 */
|
||||||
|
list-style: none; /* 移除列表项的默认样式 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#tooltip .layui-card-body ul li span {
|
||||||
|
width: 8em;
|
||||||
|
background-color: #E7EEFC !important;
|
||||||
|
color: #6197F8 !important;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-ring {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-ring .circle {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-ring .circle-bg {
|
||||||
|
fill: none;
|
||||||
|
stroke: #e6e6e6; /* 背景色 */
|
||||||
|
stroke-width: 8; /* 环的宽度(细一点) */
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-ring .circle-progress {
|
||||||
|
fill: none;
|
||||||
|
stroke: var(--global-primary-color); /* 使用 CSS 变量 */
|
||||||
|
stroke-width: 8; /* 环的宽度(细一点) */
|
||||||
|
stroke-dasharray: 339.292;
|
||||||
|
stroke-dashoffset: calc(339.292 - (339.292 * var(--progress) / 100));
|
||||||
|
transition: stroke-dashoffset 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-ring .progress-text {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -15,3 +15,4 @@
|
|||||||
@import url("module/dtree/dtree.css");
|
@import url("module/dtree/dtree.css");
|
||||||
@import url("module/layer.css");
|
@import url("module/layer.css");
|
||||||
@import url("module/layout.css");
|
@import url("module/layout.css");
|
||||||
|
@import url("module/popover.min.css");
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{% macro memory_format(memory) %}
|
|
||||||
{%- if memory > 1024 ** 4 * 2 -%}
|
|
||||||
{{- (memory / 1024 ** 4) | round(2) -}}TB
|
|
||||||
{% elif memory > 1024 ** 3 * 2 %}
|
|
||||||
{{- (memory / 1024 ** 3) | round(2) -}}GB
|
|
||||||
{% elif memory > 1024 ** 2 * 2 %}
|
|
||||||
{{- (memory / 1024 ** 2) | round(2) -}}MB
|
|
||||||
{% elif memory > 1024 ** 1 * 2 %}
|
|
||||||
{{- (memory / 1024 ** 1) | round(2) -}}KB
|
|
||||||
{% else %}
|
|
||||||
{{- memory -}}B
|
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
|
||||||
+194
-78
@@ -1,16 +1,15 @@
|
|||||||
{% from 'system/common/memory.html' import memory_format %}
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>首页</title>
|
<title>首页</title>
|
||||||
{% include 'system/common/header.html' %}
|
{% include 'system/common/header.html' %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='system/admin/css/other/console2.css') }}"/>
|
<link rel="stylesheet" href="{{ url_for('static', filename='system/admin/css/other/monitor.css') }}"/>
|
||||||
</head>
|
</head>
|
||||||
<body class="pear-container">
|
<body class="pear-container">
|
||||||
<div class="layui-row layui-col-space10">
|
<div class="layui-row layui-col-space10">
|
||||||
<div class="layui-col-md8">
|
<div class="layui-col-md8">
|
||||||
<div class="layui-row layui-col-space10">
|
<div class="layui-row layui-col-space10">
|
||||||
<div class="layui-col-md6">
|
<div class="layui-col-md6" id="host-info-card">
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div class="layui-card-header">
|
<div class="layui-card-header">
|
||||||
主机信息
|
主机信息
|
||||||
@@ -20,25 +19,25 @@
|
|||||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
||||||
<div class="pear-card2">
|
<div class="pear-card2">
|
||||||
<div class="title">核心数</div>
|
<div class="title">核心数</div>
|
||||||
<div class="count pear-text">{{ cpu_count }}</div>
|
<div class="count pear-text" id="cpu_count">-</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
||||||
<div class="pear-card2">
|
<div class="pear-card2">
|
||||||
<div class="title">空闲率</div>
|
<div class="title">空闲率</div>
|
||||||
<div class="count pear-text"></div>
|
<div class="count pear-text" id="cpu_idle_percent">-%</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
||||||
<div class="pear-card2">
|
<div class="pear-card2">
|
||||||
<div class="title">等待率</div>
|
<div class="title">等待率</div>
|
||||||
<div class="count pear-text"></div>
|
<div class="count pear-text" id="cpu_wait_percent">-%</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
||||||
<div class="pear-card2">
|
<div class="pear-card2">
|
||||||
<div class="title">使用率</div>
|
<div class="title">使用率</div>
|
||||||
<div class="count pear-text">{{ cpus_percent }}%</div>
|
<div class="count pear-text" id="cpus_percent">-%</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -55,25 +54,25 @@
|
|||||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
||||||
<div class="pear-card2">
|
<div class="pear-card2">
|
||||||
<div class="title">空闲内存</div>
|
<div class="title">空闲内存</div>
|
||||||
<div class="count pear-text">{{ memory_format(memory_free) }}</div>
|
<div class="count pear-text" id="memory_free">-</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
||||||
<div class="pear-card2">
|
<div class="pear-card2">
|
||||||
<div class="title">最大内存</div>
|
<div class="title">最大内存</div>
|
||||||
<div class="count pear-text">{{ memory_format(memory_total) }}</div>
|
<div class="count pear-text" id="memory_total">-</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
||||||
<div class="pear-card2">
|
<div class="pear-card2">
|
||||||
<div class="title">已用内存</div>
|
<div class="title">已用内存</div>
|
||||||
<div class="count pear-text">{{ memory_format(memory_used) }}</div>
|
<div class="count pear-text" id="memory_used">-</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
<div class="layui-col-md6 layui-col-sm6 layui-col-xs6">
|
||||||
<div class="pear-card2">
|
<div class="pear-card2">
|
||||||
<div class="title">内存使用</div>
|
<div class="title">内存使用</div>
|
||||||
<div class="count pear-text">{{ memory_usage }}%</div>
|
<div class="count pear-text" id="memory_usage">-%</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -93,27 +92,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-col-md4">
|
<div class="layui-col-md4">
|
||||||
<div class="layui-card">
|
|
||||||
<div class="layui-card-header">磁盘信息</div>
|
|
||||||
<div class="layui-card-body">
|
|
||||||
<ul class="pear-card-status">
|
|
||||||
{% for disk in disk_partitions_list %}
|
|
||||||
<li>
|
|
||||||
<p>{{ disk.device }}</p>
|
|
||||||
<p>{{ disk.fstype }}</p>
|
|
||||||
磁盘大小: <span>{{ memory_format(disk.total) }}</span>
|
|
||||||
空闲大小: <span>{{ memory_format(disk.free) }}</span>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
已经使用: <span>{{ memory_format(disk.used) }}</span>
|
|
||||||
使用率: <span>{{ disk.percent }}%</span>
|
|
||||||
<br/>
|
|
||||||
<a href="javascript:0" data-id="1" class="pear-btn pear-btn-xs pear-btn-primary pear-reply">详情</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div class="layui-card-header">主机信息</div>
|
<div class="layui-card-header">主机信息</div>
|
||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
@@ -127,47 +105,135 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>名称</td>
|
<td>名称</td>
|
||||||
<td>{{ hostname }}</td>
|
<td id="hostname">{{ hostname }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>系统</td>
|
<td>系统</td>
|
||||||
<td>{{ system_version }}</td>
|
<td id="system_version">{{ system_version }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>开机时间</td>
|
<td>开机时间</td>
|
||||||
<td>{{ boot_time }}</td>
|
<td id="boot_time">{{ boot_time }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>运行时长</td>
|
<td>运行时长</td>
|
||||||
<td>{{ up_time_format }}</td>
|
<td id="up_time_format">{{ up_time_format }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>python版本</td>
|
<td>Python 版本</td>
|
||||||
<td>{{ python_version }}</td>
|
<td id="python_version">{{ python_version }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>程序操作</td>
|
<td>程序操作</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="javascript:kill();"
|
<a href="javascript:kill();"
|
||||||
class="pear-btn pear-btn-xs pear-btn-primary">关闭程序</a>
|
class="layui-btn layui-btn-xs layui-btn-primary">关闭程序</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-header">磁盘信息</div>
|
||||||
|
<div class="layui-card-body" id="disk-info-card">
|
||||||
|
加载中......
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="tooltip" style="background-color: unset !important;">
|
||||||
|
<div class="layui-card" style="box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
|
||||||
|
<div class="layui-card-body" style="text-align: center" id="tooltip-cpus">
|
||||||
|
加载中......
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% include 'system/common/footer.html' %}
|
{% include 'system/common/footer.html' %}
|
||||||
<script>
|
<script>
|
||||||
|
var systemInfo = null; // 存储获取到的系统信息对象
|
||||||
|
|
||||||
|
function memoryFormat(memory) {
|
||||||
|
if (memory >= 1024 ** 4 * 2) {
|
||||||
|
return (memory / 1024 ** 4).toFixed(2) + 'TB';
|
||||||
|
} else if (memory >= 1024 ** 3 * 2) {
|
||||||
|
return (memory / 1024 ** 3).toFixed(2) + 'GB';
|
||||||
|
} else if (memory >= 1024 ** 2 * 2) {
|
||||||
|
return (memory / 1024 ** 2).toFixed(2) + 'MB';
|
||||||
|
} else if (memory >= 1024 ** 1 * 2) {
|
||||||
|
return (memory / 1024 ** 1).toFixed(2) + 'KB';
|
||||||
|
} else {
|
||||||
|
return memory + 'B';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function diskinfo(index) {
|
||||||
|
data = systemInfo.disk_partitions_list[index];
|
||||||
|
|
||||||
|
layui.laytpl(`
|
||||||
|
<ul>
|
||||||
|
<li>分区类型: <%= d.fstype %></li>
|
||||||
|
<li>磁盘大小: <%= memoryFormat(d.total) %></li>
|
||||||
|
<li>空闲大小: <%= memoryFormat(d.free) %></li>
|
||||||
|
<li>已经使用: <%= memoryFormat(d.used) %> (<%= d.percent %>%)</li>
|
||||||
|
</ul>
|
||||||
|
`, {
|
||||||
|
open: '<%',
|
||||||
|
close: '%>'
|
||||||
|
}).render(data, function (string) {
|
||||||
|
layui.layer.alert(string);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function kill() {
|
||||||
|
var success = true;
|
||||||
|
layui.$.ajax({
|
||||||
|
url: "/system/monitor/kill",
|
||||||
|
success: function (res) {
|
||||||
|
layui.popup.failure(res.msg);
|
||||||
|
success = false;
|
||||||
|
},
|
||||||
|
complete: function (xhr) {
|
||||||
|
if (success) layui.popup.success("已发送关闭命令。");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
layui.use(['layer', 'echarts', 'popup'], function () {
|
layui.use(['layer', 'echarts', 'popup'], function () {
|
||||||
var $ = layui.jquery,
|
var $ = layui.jquery,
|
||||||
echarts = layui.echarts;
|
echarts = layui.echarts;
|
||||||
let popup = layui.popup;
|
let popup = layui.popup;
|
||||||
|
let laytpl = layui.laytpl;
|
||||||
|
|
||||||
var echartsRecords = echarts.init(document.getElementById('echarts-records'), 'walden');
|
var echartsRecords = echarts.init(document.getElementById('echarts-records'), 'walden');
|
||||||
|
|
||||||
|
|
||||||
|
$('#host-info-card').hover(
|
||||||
|
function () {
|
||||||
|
$('#tooltip').addClass('show');
|
||||||
|
|
||||||
|
// 获取 #cpus_percent-card 的位置、尺寸和宽度
|
||||||
|
const card = $(this);
|
||||||
|
const cardOffset = card.offset(); // 元素相对于文档的偏移量
|
||||||
|
const cardHeight = card.outerHeight(); // 元素的高度
|
||||||
|
const cardWidth = card.outerWidth(); // 元素的宽度
|
||||||
|
|
||||||
|
// 设置悬浮提示框的宽度和位置
|
||||||
|
$('#tooltip').css({
|
||||||
|
top: cardOffset.top + cardHeight + 2, // 放在元素下方 5px
|
||||||
|
left: cardOffset.left - 5, // 与元素左对齐
|
||||||
|
width: cardWidth - 10, // 宽度与元素一致
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
$('#tooltip').removeClass('show');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
$("body").on("click", "[data-url]", function () {
|
$("body").on("click", "[data-url]", function () {
|
||||||
parent.layui.tab.addTabOnlyByElem("content", {
|
parent.layui.tab.addTabOnlyByElem("content", {
|
||||||
id: $(this).attr("data-id"),
|
id: $(this).attr("data-id"),
|
||||||
@@ -188,20 +254,6 @@
|
|||||||
"#00CA69"
|
"#00CA69"
|
||||||
];
|
];
|
||||||
|
|
||||||
let echartData = [
|
|
||||||
{
|
|
||||||
name: "{{time_now}}",
|
|
||||||
cpu_percent: {{ cpus_percent }},
|
|
||||||
memory_percent: {{ memory_usage }}
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
var xAxisData = echartData.map(v => v.name);
|
|
||||||
// ["1", "2", "3", "4", "5", "6", "7", "8"]
|
|
||||||
var yAxisData1 = echartData.map(v => v.cpu_percent);
|
|
||||||
// [100, 138, 350, 173, 180, 150, 180, 230]
|
|
||||||
var yAxisData2 = echartData.map(v => v.memory_percent);
|
|
||||||
// [233, 233, 200, 180, 199, 233, 210, 180]
|
|
||||||
const hexToRgba = (hex, opacity) => {
|
const hexToRgba = (hex, opacity) => {
|
||||||
let rgbaColor = "";
|
let rgbaColor = "";
|
||||||
let reg = /^#[\da-f]{6}$/i;
|
let reg = /^#[\da-f]{6}$/i;
|
||||||
@@ -214,7 +266,9 @@
|
|||||||
return rgbaColor;
|
return rgbaColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
option = {
|
let echartData = [];
|
||||||
|
|
||||||
|
var option = {
|
||||||
backgroundColor: bgColor,
|
backgroundColor: bgColor,
|
||||||
color: color,
|
color: color,
|
||||||
legend: {
|
legend: {
|
||||||
@@ -223,25 +277,9 @@
|
|||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
formatter: function (params) {
|
|
||||||
let html = '';
|
|
||||||
params.forEach(v => {
|
|
||||||
html +=
|
|
||||||
`<div style="color: #666;font-size: 14px;line-height: 24px">
|
|
||||||
<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${color[v.componentIndex]};"></span>
|
|
||||||
${v.seriesName}.${v.name}
|
|
||||||
<span style="color:${color[v.componentIndex]};font-weight:700;font-size: 18px">${v.value}</span>
|
|
||||||
%`;
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
return html
|
|
||||||
},
|
|
||||||
extraCssText: 'background: #fff; border-radius: 0;box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);color: #333;',
|
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
type: 'shadow',
|
type: 'shadow',
|
||||||
shadowStyle: {
|
shadowStyle: {
|
||||||
color: '#ffffff',
|
|
||||||
shadowColor: 'rgba(225,225,225,1)',
|
shadowColor: 'rgba(225,225,225,1)',
|
||||||
shadowBlur: 5
|
shadowBlur: 5
|
||||||
}
|
}
|
||||||
@@ -265,7 +303,7 @@
|
|||||||
color: "#D9D9D9"
|
color: "#D9D9D9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: xAxisData
|
data: null
|
||||||
}],
|
}],
|
||||||
yAxis: [{
|
yAxis: [{
|
||||||
type: "value",
|
type: "value",
|
||||||
@@ -329,7 +367,7 @@
|
|||||||
shadowBlur: 10
|
shadowBlur: 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: yAxisData1
|
data: null
|
||||||
}, {
|
}, {
|
||||||
name: '内存',
|
name: '内存',
|
||||||
type: "line",
|
type: "line",
|
||||||
@@ -366,7 +404,7 @@
|
|||||||
shadowBlur: 10
|
shadowBlur: 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: yAxisData2
|
data: null
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -376,17 +414,96 @@
|
|||||||
echartsRecords.resize();
|
echartsRecords.resize();
|
||||||
};
|
};
|
||||||
|
|
||||||
setInterval(ajaxPolling, 1000 * 10);
|
ajaxPolling();
|
||||||
|
setInterval(ajaxPolling, 1000 * 5);
|
||||||
|
|
||||||
function ajaxPolling() {
|
function ajaxPolling() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/system/monitor/polling",
|
url: "/system/monitor/polling",
|
||||||
success: function (data) {
|
success: function (result) {
|
||||||
|
data = result.data;
|
||||||
|
systemInfo = data;
|
||||||
|
|
||||||
|
|
||||||
|
// 更新使用率等信息
|
||||||
|
document.querySelector("#cpu_count").innerText = data.cpu_count;
|
||||||
|
document.querySelector("#cpus_percent").innerText = data.cpus_percent + "%";
|
||||||
|
document.querySelector("#cpu_idle_percent").innerText = data.cpu_idle_percent + "%";
|
||||||
|
document.querySelector("#cpu_wait_percent").innerText = data.cpu_wait_percent + "%";
|
||||||
|
|
||||||
|
document.querySelector("#memory_used").innerText = memoryFormat(data.memory_used);
|
||||||
|
document.querySelector("#memory_total").innerText = memoryFormat(data.memory_total);
|
||||||
|
document.querySelector("#memory_free").innerText = memoryFormat(data.memory_free);
|
||||||
|
document.querySelector("#memory_usage").innerText = data.memory_usage + "%";
|
||||||
|
|
||||||
|
// 基本信息
|
||||||
|
document.querySelector("#hostname").innerText = data.basic_info.hostname;
|
||||||
|
document.querySelector("#system_version").innerText = data.basic_info.system_version;
|
||||||
|
document.querySelector("#boot_time").innerText = data.basic_info.boot_time;
|
||||||
|
document.querySelector("#up_time_format").innerText = data.basic_info.up_time_format;
|
||||||
|
document.querySelector("#python_version").innerText = data.basic_info.python_version;
|
||||||
|
|
||||||
|
|
||||||
|
// 更新每一个CPU使用率
|
||||||
|
laytpl(`
|
||||||
|
<ul>
|
||||||
|
<%# layui.each(d, function(index, data){ %>
|
||||||
|
<li>
|
||||||
|
<span class="layui-badge layui-bg-blue">CPU <%= data[0] %>: <%= data[1] %>%</span>
|
||||||
|
</li>
|
||||||
|
<%# }); %>
|
||||||
|
</ul>
|
||||||
|
`, {
|
||||||
|
open: '<%',
|
||||||
|
close: '%>'
|
||||||
|
}).render(data.cpu_percent_per_core, function (string) {
|
||||||
|
document.querySelector("#tooltip-cpus").innerHTML = string;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// 更新硬盘信息
|
||||||
|
laytpl(`
|
||||||
|
<fieldset class="layui-elem-field layui-field-title"></fieldset>
|
||||||
|
<%# layui.each(d, function(index, data){ %>
|
||||||
|
<div class="layui-row" style="display: flex; align-items: center;">
|
||||||
|
<div class="progress-ring" style="margin-right: 50px;">
|
||||||
|
<svg class="circle" width="120" height="120" viewBox="0 0 120 120">
|
||||||
|
<circle class="circle-bg" cx="60" cy="60" r="54"/>
|
||||||
|
<circle class="circle-progress" cx="60" cy="60" r="54" style="--progress: <%= data.percent %>"/>
|
||||||
|
</svg>
|
||||||
|
<div class="progress-text"><%= data.device %></div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-col-space10" style="display: flex; align-items: center;">
|
||||||
|
<ul>
|
||||||
|
<li>分区类型: <%= data.fstype %></li>
|
||||||
|
<li>磁盘大小: <%= memoryFormat(data.total) %></li>
|
||||||
|
<li>空闲大小: <%= memoryFormat(data.free) %></li>
|
||||||
|
<li>已经使用: <%= memoryFormat(data.used) %> (<%= data.percent %>%)</li>
|
||||||
|
<li>
|
||||||
|
<a href="javascript:diskinfo(<%= index %>)" data-id="1"
|
||||||
|
class="layui-btn layui-btn-xs layui-btn-primary pear-reply">查看详情
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<fieldset class="layui-elem-field layui-field-title"></fieldset>
|
||||||
|
<%# }) %>
|
||||||
|
`, {
|
||||||
|
open: '<%',
|
||||||
|
close: '%>'
|
||||||
|
}).render(data.disk_partitions_list, function (string) {
|
||||||
|
document.querySelector("#disk-info-card").innerHTML = string;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// 更新图表
|
||||||
echartData.push({
|
echartData.push({
|
||||||
name: data.time_now,
|
name: data.time_now,
|
||||||
cpu_percent: data.cups_percent,
|
cpu_percent: data.cpus_percent,
|
||||||
memory_percent: data.memory_used
|
memory_percent: data.memory_usage
|
||||||
});
|
});
|
||||||
|
|
||||||
if (echartData.length > 8) {
|
if (echartData.length > 8) {
|
||||||
echartData.shift();
|
echartData.shift();
|
||||||
}
|
}
|
||||||
@@ -403,7 +520,6 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
error: function (xhr, type, errorThrown) {
|
error: function (xhr, type, errorThrown) {
|
||||||
popup.failure("api错误");
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user