发布新版本v20250429213045
This commit is contained in:
parent
29ac1b288e
commit
08c23af39c
@ -1 +1 @@
|
||||
v20250422193845
|
||||
v20250429213045
|
@ -1,22 +0,0 @@
|
||||
{
|
||||
"NTES_GOD_IMAGES": 0.54,
|
||||
"NTES_GOD_VIDEOS": 3.8,
|
||||
"NTES_GOD_CHAT_IMAGES": 0.54,
|
||||
"NTES_GOD_CHAT_VIDEOS": 3.8,
|
||||
"NTES_DASONG": 139.19,
|
||||
"SPIDER_VIDEO": 3.8,
|
||||
"SPIDER_VIDEO_SP": 13.3,
|
||||
"NTES_GOD_AI": 0.54,
|
||||
"NTES_GOD_TOP": 3.8,
|
||||
"T_SPIDER_VIDEO": 3.8,
|
||||
"T_SPIDER_VIDEO_SP": 13.3,
|
||||
"V_SPIDER_VIDEO": 3.8,
|
||||
"V_SPIDER_VIDEO_SP": 13.3,
|
||||
"NTES_GOD_XHS": 0.54,
|
||||
"XHS_SPIDER_VIDEO": 3.8,
|
||||
"Cupid": 0.54,
|
||||
"CHAT_P2P": 0.55,
|
||||
"CHAT_TEAM": 0.55,
|
||||
"CHAT_ROOM": 0.55,
|
||||
"CHAT_ROOM_MSG": 0.55
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{ "comment": 0.55, "feed": 1.54, "complaint": 5.4 }
|
707
cms_monitor.py
707
cms_monitor.py
File diff suppressed because one or more lines are too long
2418
dashboard.py
2418
dashboard.py
File diff suppressed because one or more lines are too long
449
download_auto_run.py
Normal file
449
download_auto_run.py
Normal file
@ -0,0 +1,449 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Python 2.7 Auto Download Script
|
||||
For NetEase Da Shen Review Data Monitoring System
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import shutil
|
||||
import urllib2
|
||||
import getpass
|
||||
import base64
|
||||
import subprocess
|
||||
import traceback
|
||||
import codecs
|
||||
from datetime import datetime
|
||||
|
||||
# 先尝试设置控制台代码页为UTF-8(仅Windows环境)
|
||||
try:
|
||||
if sys.platform.startswith('win'):
|
||||
subprocess.call('chcp 936', shell=True)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 基本配置
|
||||
#COS_URL = "http://cos.ui-beam.com/work_scripts/monitor/dev/latest/"
|
||||
COS_URL = "https://gitea.ui-beam.cn/ui_beam/NetEaseDSMonitor/raw/branch/main/"
|
||||
TEMP_DIR = os.path.join(os.path.expanduser("~"), "Desktop", "monitor_temp")
|
||||
LOG_FILE = os.path.join(TEMP_DIR, "download_log.txt")
|
||||
|
||||
# 要下载的文件列表 - 格式: (URL相对路径, 本地保存路径, 是否必需)
|
||||
FILES_TO_DOWNLOAD = [
|
||||
("start_monitor.cmd", "start_monitor.cmd", True),
|
||||
("dashboard.py", "dashboard.py", True),
|
||||
("breeze_monitor.py", "breeze_monitor.py", True),
|
||||
("breeze_monitor_CHAT.py", "breeze_monitor_CHAT.py", True),
|
||||
("cms_monitor.py", "cms_monitor.py", True),
|
||||
("cms_coefficients.json", "cms_coefficients.json", True),
|
||||
("breeze_coefficients.json", "breeze_coefficients.json", True),
|
||||
("templates/dashboard.html", "templates/dashboard.html", True),
|
||||
("templates/login.html", "templates/login.html", True),
|
||||
("static/ds-favicon.ico", "static/ds-favicon.ico", True),
|
||||
("install_dependencies.bat", "install_dependencies.bat", True),
|
||||
("inspect_monitor.py", "inspect_monitor.py", True)
|
||||
]
|
||||
|
||||
# 记录日志函数
|
||||
def log_message(message):
|
||||
"""记录日志消息"""
|
||||
try:
|
||||
# 确保日志目录存在
|
||||
log_dir = os.path.dirname(LOG_FILE)
|
||||
if not os.path.exists(log_dir):
|
||||
os.makedirs(log_dir)
|
||||
|
||||
# 使用codecs打开文件,指定编码为gbk
|
||||
with codecs.open(LOG_FILE, "a", "gbk") as f:
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
log_line = "[%s] %s\n" % (timestamp, message)
|
||||
f.write(log_line)
|
||||
|
||||
# 使用safe_print输出到控制台
|
||||
safe_print(message)
|
||||
except Exception as e:
|
||||
safe_print("[ERROR] Could not write to log file: %s" % str(e))
|
||||
|
||||
# 使用UTF-8安全打印
|
||||
def safe_print(text):
|
||||
"""安全打印函数,处理编码问题"""
|
||||
try:
|
||||
if isinstance(text, unicode):
|
||||
print(text.encode('gbk', 'ignore'))
|
||||
else:
|
||||
print(text)
|
||||
except UnicodeEncodeError:
|
||||
print(text.encode('gbk', 'ignore'))
|
||||
except Exception as e:
|
||||
print("[ERROR] Print error: %s" % str(e))
|
||||
|
||||
# 获取最新版本号
|
||||
def get_latest_version():
|
||||
"""获取最新版本号"""
|
||||
try:
|
||||
#version_url = "http://cos.ui-beam.com/work_scripts/monitor/dev/latest/VERSION.txt" # 测试版本版本号地址
|
||||
version_url = "https://gitea.ui-beam.cn/ui_beam/NetEaseDSMonitor/raw/branch/main/VERSION.txt" # 正式版本版本号地址
|
||||
response = urllib2.urlopen(version_url)
|
||||
version = response.read().strip()
|
||||
return version
|
||||
except Exception as e:
|
||||
error_msg = u"获取版本号失败: %s" % unicode(str(e), 'gbk', 'ignore')
|
||||
safe_print(error_msg)
|
||||
return u"未知版本"
|
||||
|
||||
# 非中文字符界面信息
|
||||
MESSAGES = {
|
||||
'tool_title': u"网易大神审核数据监控系统安装工具",
|
||||
'no_auth_version': u"当前最新版本:{0}".format(get_latest_version()),
|
||||
'downloading': u"正在下载文件,请稍候...",
|
||||
'script_started': u"下载脚本已启动",
|
||||
'temp_dir': u"临时目录",
|
||||
'dir_init_failed': u"初始化目录失败,退出",
|
||||
'created_temp_dir': u"创建临时目录",
|
||||
'dir_exists': u"临时目录已存在,正在清理内容...",
|
||||
'dir_cleared': u"临时目录已清理",
|
||||
'created_templates_dir': u"创建templates目录",
|
||||
'created_static_dir': u"创建static目录",
|
||||
'using_proxy': u"使用代理下载",
|
||||
'retrying_with_proxy': u"尝试使用代理重试...",
|
||||
'downloaded_files': u"已下载文件",
|
||||
'of': u"个,共",
|
||||
'files': u"个文件",
|
||||
'download_required_failed': u"部分必需文件下载失败",
|
||||
'all_files_downloaded': u"所有文件下载成功",
|
||||
'install_deps_not_found': u"依赖安装脚本未找到",
|
||||
'installing_deps': u"正在安装依赖...",
|
||||
'deps_output': u"依赖安装输出",
|
||||
'deps_error': u"依赖安装错误",
|
||||
'deps_installed': u"依赖安装成功",
|
||||
'deps_failed': u"依赖安装失败,返回码",
|
||||
'deps_script_error': u"运行依赖安装脚本出错",
|
||||
'start_script_not_found': u"启动脚本未找到",
|
||||
'starting_system': u"正在启动监控系统...",
|
||||
'system_started': u"监控系统启动成功",
|
||||
'start_system_failed': u"启动监控系统失败",
|
||||
'manual_guide_title': u"手动安装指南",
|
||||
'manual_guide_intro': u"如果自动安装失败,请按照以下步骤手动安装:",
|
||||
'use_ie': u"1. 获取系统文件:使用浏览器下载这些文件:",
|
||||
'save_to_structure': u"2. 文件结构:将文件保存到以下结构:",
|
||||
'run_deps_first': u"3. 安装依赖:运行install_dependencies.bat安装依赖",
|
||||
'then_run_start': u"4. 启动系统:运行start_monitor.cmd启动系统",
|
||||
'created_manual_guide': u"已创建手动安装指南",
|
||||
'create_guide_failed': u"创建手动指南失败",
|
||||
'script_copied': u"已将下载脚本复制到临时目录",
|
||||
'copy_script_failed': u"复制脚本失败",
|
||||
'deps_install_failed_try_start': u"依赖安装失败,尝试直接启动监控系统",
|
||||
'steps_failed': u"某些步骤失败,请检查日志获取详情",
|
||||
'try_manual': u"您可以尝试使用以下指南手动安装",
|
||||
'unhandled_exception': u"未处理的异常",
|
||||
'execution_completed': u"脚本执行完成",
|
||||
'press_enter': u"按回车键退出..."
|
||||
}
|
||||
|
||||
# 初始化目录函数
|
||||
def init_directory():
|
||||
"""初始化临时目录"""
|
||||
try:
|
||||
# 创建主目录
|
||||
if not os.path.exists(TEMP_DIR):
|
||||
os.makedirs(TEMP_DIR)
|
||||
log_message("[INFO] %s: %s" % (MESSAGES['created_temp_dir'], TEMP_DIR))
|
||||
else:
|
||||
log_message("[INFO] %s" % MESSAGES['dir_exists'])
|
||||
|
||||
# 清理现有目录内容,只保留日志文件
|
||||
for item in os.listdir(TEMP_DIR):
|
||||
item_path = os.path.join(TEMP_DIR, item)
|
||||
if item != "download_log.txt": # 现在只保留日志文件
|
||||
if os.path.isdir(item_path):
|
||||
shutil.rmtree(item_path)
|
||||
else:
|
||||
os.remove(item_path)
|
||||
|
||||
log_message("[INFO] %s" % MESSAGES['dir_cleared'])
|
||||
|
||||
# 创建templates子目录
|
||||
templates_dir = os.path.join(TEMP_DIR, "templates")
|
||||
if not os.path.exists(templates_dir):
|
||||
os.makedirs(templates_dir)
|
||||
log_message("[INFO] %s" % MESSAGES['created_templates_dir'])
|
||||
|
||||
# 创建static子目录
|
||||
static_dir = os.path.join(TEMP_DIR, "static")
|
||||
if not os.path.exists(static_dir):
|
||||
os.makedirs(static_dir)
|
||||
log_message("[INFO] %s" % MESSAGES['created_static_dir'])
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
log_message("[ERROR] Failed to initialize directory: %s" % str(e))
|
||||
return False
|
||||
|
||||
# 下载函数
|
||||
def download_file(url_path, local_path, use_proxy=False):
|
||||
"""下载单个文件,默认不使用代理"""
|
||||
full_url = "%s/%s" % (COS_URL, url_path)
|
||||
full_local_path = os.path.join(TEMP_DIR, local_path)
|
||||
|
||||
# 确保目标目录存在
|
||||
local_dir = os.path.dirname(full_local_path)
|
||||
if not os.path.exists(local_dir):
|
||||
os.makedirs(local_dir)
|
||||
|
||||
log_message("[INFO] Downloading %s to %s" % (full_url, full_local_path))
|
||||
|
||||
try:
|
||||
# 设置代理信息
|
||||
if use_proxy:
|
||||
log_message("[INFO] %s" % MESSAGES['using_proxy'])
|
||||
proxy_handler = urllib2.ProxyHandler({
|
||||
'http': 'http://CD-WEBPROXY02.yajuenet.internal:8080',
|
||||
'https': 'http://CD-WEBPROXY02.yajuenet.internal:8080'
|
||||
})
|
||||
opener = urllib2.build_opener(proxy_handler)
|
||||
urllib2.install_opener(opener)
|
||||
else:
|
||||
# 禁用代理
|
||||
proxy_handler = urllib2.ProxyHandler({})
|
||||
opener = urllib2.build_opener(proxy_handler)
|
||||
urllib2.install_opener(opener)
|
||||
|
||||
# 下载文件
|
||||
response = urllib2.urlopen(full_url, timeout=30)
|
||||
content = response.read()
|
||||
|
||||
# 写入文件
|
||||
with open(full_local_path, 'wb') as f:
|
||||
f.write(content)
|
||||
|
||||
log_message("[INFO] Successfully downloaded: %s" % local_path)
|
||||
return True
|
||||
|
||||
except urllib2.URLError as e:
|
||||
log_message("[ERROR] Failed to download %s: %s" % (url_path, str(e)))
|
||||
|
||||
# 如果不使用代理失败,尝试使用代理
|
||||
if not use_proxy:
|
||||
log_message("[INFO] %s" % MESSAGES['retrying_with_proxy'])
|
||||
return download_file(url_path, local_path, True)
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
log_message("[ERROR] Failed to download %s: %s" % (url_path, str(e)))
|
||||
return False
|
||||
|
||||
# 下载所有文件
|
||||
def download_all_files():
|
||||
"""下载所有必要的文件"""
|
||||
success_count = 0
|
||||
failed_required = False
|
||||
|
||||
for url_path, local_path, required in FILES_TO_DOWNLOAD:
|
||||
# 先尝试不使用代理下载
|
||||
if download_file(url_path, local_path, False):
|
||||
success_count += 1
|
||||
elif required:
|
||||
failed_required = True
|
||||
|
||||
log_message("[INFO] %s %d %s %d %s" % (
|
||||
MESSAGES['downloaded_files'],
|
||||
success_count,
|
||||
MESSAGES['of'],
|
||||
len(FILES_TO_DOWNLOAD),
|
||||
MESSAGES['files']
|
||||
))
|
||||
|
||||
if failed_required:
|
||||
log_message("[ERROR] %s" % MESSAGES['download_required_failed'])
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# 运行依赖安装脚本
|
||||
def run_install_dependencies():
|
||||
"""运行依赖安装脚本"""
|
||||
install_script = os.path.join(TEMP_DIR, "install_dependencies.bat")
|
||||
|
||||
if not os.path.exists(install_script):
|
||||
log_message("[ERROR] %s: %s" % (MESSAGES['install_deps_not_found'], install_script))
|
||||
return False
|
||||
|
||||
try:
|
||||
log_message("[INFO] %s" % MESSAGES['installing_deps'])
|
||||
|
||||
# 记录当前工作目录
|
||||
original_dir = os.getcwd()
|
||||
|
||||
# 切换到临时目录并启动脚本
|
||||
os.chdir(TEMP_DIR)
|
||||
|
||||
# 使用subprocess运行批处理文件并显示在控制台
|
||||
# 移除stdout和stderr的PIPE重定向,让输出直接显示在控制台
|
||||
process = subprocess.Popen(["cmd", "/c", install_script],
|
||||
shell=True)
|
||||
|
||||
# 等待脚本执行完成
|
||||
return_code = process.wait()
|
||||
|
||||
# 返回到原始目录
|
||||
os.chdir(original_dir)
|
||||
|
||||
if return_code == 0:
|
||||
log_message("[INFO] %s" % MESSAGES['deps_installed'])
|
||||
return True
|
||||
else:
|
||||
log_message("[ERROR] %s: %d" % (MESSAGES['deps_failed'], return_code))
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
log_message("[ERROR] %s: %s" % (MESSAGES['deps_script_error'], str(e)))
|
||||
return False
|
||||
|
||||
# 启动监控系统
|
||||
def start_monitor_system():
|
||||
"""启动监控系统"""
|
||||
start_script = os.path.join(TEMP_DIR, "start_monitor.cmd")
|
||||
|
||||
if not os.path.exists(start_script):
|
||||
log_message("[ERROR] %s: %s" % (MESSAGES['start_script_not_found'], start_script))
|
||||
return False
|
||||
|
||||
try:
|
||||
log_message("[INFO] %s" % MESSAGES['starting_system'])
|
||||
|
||||
# 记录当前工作目录
|
||||
original_dir = os.getcwd()
|
||||
|
||||
# 切换到临时目录并启动脚本
|
||||
os.chdir(TEMP_DIR)
|
||||
|
||||
# 使用subprocess启动批处理文件,不等待其完成
|
||||
process = subprocess.Popen(["cmd", "/c", "start", "", "start_monitor.cmd"],
|
||||
shell=True)
|
||||
|
||||
# 返回到原始目录
|
||||
os.chdir(original_dir)
|
||||
|
||||
log_message("[INFO] %s" % MESSAGES['system_started'])
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
log_message("[ERROR] %s: %s" % (MESSAGES['start_system_failed'], str(e)))
|
||||
return False
|
||||
|
||||
# 创建手动指南
|
||||
def create_manual_guide():
|
||||
"""创建手动安装指南"""
|
||||
guide_path = os.path.join(TEMP_DIR, "manual_install_guide.txt")
|
||||
|
||||
try:
|
||||
with codecs.open(guide_path, "w", "gbk") as f:
|
||||
f.write("=" * 50 + "\n")
|
||||
f.write("%s\n" % MESSAGES['manual_guide_title'])
|
||||
f.write("=" * 50 + "\n\n")
|
||||
|
||||
f.write("%s\n\n" % MESSAGES['manual_guide_intro'])
|
||||
|
||||
f.write("%s\n\n" % MESSAGES['use_ie'])
|
||||
|
||||
for url_path, local_path, required in FILES_TO_DOWNLOAD:
|
||||
full_url = "%s/%s" % (COS_URL, url_path)
|
||||
f.write(" %s\n" % full_url)
|
||||
|
||||
f.write("\n%s\n\n" % MESSAGES['save_to_structure'])
|
||||
f.write(" %s/\n" % TEMP_DIR)
|
||||
f.write(" |-- start_monitor.cmd\n")
|
||||
f.write(" |-- dashboard.py\n")
|
||||
f.write(" |-- breeze_monitor.py\n")
|
||||
f.write(" |-- breeze_monitor_CHAT.py\n")
|
||||
f.write(" |-- cms_monitor.py\n")
|
||||
f.write(" |-- inspect_monitor.py\n")
|
||||
f.write(" |-- cms_coefficients.json\n")
|
||||
f.write(" |-- breeze_coefficients.json\n")
|
||||
f.write(" |-- install_dependencies.bat\n")
|
||||
f.write(" |-- templates/\n")
|
||||
f.write(" | |-- dashboard.html\n")
|
||||
f.write(" | |-- login.html\n")
|
||||
f.write(" |-- static/\n")
|
||||
f.write(" |-- ds-favicon.ico\n\n")
|
||||
|
||||
f.write("%s\n\n" % MESSAGES['run_deps_first'])
|
||||
f.write("%s\n\n" % MESSAGES['then_run_start'])
|
||||
|
||||
f.write("=" * 50 + "\n")
|
||||
|
||||
log_message("[INFO] %s: %s" % (MESSAGES['created_manual_guide'], guide_path))
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
log_message("[ERROR] %s: %s" % (MESSAGES['create_guide_failed'], str(e)))
|
||||
return False
|
||||
|
||||
# 主函数
|
||||
def main():
|
||||
"""主函数"""
|
||||
try:
|
||||
# 使用print可能会更安全,不使用log_message来输出开头的界面
|
||||
safe_print(u"\n%s" % MESSAGES['tool_title'])
|
||||
print("======================================================\n")
|
||||
safe_print(u"%s" % MESSAGES['no_auth_version'])
|
||||
safe_print(u"%s\n" % MESSAGES['downloading'])
|
||||
|
||||
# 初始化日志
|
||||
if not os.path.exists(os.path.dirname(LOG_FILE)):
|
||||
os.makedirs(os.path.dirname(LOG_FILE))
|
||||
|
||||
log_message("\n" + "=" * 40)
|
||||
log_message("[INFO] %s" % MESSAGES['script_started'])
|
||||
log_message("[INFO] %s: %s" % (MESSAGES['temp_dir'], TEMP_DIR))
|
||||
|
||||
# 初始化目录
|
||||
if not init_directory():
|
||||
log_message("[ERROR] %s" % MESSAGES['dir_init_failed'])
|
||||
return 1
|
||||
|
||||
# 创建手动指南
|
||||
create_manual_guide()
|
||||
|
||||
# 下载文件
|
||||
if download_all_files():
|
||||
log_message("[INFO] %s" % MESSAGES['all_files_downloaded'])
|
||||
|
||||
# 安装依赖
|
||||
if run_install_dependencies():
|
||||
log_message("[INFO] %s" % MESSAGES['deps_installed'])
|
||||
|
||||
# 启动监控系统
|
||||
if start_monitor_system():
|
||||
# 稍等几秒,让监控系统先启动
|
||||
time.sleep(3)
|
||||
return 0
|
||||
else:
|
||||
log_message("[WARNING] %s" % MESSAGES['deps_install_failed_try_start'])
|
||||
if start_monitor_system():
|
||||
# 稍等几秒,让监控系统先启动
|
||||
time.sleep(3)
|
||||
return 0
|
||||
|
||||
log_message("[WARNING] %s" % MESSAGES['steps_failed'])
|
||||
log_message("[INFO] %s: %s" % (
|
||||
MESSAGES['try_manual'],
|
||||
os.path.join(TEMP_DIR, "manual_install_guide.txt")
|
||||
))
|
||||
return 1
|
||||
|
||||
except Exception as e:
|
||||
log_message("[ERROR] %s: %s" % (MESSAGES['unhandled_exception'], str(e)))
|
||||
log_message("[TRACE] %s" % traceback.format_exc())
|
||||
return 1
|
||||
|
||||
finally:
|
||||
log_message("[INFO] %s" % MESSAGES['execution_completed'])
|
||||
|
||||
# 入口点
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -1,49 +1,388 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import base64,zlib,sys,os,time,random
|
||||
import threading,importlib,subprocess
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import requests
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from threading import Lock
|
||||
import signal
|
||||
import sys
|
||||
import threading
|
||||
|
||||
def _agAjBFr1KeeY(d,k):
|
||||
return bytes(a^b for a,b in zip(d,k*(len(d)//len(k)+1)))
|
||||
# 配置日志
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler('inspect_monitor.log'),
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
|
||||
def _D1AyQvAz0(t,m,is_error=False):
|
||||
try:
|
||||
try:
|
||||
from playsound import playsound
|
||||
except ImportError:
|
||||
subprocess.check_call([sys.executable,"-m","pip","install","playsound==1.2.2"],
|
||||
stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
|
||||
from playsound import playsound
|
||||
# 增加log函数,兼容自定义日志调用
|
||||
def log(message):
|
||||
try:
|
||||
logging.info(f"[INSPECT] {message}")
|
||||
except Exception as e:
|
||||
print(f"日志记录失败: {str(e)}")
|
||||
print(f"原始消息: {message}")
|
||||
|
||||
# 常量定义
|
||||
INSPECT_API_URL = "https://api.cc.163.com/v1/inspectapi/forumtrack/tracklog/searchtracklog"
|
||||
COEFFICIENT = 1.5 # CC审核平台的系数
|
||||
HOURLY_DATA_FILE = "inspect_hourly.json"
|
||||
DAILY_DATA_FILE = "inspect_daily.json"
|
||||
COEFFICIENTS_CONFIG_FILE = "inspect_coefficients.json"
|
||||
DEFAULT_COEFFICIENTS = {"default": 1.5}
|
||||
COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
|
||||
coefficients_lock = Lock()
|
||||
|
||||
try:
|
||||
import winsound
|
||||
sound_type = winsound.MB_ICONERROR if is_error else winsound.MB_ICONINFORMATION
|
||||
winsound.MessageBeep(sound_type)
|
||||
except:
|
||||
print("\a")
|
||||
def handle_exit(signum, frame):
|
||||
logging.info(f"收到退出信号({signum}),即将退出")
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGTERM, handle_exit)
|
||||
signal.signal(signal.SIGINT, handle_exit)
|
||||
|
||||
print("\n" + "="*50)
|
||||
print(f"{t}: {m}")
|
||||
print("="*50 + "\n")
|
||||
def get_inspect_stats(username, cookie, start_time, end_time):
|
||||
"""获取CC审核平台的统计数据"""
|
||||
try:
|
||||
# 每次统计前主动加载系数,确保用到最新
|
||||
load_coefficients()
|
||||
# 准备请求数据
|
||||
data = {
|
||||
"data": {
|
||||
"form": {
|
||||
"operator": f"{username.lower()}@mail.go",
|
||||
"startTime": start_time,
|
||||
"endTime": end_time,
|
||||
"tid": "",
|
||||
"pid": ""
|
||||
},
|
||||
"page": 1,
|
||||
"pageSize": 500
|
||||
}
|
||||
}
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"\n{t}: {m} (提示音播放失败: {str(e)})\n")
|
||||
return False
|
||||
# 设置请求头
|
||||
headers = {
|
||||
"accept": "application/json, text/plain, */*",
|
||||
"content-type": "text/plain",
|
||||
"cookie": cookie,
|
||||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
|
||||
}
|
||||
|
||||
def _cPsIFmOQB7j(t,m,e=0):
|
||||
_D1AyQvAz0(t,m,e==1)
|
||||
# 发送请求
|
||||
response = requests.post(INSPECT_API_URL, headers=headers, json=data)
|
||||
response.raise_for_status()
|
||||
|
||||
# 解析响应
|
||||
result = response.json()
|
||||
if result.get("code") == "OK":
|
||||
total = result.get("data", {}).get("result", {}).get("total", 0)
|
||||
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
_GxOvPU=b'\xb0a=\xce\xc0\x1b\xcb\xfe1:\x8b\xd0\x18>\xdfK'
|
||||
_gFwziLer=b'$o+tpy>uA3DaEu;`dZ7L_Q<Y!baSp}XHRB$m`H`dpvxBp<ctkHfCq4rd6vyE(O^4z8=J|U8n%fGEaYu!ShoytjP~t;+!1GKBL%K07mSCet&S53jplePhN-0G>bMW1LRaixz@3E5%Qiv6=BNC9O(bWYwhnWoYgn0h)^m6j?6^s^0bkATDMpZbrDT!a^@<aD+btx$rDQH$uh^2=)1}D=rO@LkIqml$g9ASgPn86o3@sa%-*_1q+}u?ZrH(H|qnKedv0xSoZAldTzF4M0ri*BJE6xdyRV$aD5UM5`m*Suc+G*kGS(y##OGZ&2X#&JVs#mv<1O#0qQc2opI9TXq1a_9kj{L1=zx6SMi~wYQ#N#8T!UIX7BBm-|cwc*MN!ur|_b@ZZ<yq&M5vSe#Rq!~j+#Zrr_s}BE=#Dh!2<$&C6)jQwzaa*|P~|^UO$C5K?&SF%IO_v8+3I5;z#2D(dK@()gII_V`#EGTqQwN{UY+L{9n^h*?8@bSJupy+Mn<T)#yrexpzA0T%&Z@rA~=jYvnj?zp+fAStSx{FWqVOa!Zm5<eXa{Q2&?BQb)XAFf)OsW!j6p(s8Gz#S6~aoEK<>)u`>yPqreT;4|E8$qq5D_2JJVyGyWR$IUG}N(Hu)h%Y!hCwUc4LE*$^Y+h2piB-XVLKwd<e<p7<dRZ63<^k|a>td4RCnqhjM_yqIzxC_AZC&{T&;P6_4;SS_5&83fbSpZuOj8Z)+a~+$DQ6ACJfVz>;>R$wmU68@{C+>ove+5r%1nw1g?}(yb{vRoyxy}n6PUROVA!=M<1`@7(4xZEKQ83Q8tO}t^TVpXsPq(>I+51r*|Lc-$hfdy8|HC%6-9I+B6FU>$?A{lZH7iA@;V-9J0Qjt#8m~=e0|M#OsiyHk^hTU5Oh}DcKMH&+ep@w!?SNX%wkoG22L@Y(Mt-dx-~&go(P_-&iqJH6n3l`!G1DqHQhnH%&v3lIp0A?#<u9LnAG25q#*#zo4+($cYOO7GIpJtI)<K5!Kv4R9ad)UW12>G*f`7Q(ow6LPo4|tmf!%jM4An1k>T_?3TX$e&vM(drPU^}GBm*8YB)U8!v%!Al@5#g}t#qLNyJxP7lB$V)@XZ&Sj3qUO!4TOraIKQ>Ix=gIGx>QNd9lsG8rYxeCmAk0{%Vr`=|cmy9PoL?!?+*$Dr2Az89&e%of1OcskJK}r1KheQ~o8IFdu~9Jh9Smm*s2o_C4MuxzVYt`#-Tg{7mqyt-X)VrB4&V^?81Eu0neQLMva>q3Vb7DwRg&B6a?dakHQ@e4uUdw*`x2W_;m9yK4=f>I~*#0Ofo#cND5o6@~PC|098cPv>4(!%ri4@yMe~vWIJ9tjZ31OXHV`YM6=0+~k$N={pO8X6%?WO(1?NWD1AUGu+7_a`%mm3`zu^&d%viF=|`N@X%?Ts)d+ko`wET#xTGDUc?9?mTtHmbk=g@v#-s`Bcd(U3Q1#?hjA%x4P`Fvr9&#@rLcNIg)P%^K2X?9!#oNbLiDj>{vljxpU_IM1vZkn{D^8weA2XVTllzsmnYOXD8qUdwOCD1x(HM-^GVkUjuP0aiu%h^nxsY5Q?bOm23&0L@^zS+_oX<M9aKuA-YrKxAb{I+F%O+M(qRYUcW+^egQjgwGOb>8Z--sH7)@&tJi>U@nzPq-C6)mk<>%j?bN7=d7{~k)n1JWW62thI+VjmV)=V;vb-UK24;s`#ilsgsV^d=G4J!K=^8Sp9E5a;_>a%f}>t{k9OhaPmI7%@Uno#+1rHkPmDAv~$2s$=yuL0`~{icK>eaB0}v{vGyD)7@%_Cz(#F93$Yawn$rjeJ6Cze{-iN<H6nMpH^{s_OP4>GZukh5$O1uxEs(K{T(nORm;V)!Ot|vZPfnw=m~(VN+FguJ)7rHs@~7?_k~ro1c8o1QRCP&Nay@=k>+I0R`IJs1a_ic8)yxn23wU)L!8+pxdTktI?3Y?JF-$iQF;|fuX*G<i~Y`Z@{Vcimuw(cj5nz9P+2w9U^~|h{EK)5UQ%wDc%I16oKG<$PI->Ti5uGD#R)w=^cDZ$MLU7iGi@cvD2^z%-0iN3>pGITSp*9^tS|@P4fajWst&=VE=%Q%sbdQ-1`p`4}-um0ARB}YCw+&YHGFtpWl_?{&Znx9Q)@`KGT(h3im`!K5wVypq6>#lToBFWjsZae{5<9$=Orz=gSyw-xQ;H{xx|=Pdg_r^RX1B8Gg)~v!h`CfpSJWmX4QstDGpw1J-{2<`I8}mTQ_nLb!0HO%o1&KD^Hf+6VCSpB_w^ZdoZwaQk|}u6b&R`Jh}Pu{5@z&QRj(1WD=!bw6(uOq3B$D#1KXMo1v{Si0o2$G(yq*&@)gt{Dspd2e2(7{?9c*U!m4*=skf>s~>BdF8)3YH<+#<tG-j7a@K^de#><Lk(9|^UF2<YK!oS!l|FH8Lj~mcH~tF%lDr)H+B_1;pJb6o(c'
|
||||
try:
|
||||
_L4lLFNi=base64.b85decode(_gFwziLer)
|
||||
_xoMpEZj=_agAjBFr1KeeY(_L4lLFNi,_GxOvPU)
|
||||
_W9cROmjF=zlib.decompress(_xoMpEZj)
|
||||
exec(compile(_W9cROmjF.decode('utf-8'),'<string>','exec'))
|
||||
except Exception as e:
|
||||
_YdA3Am9Vo="程序无法启动: "+str(e)[:50]
|
||||
_cPsIFmOQB7j("错误",_YdA3Am9Vo,1)
|
||||
sys.exit(1)
|
||||
# 使用从在线链接获取的系数
|
||||
with coefficients_lock:
|
||||
current_coefficient = COEFFICIENTS.get('default', 1.5)
|
||||
|
||||
return {
|
||||
"total": total,
|
||||
"weighted_total": total * current_coefficient,
|
||||
"timestamp": int(time.time()),
|
||||
"update_time": current_time
|
||||
}
|
||||
else:
|
||||
logging.error(f"获取CC审核平台数据失败: {result.get('msg')}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"获取CC审核平台数据时发生错误: {str(e)}")
|
||||
return None
|
||||
|
||||
def save_stats(stats, file_path):
|
||||
"""保存统计数据到文件"""
|
||||
try:
|
||||
with open(file_path, 'w') as f:
|
||||
json.dump(stats, f)
|
||||
except Exception as e:
|
||||
logging.error(f"保存统计数据时发生错误: {str(e)}")
|
||||
|
||||
def load_stats(file_path):
|
||||
"""从文件加载统计数据"""
|
||||
try:
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
logging.error(f"加载统计数据时发生错误: {str(e)}")
|
||||
return {"stats": []}
|
||||
|
||||
def update_hourly_stats(username, cookie):
|
||||
"""更新小时统计数据"""
|
||||
now = datetime.now()
|
||||
start_time = now.strftime("%Y/%m/%d %H:00:00")
|
||||
end_time = now.strftime("%Y/%m/%d %H:59:59")
|
||||
|
||||
stats = get_inspect_stats(username, cookie, start_time, end_time)
|
||||
if stats:
|
||||
hourly_data = load_stats(HOURLY_DATA_FILE)
|
||||
|
||||
# 移除超过24小时的数据
|
||||
current_time = int(time.time())
|
||||
hourly_data["stats"] = [
|
||||
stat for stat in hourly_data["stats"]
|
||||
if current_time - stat["timestamp"] <= 24 * 3600
|
||||
]
|
||||
|
||||
# 添加新数据
|
||||
hourly_data["stats"].append(stats)
|
||||
save_stats(hourly_data, HOURLY_DATA_FILE)
|
||||
logging.info(f"成功更新小时统计数据: {stats}")
|
||||
|
||||
def update_daily_stats(username, cookie):
|
||||
"""更新日统计数据"""
|
||||
now = datetime.now()
|
||||
start_time = now.strftime("%Y/%m/%d 00:00:00")
|
||||
end_time = now.strftime("%Y/%m/%d 23:59:59")
|
||||
|
||||
stats = get_inspect_stats(username, cookie, start_time, end_time)
|
||||
if stats:
|
||||
daily_data = load_stats(DAILY_DATA_FILE)
|
||||
|
||||
# 移除超过7天的数据
|
||||
current_time = int(time.time())
|
||||
daily_data["stats"] = [
|
||||
stat for stat in daily_data["stats"]
|
||||
if current_time - stat["timestamp"] <= 7 * 24 * 3600
|
||||
]
|
||||
|
||||
# 添加新数据
|
||||
daily_data["stats"].append(stats)
|
||||
save_stats(daily_data, DAILY_DATA_FILE)
|
||||
logging.info(f"成功更新日统计数据: {stats}")
|
||||
|
||||
def fetch_and_save_coefficients(url):
|
||||
"""从在线服务器获取系数配置并保存到本地"""
|
||||
max_retries = 3
|
||||
retry_delay = 5 # 重试间隔(秒)
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
# 尝试不使用代理直接获取
|
||||
try:
|
||||
response = requests.get(url, timeout=10, proxies={'http': None, 'https': None}, verify=False)
|
||||
except:
|
||||
# 如果直接获取失败,尝试使用系统代理
|
||||
proxies = {
|
||||
'http': os.environ.get('HTTP_PROXY', ''),
|
||||
'https': os.environ.get('HTTPS_PROXY', '')
|
||||
}
|
||||
response = requests.get(url, timeout=10, proxies=proxies, verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
loaded_coefficients = response.json()
|
||||
# 更新系数
|
||||
COEFFICIENTS.update(loaded_coefficients)
|
||||
# 保存到本地文件
|
||||
with open(COEFFICIENTS_CONFIG_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(loaded_coefficients, f, indent=4, ensure_ascii=False)
|
||||
log(f"从服务器获取系数: {loaded_coefficients}")
|
||||
return True
|
||||
else:
|
||||
log(f"获取在线系数配置失败,HTTP状态码: {response.status_code}")
|
||||
if attempt < max_retries - 1:
|
||||
log(f"第{attempt + 1}次重试失败,{retry_delay}秒后重试...")
|
||||
time.sleep(retry_delay)
|
||||
continue
|
||||
return False
|
||||
except Exception as e:
|
||||
log(f"获取在线系数配置时发生错误: {str(e)}")
|
||||
if attempt < max_retries - 1:
|
||||
log(f"第{attempt + 1}次重试失败,{retry_delay}秒后重试...")
|
||||
time.sleep(retry_delay)
|
||||
continue
|
||||
return False
|
||||
|
||||
def load_coefficients():
|
||||
"""从在线链接获取系数配置,如果获取失败则使用默认配置"""
|
||||
global COEFFICIENTS
|
||||
try:
|
||||
with coefficients_lock:
|
||||
url = "http://scripts.ui-beam.com:5000/NetEaseDSMonitor/config/inspect_coefficients.json"
|
||||
|
||||
# 检查本地文件是否存在
|
||||
local_config_exists = os.path.exists(COEFFICIENTS_CONFIG_FILE)
|
||||
|
||||
# 如果是首次运行或需要强制更新
|
||||
if not local_config_exists:
|
||||
log("首次运行,从在线服务器获取系数配置")
|
||||
if not fetch_and_save_coefficients(url):
|
||||
log("首次获取系数配置失败,使用默认配置")
|
||||
COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
|
||||
return
|
||||
|
||||
# 读取本地配置
|
||||
try:
|
||||
with open(COEFFICIENTS_CONFIG_FILE, 'r', encoding='utf-8') as f:
|
||||
local_coefficients = json.load(f)
|
||||
except Exception as e:
|
||||
log(f"读取本地系数配置失败: {str(e)}")
|
||||
local_coefficients = None
|
||||
|
||||
# 尝试获取在线配置
|
||||
try:
|
||||
response = requests.get(url, timeout=10, proxies={'http': None, 'https': None}, verify=False)
|
||||
if response.status_code == 200:
|
||||
online_coefficients = response.json()
|
||||
|
||||
# 比较配置是否发生变化
|
||||
if local_coefficients != online_coefficients:
|
||||
log("检测到系数配置发生变化,更新本地配置")
|
||||
if fetch_and_save_coefficients(url):
|
||||
log("系数配置更新成功")
|
||||
else:
|
||||
log("系数配置更新失败,继续使用本地配置")
|
||||
else:
|
||||
log("系数配置未发生变化,使用本地配置")
|
||||
else:
|
||||
log(f"获取在线系数配置失败,HTTP状态码: {response.status_code}")
|
||||
except Exception as e:
|
||||
log(f"检查在线系数配置时发生错误: {str(e)}")
|
||||
|
||||
# 使用本地配置
|
||||
if local_coefficients:
|
||||
COEFFICIENTS.update(local_coefficients)
|
||||
log(f"从本地从加载系数: {local_coefficients}")
|
||||
else:
|
||||
COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
|
||||
|
||||
except Exception as e:
|
||||
log(f"加载系数配置失败: {str(e)}")
|
||||
COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
|
||||
|
||||
def monitor_config_thread():
|
||||
"""监控配置文件变化线程"""
|
||||
log("配置监控线程启动")
|
||||
last_check_time = 0
|
||||
check_interval = 1800 # 30分钟
|
||||
|
||||
while True:
|
||||
try:
|
||||
current_time = time.time()
|
||||
|
||||
# 检查是否需要更新配置
|
||||
if current_time - last_check_time >= check_interval:
|
||||
log("开始检查系数配置更新")
|
||||
load_coefficients()
|
||||
last_check_time = current_time
|
||||
|
||||
time.sleep(60) # 每分钟检查一次时间
|
||||
|
||||
except Exception as e:
|
||||
log(f"配置监控线程异常: {str(e)}")
|
||||
time.sleep(60) # 发生异常时等待1分钟后重试
|
||||
|
||||
def send_global_message(message):
|
||||
"""发送全局消息提示"""
|
||||
try:
|
||||
# 将消息写入到全局消息文件
|
||||
message_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'global_messages.json')
|
||||
messages = []
|
||||
if os.path.exists(message_file):
|
||||
with open(message_file, 'r', encoding='utf-8') as f:
|
||||
messages = json.load(f)
|
||||
|
||||
# 添加新消息
|
||||
messages.append({
|
||||
'timestamp': int(time.time()),
|
||||
'message': message,
|
||||
'type': 'error'
|
||||
})
|
||||
|
||||
# 只保留最近100条消息
|
||||
if len(messages) > 100:
|
||||
messages = messages[-100:]
|
||||
|
||||
# 保存消息
|
||||
with open(message_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(messages, f, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
log(f"发送全局消息失败: {str(e)}")
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
logging.info("CC审核平台监控系统启动")
|
||||
|
||||
# 解析命令行参数
|
||||
check_now = False
|
||||
for arg in sys.argv:
|
||||
if arg == "--check-now":
|
||||
check_now = True
|
||||
logging.info("收到立即检查参数")
|
||||
|
||||
# 从环境变量获取凭据
|
||||
username = os.environ.get('INSPECT_USERNAME')
|
||||
cookie = os.environ.get('INSPECT_COOKIE')
|
||||
if not username or not cookie:
|
||||
logging.error("未设置CC审核平台凭据")
|
||||
return
|
||||
|
||||
if check_now:
|
||||
logging.info("开始执行手动检查")
|
||||
update_hourly_stats(username, cookie)
|
||||
logging.info("手动检查完成")
|
||||
sys.exit(0)
|
||||
|
||||
# 启动小时和日数据监控线程
|
||||
def hourly_update_thread():
|
||||
while True:
|
||||
try:
|
||||
update_hourly_stats(username, cookie)
|
||||
logging.info("已完成小时统计数据更新")
|
||||
time.sleep(120)
|
||||
except Exception as e:
|
||||
logging.error(f"小时数据更新线程错误: {str(e)}")
|
||||
time.sleep(60)
|
||||
|
||||
def daily_update_thread():
|
||||
last_daily_check = None
|
||||
while True:
|
||||
try:
|
||||
now = datetime.now()
|
||||
if last_daily_check is None or (now - last_daily_check).total_seconds() >= 3600:
|
||||
update_daily_stats(username, cookie)
|
||||
last_daily_check = now
|
||||
logging.info("已完成日统计数据更新")
|
||||
time.sleep(300)
|
||||
except Exception as e:
|
||||
logging.error(f"日数据更新线程错误: {str(e)}")
|
||||
time.sleep(60)
|
||||
|
||||
hourly_thread = threading.Thread(target=hourly_update_thread)
|
||||
hourly_thread.daemon = True
|
||||
hourly_thread.start()
|
||||
|
||||
daily_thread = threading.Thread(target=daily_update_thread)
|
||||
daily_thread.daemon = True
|
||||
daily_thread.start()
|
||||
|
||||
# 启动配置监控线程
|
||||
config_thread = threading.Thread(target=monitor_config_thread)
|
||||
config_thread.daemon = True
|
||||
config_thread.start()
|
||||
|
||||
# 保持主线程运行
|
||||
try:
|
||||
while True:
|
||||
time.sleep(10)
|
||||
except KeyboardInterrupt:
|
||||
logging.info("程序被用户中断")
|
||||
except Exception as e:
|
||||
logging.error(f"主线程异常: {str(e)}")
|
||||
finally:
|
||||
logging.info("CC审核平台监控系统关闭")
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -150,6 +150,76 @@
|
||||
<p>记录系统各版本的更新内容和修复问题</p>
|
||||
</header>
|
||||
|
||||
<div class="release-item">
|
||||
<div class="release-header">
|
||||
<div class="release-date">2025年4月29日</div>
|
||||
<div class="release-tag">
|
||||
<a href="https://gitea.ui-beam.cn/ui_beam/NetEaseDSMonitor/releases/tag/v20250429213045" target="_blank">v20250429213045</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="release-content">
|
||||
<h5>2025年4月29日更新 (v20250429213045):</h5>
|
||||
<div class="feature">
|
||||
<h4>告警提示机制优化</h4>
|
||||
<ul>
|
||||
<li>将告警提示方式由横幅改为WebSocket实时弹窗提示,实现秒级响应</li>
|
||||
<li>实现网页弹窗与Windows通知同步显示,不再有延迟</li>
|
||||
<li>优化了告警文本的可读性和清晰度</li>
|
||||
<li>新增零值持续告警功能:当检测到连续14分钟获取数值为0时,触发弹窗提醒,直至数据恢复非零状态</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="feature">
|
||||
<h4>数据监控看板样式优化</h4>
|
||||
<ul>
|
||||
<li>实现当前小时"总计(折算量)"数值根据阈值动态变色功能:
|
||||
<ul>
|
||||
<li><200:红色(异常状态)</li>
|
||||
<li>200-682:橙色(警告状态)</li>
|
||||
<li>>682:绿色(达标状态)</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>优化数值展示效果,提升数据感知效率</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="enhancement">
|
||||
<h4>系数配置重构</h4>
|
||||
<ul>
|
||||
<li>改为在线获取系数配置,无需手动修改</li>
|
||||
<li>移除手动配置入口,简化操作流程</li>
|
||||
<li>优化系数加载和应用机制,提高稳定性</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="optimization">
|
||||
<h4>日志与界面优化</h4>
|
||||
<ul>
|
||||
<li>增强日志记录功能,优化日志格式和输出方式</li>
|
||||
<li>简化页面展示,移除冗余的工单总数和总记录数卡片</li>
|
||||
<li>优化数据展示区域,聚焦折算总计和类别数据</li>
|
||||
<li>优化系统状态提示信息,改进错误提示机制</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="enhancement">
|
||||
<h4>自动化与用户体验</h4>
|
||||
<ul>
|
||||
<li>所有监控进程启动时自动最小化窗口,减少界面干扰</li>
|
||||
<li>主控台窗口启动时自动最小化,保持桌面整洁</li>
|
||||
<li>修复网页自动关闭失败的提示方式,改为弹窗提示</li>
|
||||
<li>优化配置文件检查间隔为2分钟,降低系统资源占用</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="bug-fix">
|
||||
<h4>Bug修复</h4>
|
||||
<ul>
|
||||
<li>修复了用户登出时可能未清理共享数据文件的问题</li>
|
||||
<li>修复了多监控进程启动窗口叠加的干扰问题</li>
|
||||
<li>修复了favicon.ico 404错误,调整为正确的图标文件路径</li>
|
||||
<li>修复了静态资源路径问题,确保UI资源正确加载</li>
|
||||
<li>修复了更新小时数据时 inspect_monitor.py 进程未正常结束导致更新失败的问题</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="release-item">
|
||||
<div class="release-header">
|
||||
<div class="release-date">2025年4月22日</div>
|
||||
@ -337,11 +407,11 @@
|
||||
<div class="release-header">
|
||||
<div class="release-date">2025年4月8日</div>
|
||||
<div class="release-tag">
|
||||
<a href="https://gitea.ui-beam.cn/ui_beam/NetEaseDSMonitor/releases/tag/v20250408165207" target="_blank">v20250408165207</a>
|
||||
<a href="https://gitea.ui-beam.cn/ui_beam/NetEaseDSMonitor/releases/tag/v20250410232012" target="_blank">v20250410232012</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="release-content">
|
||||
<h5>2025年4月8日更新 (v20250408165207):</h5>
|
||||
<h5>2025年4月8日更新 (v20250410232012):</h5>
|
||||
<div class="feature">
|
||||
<h4>一键部署功能</h4>
|
||||
<p>添加download_auto_run.py一键安装脚本,自动下载文件、安装依赖并启动系统,简化安装流程</p>
|
||||
@ -382,7 +452,7 @@
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 网易DS监控系统 - 版本更新日志</p>
|
||||
<p>© 2025 网易大神实时审核数据监控看板 - 版本更新日志</p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -2,7 +2,7 @@
|
||||
chcp 65001 >nul
|
||||
cd /d "%~dp0"
|
||||
|
||||
echo 启动网易大神审核数据看板...
|
||||
echo 启动网易大神实时审核数据看板...
|
||||
|
||||
REM 检查Python路径
|
||||
set PYTHON_PATH=C:\Python39\python.exe
|
||||
@ -34,7 +34,7 @@ timeout /t 3 >nul
|
||||
REM 启动监控系统
|
||||
echo [INFO] 正在启动主控制面板 (端口:8000)...
|
||||
cd /d "%~dp0"
|
||||
start "网易大神审核数据监控系统" /b "%PYTHON_PATH%" dashboard.py
|
||||
start "网易大神实时审核数据监控系统" /min "%PYTHON_PATH%" dashboard.py
|
||||
|
||||
REM 等待1秒确保程序启动
|
||||
timeout /t 1 >nul
|
||||
|
@ -4,9 +4,16 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>网易大神审核数据监控看板</title>
|
||||
<title>网易大神实时审核数据监控看板</title>
|
||||
<link rel="icon" href="/static/ds-favicon.ico" type="image/x-icon">
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js" integrity="sha512-eVL5Lb9al9FzgR63gDs1MxcDS2wFu3loYAgjIH0+Hg38tCS8Ag62dwKyH+wzDb+QauDpEZjXbMn11blw8cbTJQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript">
|
||||
(function(c,l,a,r,i,t,y){
|
||||
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
|
||||
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
|
||||
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
|
||||
})(window, document, "clarity", "script", "rb98rvt1la");
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||||
@ -713,13 +720,121 @@
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
/* 移除默认的总计面板样式 */
|
||||
.stats-card.total {
|
||||
background: #fff7e6;
|
||||
border: 1px solid #ffe7ba;
|
||||
background: white; /* 设置默认白色背景 */
|
||||
border: 1px solid #eee;
|
||||
transition: all 0.3s ease; /* 添加过渡效果 */
|
||||
}
|
||||
|
||||
.stats-card.total h3 {
|
||||
color: #d46b08;
|
||||
/* 动态背景色样式 */
|
||||
.stats-card.total.status-red {
|
||||
background-color: #fff1f0 !important;
|
||||
border: 1px solid #ffccc7 !important;
|
||||
}
|
||||
.stats-card.total.status-red h3 {
|
||||
color: #cf1322 !important;
|
||||
}
|
||||
|
||||
.stats-card.total.status-orange {
|
||||
background-color: #fff7e6 !important;
|
||||
border: 1px solid #ffd591 !important;
|
||||
}
|
||||
.stats-card.total.status-orange h3 {
|
||||
color: #d46b08 !important;
|
||||
}
|
||||
|
||||
.stats-card.total.status-green {
|
||||
background-color: #f6ffed !important;
|
||||
border: 1px solid #b7eb8f !important;
|
||||
}
|
||||
.stats-card.total.status-green h3 {
|
||||
color: #52c41a !important;
|
||||
}
|
||||
|
||||
/* 删除系数设置相关的样式 */
|
||||
.settings-dialog {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.settings-content {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.settings-form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.settings-buttons {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.settings-buttons button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
/* 添加颜色样式类 */
|
||||
.status-red {
|
||||
color: #ff4d4f !important;
|
||||
}
|
||||
.status-orange {
|
||||
color: #fa8c16 !important;
|
||||
}
|
||||
.status-green {
|
||||
color: #52c41a !important;
|
||||
}
|
||||
|
||||
/* 告警弹窗样式 */
|
||||
.zero-alert {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #fff1f0;
|
||||
border: 1px solid #ffccc7;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
}
|
||||
.zero-alert .close-btn {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
/* 添加闪烁动画 */
|
||||
@keyframes blink {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
.blink {
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@ -729,19 +844,18 @@
|
||||
|
||||
<div class="header">
|
||||
<div class="header-title">
|
||||
<h1>网易大神审核数据监控看板</h1>
|
||||
<h1>网易大神实时审核数据监控看板</h1>
|
||||
<span id="version-display" class="version-display">加载中...</span>
|
||||
</div>
|
||||
<div class="header-buttons">
|
||||
<button class="current-user">当前登录用户:{{ staff_name }}</button>
|
||||
<!--<button class="current-user">当前登录用户:{{ username }}({{ staff_name }})</button> <!-- 启用工号验证 -->
|
||||
<button class="current-user">当前登录用户:{{ staff_name }}</button> <!-- 禁用工号验证 -->
|
||||
<button class="refresh-button">刷新数据</button>
|
||||
<button class="check-now-button">更新当前小时数据</button>
|
||||
<button class="test-alarm-button">测试告警</button>
|
||||
<button class="restart-button">更新全天数据</button>
|
||||
<button class="check-version-button">检测版本更新</button>
|
||||
<button class="cms-settings-button">CMS系数设置</button>
|
||||
<button class="breeze-settings-button">Breeze系数设置</button>
|
||||
<button id="logout-button">登出</button>
|
||||
<button id="logout-button">退出</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-container">
|
||||
@ -821,7 +935,7 @@
|
||||
|
||||
<div id="alarm-banner" class="alarm-banner">
|
||||
<div class="alarm-message">
|
||||
<span id="alarm-type"></span>:当前小时折算总量已超过阈值<span id="alarm-details"></span>!
|
||||
<span id="alarm-type"></span>:<span id="alarm-message"></span>
|
||||
</div>
|
||||
<button id="reset-alarm" class="alarm-button">知道了</button>
|
||||
</div>
|
||||
@ -835,10 +949,6 @@
|
||||
<div class="panel-body">
|
||||
<div class="data-section">
|
||||
<h3>当前小时数据</h3>
|
||||
<div class="data-card">
|
||||
<div class="value" id="breeze-hourly-count">-</div>
|
||||
<div class="label">工单总数</div>
|
||||
</div>
|
||||
<div class="data-total">
|
||||
<div class="label">折算总计</div>
|
||||
<div class="value" id="breeze-hourly-weighted">-</div>
|
||||
@ -849,10 +959,6 @@
|
||||
</div>
|
||||
<div class="data-section">
|
||||
<h3>今日全天数据</h3>
|
||||
<div class="data-card">
|
||||
<div class="value" id="breeze-daily-count">-</div>
|
||||
<div class="label">工单总数</div>
|
||||
</div>
|
||||
<div class="data-total">
|
||||
<div class="label">折算总计</div>
|
||||
<div class="value" id="breeze-daily-weighted">-</div>
|
||||
@ -888,10 +994,6 @@
|
||||
<div class="label">举报处理</div>
|
||||
<div class="data-coefficient" id="cms-hourly-coefficient-complaint">系数: -</div>
|
||||
</div>
|
||||
<div class="data-card">
|
||||
<div class="value" id="cms-hourly-count">-</div>
|
||||
<div class="label">总记录数</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-total">
|
||||
<div class="label">折算总计</div>
|
||||
@ -916,10 +1018,6 @@
|
||||
<div class="label">举报处理</div>
|
||||
<div class="data-coefficient" id="cms-daily-coefficient-complaint">系数: -</div>
|
||||
</div>
|
||||
<div class="data-card">
|
||||
<div class="value" id="cms-daily-count">-</div>
|
||||
<div class="label">总记录数</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-total">
|
||||
<div class="label">折算总计</div>
|
||||
@ -999,6 +1097,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加零值告警弹窗 -->
|
||||
<div id="zeroAlert" class="zero-alert">
|
||||
<span class="close-btn" onclick="dismissZeroAlert()">×</span>
|
||||
<h3 style="color: #cf1322; margin: 0 0 10px 0">⚠️ 数据异常警告</h3>
|
||||
<p style="margin: 0">检测到数据持续为零,请检查系统运行状态!</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 建立 WebSocket 连接
|
||||
const socket = io();
|
||||
@ -1115,19 +1220,18 @@
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.data.is_alarming) {
|
||||
alarmBanner.classList.add('active');
|
||||
|
||||
// 从API返回数据中获取告警类型
|
||||
// 用alert弹窗提示
|
||||
const alarmType = data.data.alarm_type || "实时告警";
|
||||
document.getElementById('alarm-type').textContent = alarmType;
|
||||
|
||||
// 更新告警详细信息
|
||||
const total = parseFloat(document.getElementById('total-weighted-hourly').textContent);
|
||||
const threshold = data.data.threshold;
|
||||
if (!isNaN(total) && total > 0) {
|
||||
const overPercentage = ((total - threshold) / threshold * 100).toFixed(1);
|
||||
document.getElementById('alarm-details').textContent = ` (当前值:${total},超出${overPercentage}%)`;
|
||||
alert(`${alarmType}:当前值:${total},超出${overPercentage}%`);
|
||||
} else {
|
||||
alert(`${alarmType}:告警已触发`);
|
||||
}
|
||||
// 不再显示横幅
|
||||
alarmBanner.classList.remove('active');
|
||||
} else {
|
||||
alarmBanner.classList.remove('active');
|
||||
}
|
||||
@ -1148,7 +1252,6 @@
|
||||
|
||||
// 更新Breeze工单系统面板
|
||||
if (data.breeze.hourly) {
|
||||
document.getElementById('breeze-hourly-count').textContent = data.breeze.hourly.total || '0';
|
||||
document.getElementById('breeze-hourly-weighted').textContent = data.breeze.hourly.weighted_total ? data.breeze.hourly.weighted_total.toFixed(2) : '0.00';
|
||||
|
||||
// 更新小时类别数据
|
||||
@ -1178,14 +1281,12 @@
|
||||
breezeHourlyCategories.innerHTML = '<div class="loading">暂无可用数据</div>';
|
||||
}
|
||||
} else {
|
||||
document.getElementById('breeze-hourly-count').textContent = '0';
|
||||
document.getElementById('breeze-hourly-weighted').textContent = '0.00';
|
||||
document.getElementById('breeze-hourly-categories').innerHTML = '<div class="loading">暂无可用数据</div>';
|
||||
}
|
||||
|
||||
// 更新日数据
|
||||
if (data.breeze.daily) {
|
||||
document.getElementById('breeze-daily-count').textContent = data.breeze.daily.total || '0';
|
||||
document.getElementById('breeze-daily-weighted').textContent = data.breeze.daily.weighted_total ? data.breeze.daily.weighted_total.toFixed(2) : '0.00';
|
||||
|
||||
// 更新日类别数据
|
||||
@ -1215,7 +1316,6 @@
|
||||
breezeDailyCategories.innerHTML = '<div class="loading">暂无可用数据</div>';
|
||||
}
|
||||
} else {
|
||||
document.getElementById('breeze-daily-count').textContent = '0';
|
||||
document.getElementById('breeze-daily-weighted').textContent = '0.00';
|
||||
document.getElementById('breeze-daily-categories').innerHTML = '<div class="loading">暂无可用数据</div>';
|
||||
}
|
||||
@ -1244,13 +1344,11 @@
|
||||
document.getElementById('cms-hourly-comment').textContent = data.cms.hourly.stats.comment || '0';
|
||||
document.getElementById('cms-hourly-feed').textContent = data.cms.hourly.stats.feed || '0';
|
||||
document.getElementById('cms-hourly-complaint').textContent = data.cms.hourly.stats.complaint || '0';
|
||||
document.getElementById('cms-hourly-count').textContent = data.cms.hourly.total_count || '0';
|
||||
document.getElementById('cms-hourly-weighted').textContent = data.cms.hourly.weighted_total ? data.cms.hourly.weighted_total.toFixed(2) : '0.00';
|
||||
} else {
|
||||
document.getElementById('cms-hourly-comment').textContent = '0';
|
||||
document.getElementById('cms-hourly-feed').textContent = '0';
|
||||
document.getElementById('cms-hourly-complaint').textContent = '0';
|
||||
document.getElementById('cms-hourly-count').textContent = '0';
|
||||
document.getElementById('cms-hourly-weighted').textContent = '0.00';
|
||||
}
|
||||
|
||||
@ -1269,13 +1367,11 @@
|
||||
document.getElementById('cms-daily-comment').textContent = data.cms.daily.stats.comment || '0';
|
||||
document.getElementById('cms-daily-feed').textContent = data.cms.daily.stats.feed || '0';
|
||||
document.getElementById('cms-daily-complaint').textContent = data.cms.daily.stats.complaint || '0';
|
||||
document.getElementById('cms-daily-count').textContent = data.cms.daily.total_count || '0';
|
||||
document.getElementById('cms-daily-weighted').textContent = data.cms.daily.weighted_total ? data.cms.daily.weighted_total.toFixed(2) : '0.00';
|
||||
} else {
|
||||
document.getElementById('cms-daily-comment').textContent = '0';
|
||||
document.getElementById('cms-daily-feed').textContent = '0';
|
||||
document.getElementById('cms-daily-complaint').textContent = '0';
|
||||
document.getElementById('cms-daily-count').textContent = '0';
|
||||
document.getElementById('cms-daily-weighted').textContent = '0.00';
|
||||
}
|
||||
}
|
||||
@ -1368,174 +1464,6 @@
|
||||
'系数: ' + (coefficients.complaint || '-').toFixed(2);
|
||||
}
|
||||
|
||||
// 显示CMS系数设置对话框
|
||||
function showCMSSettingsDialog() {
|
||||
fetch('/api/get-coefficients')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
document.getElementById('cms-coefficient-comment').value = data.data.comment;
|
||||
document.getElementById('cms-coefficient-feed').value = data.data.feed;
|
||||
document.getElementById('cms-coefficient-complaint').value = data.data.complaint;
|
||||
settingsDialog.style.display = 'block';
|
||||
} else {
|
||||
alert('获取系数失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('获取系数出错:', error);
|
||||
alert('获取系数出错');
|
||||
});
|
||||
}
|
||||
|
||||
// 显示Breeze系数设置对话框
|
||||
function showBreezeSettingsDialog() {
|
||||
fetch('/api/get-breeze-coefficients')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const breezeSettingsForm = document.getElementById('breeze-settings-form');
|
||||
|
||||
// 清空现有内容
|
||||
breezeSettingsForm.innerHTML = '';
|
||||
|
||||
// 为每个系数创建输入字段
|
||||
const coefficients = data.data;
|
||||
const chineseNames = {
|
||||
'NTES_GOD_IMAGES': '网易大神APP图片',
|
||||
'NTES_GOD_VIDEOS': '网易大神APP视频',
|
||||
'NTES_GOD_CHAT_IMAGES': '网易大神APP聊天图片',
|
||||
'NTES_GOD_CHAT_VIDEOS': '网易大神APP聊天视频',
|
||||
'NTES_DASONG': '大神大宋视频',
|
||||
'SPIDER_VIDEO': '大神普通供给视频',
|
||||
'SPIDER_VIDEO_SP': '大神高优供给视频',
|
||||
'NTES_GOD_AI': '大神AI图片',
|
||||
'NTES_GOD_TOP': '大神短视频',
|
||||
'T_SPIDER_VIDEO': '大神tiktok普通视频',
|
||||
'T_SPIDER_VIDEO_SP': '大神tiktok高优视频',
|
||||
'V_SPIDER_VIDEO': '大神ins普通供给视频',
|
||||
'V_SPIDER_VIDEO_SP': '大神ins高优供给视频',
|
||||
'NTES_GOD_XHS': '大神小红书图片',
|
||||
'XHS_SPIDER_VIDEO': '小红书供给视频',
|
||||
'Cupid': '大神交友',
|
||||
'CHAT_P2P': '大神聊天/风险用户_私聊/私聊频繁',
|
||||
'CHAT_TEAM': '大神聊天/风险用户_群聊/群聊频繁',
|
||||
'CHAT_ROOM': '大神聊天_聊天室',
|
||||
'CHAT_ROOM_MSG': '风险用户_聊天室频繁'
|
||||
};
|
||||
|
||||
// 创建搜索框
|
||||
const searchDiv = document.createElement('div');
|
||||
searchDiv.className = 'form-group search-group';
|
||||
searchDiv.innerHTML = `
|
||||
<label for="breeze-search">搜索系数:</label>
|
||||
<input type="text" id="breeze-search" placeholder="输入关键词搜索系数" />
|
||||
`;
|
||||
breezeSettingsForm.appendChild(searchDiv);
|
||||
|
||||
// 创建表单内容容器
|
||||
const formContentDiv = document.createElement('div');
|
||||
formContentDiv.className = 'form-content';
|
||||
breezeSettingsForm.appendChild(formContentDiv);
|
||||
|
||||
// 为每个系数创建输入字段
|
||||
for (const [key, value] of Object.entries(coefficients)) {
|
||||
const formGroup = document.createElement('div');
|
||||
formGroup.className = 'form-group';
|
||||
formGroup.dataset.name = key;
|
||||
|
||||
const label = document.createElement('label');
|
||||
label.htmlFor = `breeze-coefficient-${key}`;
|
||||
label.textContent = chineseNames[key] || key;
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.type = 'number';
|
||||
input.id = `breeze-coefficient-${key}`;
|
||||
input.className = 'breeze-coefficient';
|
||||
input.dataset.key = key;
|
||||
input.step = '0.01';
|
||||
input.min = '0';
|
||||
input.max = '200';
|
||||
input.value = value;
|
||||
|
||||
formGroup.appendChild(label);
|
||||
formGroup.appendChild(input);
|
||||
formContentDiv.appendChild(formGroup);
|
||||
}
|
||||
|
||||
// 添加搜索功能
|
||||
const searchInput = document.getElementById('breeze-search');
|
||||
searchInput.addEventListener('input', function () {
|
||||
const searchText = this.value.toLowerCase();
|
||||
const formGroups = formContentDiv.querySelectorAll('.form-group');
|
||||
|
||||
formGroups.forEach(group => {
|
||||
const key = group.dataset.name;
|
||||
const label = group.querySelector('label').textContent.toLowerCase();
|
||||
|
||||
if (key && key.toLowerCase().includes(searchText) || label.includes(searchText)) {
|
||||
group.style.display = '';
|
||||
} else {
|
||||
group.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 添加保存按钮
|
||||
const saveButton = document.createElement('button');
|
||||
saveButton.id = 'save-breeze-settings-button';
|
||||
saveButton.textContent = '保存';
|
||||
saveButton.addEventListener('click', saveBreezeCoefficients);
|
||||
breezeSettingsForm.appendChild(saveButton);
|
||||
|
||||
// 显示对话框
|
||||
breezeSettingsDialog.style.display = 'block';
|
||||
} else {
|
||||
alert('获取Breeze系数失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('获取Breeze系数出错:', error);
|
||||
alert('获取Breeze系数出错');
|
||||
});
|
||||
}
|
||||
|
||||
// 保存Breeze系数设置
|
||||
function saveBreezeCoefficients() {
|
||||
const coefficientInputs = document.querySelectorAll('.breeze-coefficient');
|
||||
const newCoefficients = {};
|
||||
|
||||
coefficientInputs.forEach(input => {
|
||||
if (input.value) {
|
||||
newCoefficients[input.dataset.key] = parseFloat(input.value);
|
||||
}
|
||||
});
|
||||
|
||||
fetch('/api/update-breeze-coefficients', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(newCoefficients)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('Breeze系数更新成功');
|
||||
breezeSettingsDialog.style.display = 'none';
|
||||
|
||||
// 刷新数据
|
||||
setTimeout(fetchStats, 2000);
|
||||
} else {
|
||||
alert('更新Breeze系数失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('更新Breeze系数出错:', error);
|
||||
alert('更新Breeze系数出错');
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定按钮事件
|
||||
function bindEvents() {
|
||||
// 绑定刷新数据按钮事件
|
||||
@ -1553,15 +1481,9 @@
|
||||
// 绑定版本检测更新按钮事件
|
||||
document.querySelector('.check-version-button').addEventListener('click', checkVersion);
|
||||
|
||||
// 绑定CMS系数设置按钮事件
|
||||
document.querySelector('.cms-settings-button').addEventListener('click', showCMSSettingsDialog);
|
||||
|
||||
// 绑定Breeze系数设置按钮事件
|
||||
document.querySelector('.breeze-settings-button').addEventListener('click', showBreezeSettingsDialog);
|
||||
|
||||
// 绑定登出按钮事件
|
||||
document.getElementById('logout-button').addEventListener('click', function () {
|
||||
if (confirm('确认要登出吗?')) {
|
||||
if (confirm('确认要退出吗?')) {
|
||||
window.location.href = '/logout';
|
||||
}
|
||||
});
|
||||
@ -1993,12 +1915,11 @@
|
||||
|
||||
function updateStats(data) {
|
||||
try {
|
||||
// 更新统计栏数据
|
||||
// 更新清风审核数据
|
||||
if (data.breeze && data.breeze.hourly) {
|
||||
document.getElementById('breeze-total').textContent = data.breeze.hourly.total || '0';
|
||||
document.getElementById('breeze-daily-total').textContent = data.breeze.daily ? (data.breeze.daily.total || '0') : '0';
|
||||
|
||||
// 更新时间戳
|
||||
if (data.breeze.hourly_update) {
|
||||
document.getElementById('breeze-hourly-time').textContent = data.breeze.hourly_update;
|
||||
}
|
||||
@ -2009,12 +1930,10 @@
|
||||
|
||||
// 更新CMS数据
|
||||
if (data.cms && data.cms.hourly) {
|
||||
// 更新顶部统计栏
|
||||
const cmsTotal = data.cms.hourly.total_count || 0;
|
||||
document.getElementById('cms-total').textContent = cmsTotal;
|
||||
document.getElementById('cms-daily-total').textContent = data.cms.daily ? (data.cms.daily.total_count || '0') : '0';
|
||||
|
||||
// 更新时间戳
|
||||
if (data.cms.hourly_update) {
|
||||
document.getElementById('cms-hourly-time').textContent = data.cms.hourly_update;
|
||||
}
|
||||
@ -2034,7 +1953,6 @@
|
||||
document.getElementById('inspect-daily-weighted').textContent = `(${Math.round(data.inspect.daily.weighted_total)})`;
|
||||
}
|
||||
|
||||
// 更新时间戳
|
||||
if (data.inspect.hourly_update) {
|
||||
document.getElementById('inspect-hourly-time').textContent = data.inspect.hourly_update;
|
||||
}
|
||||
@ -2048,7 +1966,10 @@
|
||||
document.getElementById('total-weighted-hourly').textContent = Math.round(data.total.hourly);
|
||||
document.getElementById('total-weighted-daily').textContent = Math.round(data.total.daily);
|
||||
|
||||
// 获取最新的时间戳
|
||||
// 立即更新总计面板颜色
|
||||
updateTotalCardColor(Math.round(data.total.hourly));
|
||||
|
||||
// 更新时间戳
|
||||
const hourlyUpdateTime = getLatestTimestamp([
|
||||
data.breeze?.hourly_update,
|
||||
data.cms?.hourly_update,
|
||||
@ -2061,7 +1982,6 @@
|
||||
data.inspect?.daily_update
|
||||
]);
|
||||
|
||||
// 更新时间戳显示
|
||||
if (hourlyUpdateTime) {
|
||||
document.getElementById('total-hourly-time').textContent = hourlyUpdateTime;
|
||||
}
|
||||
@ -2092,6 +2012,109 @@
|
||||
return new Date(current) > new Date(latest) ? current : latest;
|
||||
}, null);
|
||||
}
|
||||
|
||||
// 添加颜色判断函数
|
||||
function updateWeightedTotalColor(value) {
|
||||
const element = document.getElementById('weighted-total');
|
||||
if (!element) return;
|
||||
|
||||
// 移除现有的状态类
|
||||
element.classList.remove('status-red', 'status-orange', 'status-green');
|
||||
|
||||
// 根据阈值添加对应的颜色类
|
||||
if (value < 200) {
|
||||
element.classList.add('status-red');
|
||||
} else if (value <= 682) {
|
||||
element.classList.add('status-orange');
|
||||
} else {
|
||||
element.classList.add('status-green');
|
||||
}
|
||||
}
|
||||
|
||||
// 零值检测相关变量
|
||||
let zeroValueStartTime = null;
|
||||
let zeroAlertShown = false;
|
||||
|
||||
// 显示零值告警
|
||||
function showZeroAlert() {
|
||||
if (!zeroAlertShown) {
|
||||
const alarmBanner = document.getElementById('alarm-banner');
|
||||
const alarmType = document.getElementById('alarm-type');
|
||||
const alarmMessage = document.getElementById('alarm-message');
|
||||
|
||||
alarmType.textContent = "断审预警";
|
||||
alarmMessage.textContent = "已连续14分钟未产生审核记录!再过1分钟将记为一次断审违纪,每天累计两次将被记为违规。请立即处理!";
|
||||
alarmBanner.classList.add('active');
|
||||
zeroAlertShown = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭零值告警
|
||||
function dismissZeroAlert() {
|
||||
const alarmBanner = document.getElementById('alarm-banner');
|
||||
alarmBanner.classList.remove('active');
|
||||
zeroAlertShown = false;
|
||||
}
|
||||
|
||||
// 移除单独的零值告警弹窗
|
||||
function checkZeroValue(value) {
|
||||
const now = new Date();
|
||||
|
||||
if (value === 0) {
|
||||
if (!zeroValueStartTime) {
|
||||
zeroValueStartTime = now;
|
||||
} else {
|
||||
const duration = (now - zeroValueStartTime) / (1000 * 60); // 转换为分钟
|
||||
if (duration >= 14) {
|
||||
showZeroAlert();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果值不为零,重置计时器并关闭告警
|
||||
zeroValueStartTime = null;
|
||||
if (zeroAlertShown) {
|
||||
dismissZeroAlert();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新总计面板的颜色
|
||||
function updateTotalCardColor(value) {
|
||||
const totalCard = document.querySelector('.stats-card.total');
|
||||
if (!totalCard) return;
|
||||
|
||||
// 移除现有的状态类
|
||||
totalCard.classList.remove('status-red', 'status-orange', 'status-green');
|
||||
|
||||
// 根据阈值添加对应的颜色类
|
||||
if (value < 200) {
|
||||
totalCard.classList.add('status-red');
|
||||
} else if (value <= 682) {
|
||||
totalCard.classList.add('status-orange');
|
||||
} else {
|
||||
totalCard.classList.add('status-green');
|
||||
}
|
||||
}
|
||||
|
||||
// 确保在页面加载完成后立即更新一次颜色
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const hourlyTotal = parseInt(document.getElementById('total-weighted-hourly').textContent) || 0;
|
||||
updateTotalCardColor(hourlyTotal);
|
||||
});
|
||||
|
||||
// 添加定时检查
|
||||
setInterval(function() {
|
||||
const hourlyTotal = parseInt(document.getElementById('total-weighted-hourly').textContent) || 0;
|
||||
console.log('定时检查,当前值:', hourlyTotal); // 添加调试日志
|
||||
updateTotalCardColor(hourlyTotal);
|
||||
}, 5000); // 每5秒检查一次
|
||||
|
||||
// WebSocket告警推送
|
||||
socket.on('alarm', function(data) {
|
||||
if (data && data.message) {
|
||||
alert(data.message);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>网易大神审核数据监控看板 - 登录</title>
|
||||
<title>网易大神实时审核数据监控看板 - 登录</title>
|
||||
<link rel="icon" href="/static/ds-favicon.ico" type="image/x-icon">
|
||||
<style>
|
||||
:root {
|
||||
@ -538,7 +538,7 @@
|
||||
<div id="messageContainer" class="message-container"></div>
|
||||
<div class="login-container">
|
||||
<div class="login-banner">
|
||||
<h1>网易大神审核数据监控看板</h1>
|
||||
<h1>网易大神实时审核数据监控看板</h1>
|
||||
<ul class="features">
|
||||
<li>实时监控审核数据,自动统计工作量</li>
|
||||
<li>多系统数据整合,一目了然</li>
|
||||
@ -552,7 +552,7 @@
|
||||
<form id="loginForm">
|
||||
<div class="form-group">
|
||||
<label>工号</label>
|
||||
<input type="text" name="username" placeholder="请输入您的工号" required>
|
||||
<input type="text" name="username" placeholder="请输入您的工号" required oninput="this.value = this.value.toUpperCase()">
|
||||
<div style="color: #ff4d4f; font-size: 12px; margin-top: 5px;">
|
||||
必填项
|
||||
</div>
|
||||
@ -667,5 +667,13 @@
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function(c,l,a,r,i,t,y){
|
||||
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
|
||||
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
|
||||
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
|
||||
})(window, document, "clarity", "script", "rb98rvt1la");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user