feat: 日志解析时增加进度条展示
This commit is contained in:
parent
c6d3d57358
commit
40f4ed22cf
@ -33,13 +33,15 @@
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="textBrowser_console">
|
||||
<property name="markdown">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:18pt; font-weight:600;">通过文件上传一键日志压缩包来开始</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:18pt; font-weight:600;">或者将日志压缩包拖入程序</span></p></body></html></string>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@ -28,6 +28,7 @@ class Ui_MainWindow(object):
|
||||
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.tab_console)
|
||||
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
||||
self.textBrowser_console = QtWidgets.QTextBrowser(self.tab_console)
|
||||
self.textBrowser_console.setMarkdown("")
|
||||
self.textBrowser_console.setObjectName("textBrowser_console")
|
||||
self.horizontalLayout_4.addWidget(self.textBrowser_console)
|
||||
self.tabWidget.addTab(self.tab_console, "")
|
||||
@ -102,8 +103,7 @@ class Ui_MainWindow(object):
|
||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
||||
"p, li { white-space: pre-wrap; }\n"
|
||||
"</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:18pt; font-weight:600;\">通过文件上传一键日志压缩包来开始</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:18pt; font-weight:600;\">或者将日志压缩包拖入程序</span></p></body></html>"))
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_console), _translate("MainWindow", "控制台"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_baseinfo), _translate("MainWindow", "基本信息"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_alert), _translate("MainWindow", "关键告警"))
|
||||
|
||||
40
src/background_task.py
Normal file
40
src/background_task.py
Normal file
@ -0,0 +1,40 @@
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
import service
|
||||
|
||||
class DiagnoseThread(QThread):
|
||||
"""后台线程,用于执行耗时的诊断任务"""
|
||||
# 定义信号:更新进度(值, 消息)、任务完成(是否成功, 消息)
|
||||
progress_updated = pyqtSignal(int, str)
|
||||
task_completed = pyqtSignal(bool, str)
|
||||
|
||||
def __init__(self, parse_status, file_path):
|
||||
super().__init__()
|
||||
self.parse_status = parse_status
|
||||
self.file_path = file_path
|
||||
self.is_running = True
|
||||
|
||||
def run(self):
|
||||
"""线程执行函数:执行耗时任务"""
|
||||
try:
|
||||
self.progress_updated.emit(1, "正在初始化解析...")
|
||||
|
||||
# 执行耗时任务
|
||||
service.start_diagnose(self.parse_status, self.file_path, progress_callback=self.update_progress)
|
||||
|
||||
# 确保最终进度为100%
|
||||
self.progress_updated.emit(100, "处理完成")
|
||||
self.task_completed.emit(True, "日志解析任务已完成")
|
||||
except Exception as e:
|
||||
# 出错时也允许关闭对话框
|
||||
self.progress_updated.emit(100, f"处理失败:{str(e)}")
|
||||
self.task_completed.emit(False, f"处理失败:{str(e)}")
|
||||
|
||||
def update_progress(self, value, message):
|
||||
"""接收service层的进度更新"""
|
||||
if 0 <= value <= 100 and self.is_running:
|
||||
self.progress_updated.emit(value, message)
|
||||
|
||||
def stop(self):
|
||||
"""停止线程"""
|
||||
self.is_running = False
|
||||
self.wait()
|
||||
@ -1,77 +1,119 @@
|
||||
import time
|
||||
import os
|
||||
import service
|
||||
from utils import show_error_message, show_critical_message
|
||||
from utils import show_error_message, show_critical_message, show_info_message
|
||||
from progress_diaglog import ProgressDialog
|
||||
from background_task import DiagnoseThread
|
||||
|
||||
class FileProcessor:
|
||||
def __init__(self, main_window):
|
||||
self.main_window = main_window # 持有主窗口引用
|
||||
self.parse_status = main_window.parse_status # 服务状态
|
||||
self.view_renderer = main_window.view_renderer # 关联视图渲染模块
|
||||
self.main_window = main_window
|
||||
self.parse_status = main_window.parse_status
|
||||
self.view_renderer = main_window.view_renderer
|
||||
self.last_processed_path = None
|
||||
self.last_processed_time = 0
|
||||
self.diagnose_thread = None # 保存后台线程引用
|
||||
|
||||
def process_uploaded_file(self, file_path):
|
||||
# 防重复处理
|
||||
current_time = time.time()
|
||||
if (file_path == self.last_processed_path and
|
||||
current_time - self.last_processed_time < 1):
|
||||
print(f"跳过重复处理:{file_path}")
|
||||
return
|
||||
|
||||
self.last_processed_path = file_path
|
||||
self.last_processed_time = current_time
|
||||
|
||||
# 格式校验
|
||||
if not self.is_valid_file_format(file_path):
|
||||
show_error_message(self.main_window, file_path)
|
||||
return
|
||||
|
||||
try:
|
||||
# 显示文件信息
|
||||
file_name = os.path.basename(file_path)
|
||||
file_size = os.path.getsize(file_path) / 1024
|
||||
info = (
|
||||
f"已上传文件:\n"
|
||||
f"文件名:{file_name}\n"
|
||||
f"路径:{file_path}\n"
|
||||
f"大小:{file_size:.2f} KB\n"
|
||||
f"-------------------------------------------" + "\n"
|
||||
)
|
||||
self.main_window.textBrowser_console.insertPlainText(info)
|
||||
|
||||
# 初始化进度对话框
|
||||
self.progress_dialog = ProgressDialog(
|
||||
parent=self.main_window,
|
||||
title="正在处理文件",
|
||||
label_text="准备开始处理..."
|
||||
)
|
||||
|
||||
# 创建并配置后台线程
|
||||
self.diagnose_thread = DiagnoseThread(self.parse_status, file_path)
|
||||
self.diagnose_thread.progress_updated.connect(self.progress_dialog.update_progress)
|
||||
self.diagnose_thread.task_completed.connect(self.on_diagnose_completed)
|
||||
|
||||
# 显示进度条并启动线程
|
||||
self.progress_dialog.show()
|
||||
self.diagnose_thread.start()
|
||||
|
||||
except Exception as e:
|
||||
show_critical_message(self.main_window, "处理失败", f"文件处理出错:{str(e)}")
|
||||
|
||||
def on_diagnose_completed(self, success, message):
|
||||
"""处理诊断任务完成后的逻辑"""
|
||||
if hasattr(self, 'progress_dialog') and self.progress_dialog:
|
||||
# 明确允许对话框关闭
|
||||
self.progress_dialog.set_allow_close(True)
|
||||
# 关闭对话框
|
||||
self.progress_dialog.close()
|
||||
# 释放引用
|
||||
self.progress_dialog = None
|
||||
|
||||
# 显示结果信息
|
||||
self.main_window.textBrowser_console.insertPlainText(f"{message}\n")
|
||||
|
||||
if success:
|
||||
# 处理成功,更新视图
|
||||
self._update_view_after_parse()
|
||||
show_info_message(self.main_window, "成功", "文件解析完成")
|
||||
else:
|
||||
# 处理失败,显示错误
|
||||
show_critical_message(self.main_window, "失败", message)
|
||||
|
||||
# 清理线程引用
|
||||
self.diagnose_thread = None
|
||||
|
||||
# 其他原有方法保持不变...
|
||||
def is_valid_file_format(self, file_path):
|
||||
"""校验文件是否为 .tar.gz 格式"""
|
||||
# 原有实现...
|
||||
_, ext = os.path.splitext(file_path)
|
||||
if ext.lower() == '.gz':
|
||||
base, ext2 = os.path.splitext(os.path.splitext(file_path)[0])
|
||||
return ext2.lower() == '.tar'
|
||||
return False
|
||||
|
||||
def get_sensorhistory_path(self, key):
|
||||
"""调用服务层获取传感器历史图片路径"""
|
||||
return service.get_sensorhistory_path(key)
|
||||
|
||||
def process_uploaded_file(self, file_path):
|
||||
"""核心:处理上传的文件(校验→解析→传递结果)"""
|
||||
# 1. 格式校验
|
||||
if not self.is_valid_file_format(file_path):
|
||||
show_error_message(self.main_window, file_path)
|
||||
return
|
||||
|
||||
try:
|
||||
# 2. 提取文件信息并显示到控制台
|
||||
file_name = os.path.basename(file_path)
|
||||
file_size = os.path.getsize(file_path) / 1024 # 转换为 KB
|
||||
info = (
|
||||
f"已上传文件:\n"
|
||||
f"文件名:{file_name}\n"
|
||||
f"路径:{file_path}\n"
|
||||
f"大小:{file_size:.2f} KB\n"
|
||||
f"------------------------------------------------------"+ "\n"
|
||||
)
|
||||
self.main_window.textBrowser_console.insertPlainText(info)
|
||||
|
||||
# 3. 调用服务层解析文件
|
||||
service.send_log_to_cache(file_path)
|
||||
service.start_diagnose(self.parse_status)
|
||||
|
||||
# 4. 根据解析状态更新视图
|
||||
self._update_view_after_parse()
|
||||
|
||||
self.main_window.textBrowser_console.insertPlainText("完成文件解析\n")
|
||||
|
||||
except Exception as e:
|
||||
show_critical_message(self.main_window, "处理失败", f"文件处理出错:{str(e)}")
|
||||
|
||||
def _update_view_after_parse(self):
|
||||
"""解析完成后更新各视图组件"""
|
||||
# 更新基础信息文本框
|
||||
if self.parse_status.baseinfo_status:
|
||||
baseinfo_str = service.get_baseinfo_str()
|
||||
self.main_window.textBrowser_info.insertPlainText(baseinfo_str)
|
||||
|
||||
# 更新传感器图片
|
||||
if self.parse_status.sensorhistory_status:
|
||||
self.view_renderer.display_pic(
|
||||
self.get_sensorhistory_path("all"),
|
||||
self.parse_status.diag_complete_status
|
||||
)
|
||||
|
||||
# 更新告警表格
|
||||
if self.parse_status.parseidl_status and not service.is_idl_alert_empty():
|
||||
alert_json = service.get_idl_alert_json()
|
||||
self.view_renderer.fill_tableView_alert(alert_json)
|
||||
|
||||
# 更新时间线
|
||||
if self.parse_status.eventline_status:
|
||||
event_json = service.get_timeline_event_json()
|
||||
self.main_window.timeline_content.load_events_from_json(event_json)
|
||||
|
||||
def get_sensorhistory_path(self, key):
|
||||
return service.get_sensorhistory_path(key)
|
||||
|
||||
@ -15,7 +15,7 @@ if __name__ == "__main__":
|
||||
pass # 非Windows系统忽略
|
||||
|
||||
# 初始化服务缓存
|
||||
service.app_cache_init()
|
||||
# service.app_cache_init()
|
||||
# 创建PyQt应用实例
|
||||
app = QApplication(sys.argv)
|
||||
# 获取文件系统中存放的icon
|
||||
|
||||
@ -25,6 +25,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||
"""统一执行所有模块的初始化"""
|
||||
# UI初始化(样式、图形视图、表格模型、时间线)
|
||||
self.ui_init.init_ui()
|
||||
self.ui_init.init_textbrower_console_style()
|
||||
self.ui_init.init_graphic_views()
|
||||
self.ui_init.init_textbrowser_style()
|
||||
self.ui_init.init_tableView_alert_model()
|
||||
|
||||
46
src/progress_diaglog.py
Normal file
46
src/progress_diaglog.py
Normal file
@ -0,0 +1,46 @@
|
||||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QProgressBar, QLabel
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
|
||||
class ProgressDialog(QDialog):
|
||||
"""进度条对话框,支持程序控制自动关闭"""
|
||||
def __init__(self, parent=None, title="处理中", label_text="正在处理,请稍候..."):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle(title)
|
||||
self.setModal(True) # 模态对话框
|
||||
self.setFixedSize(400, 120)
|
||||
self.allow_close = False # 新增:允许关闭标记
|
||||
|
||||
# 布局
|
||||
layout = QVBoxLayout()
|
||||
|
||||
# 提示文本
|
||||
self.label = QLabel(label_text)
|
||||
layout.addWidget(self.label)
|
||||
|
||||
# 进度条
|
||||
self.progress_bar = QProgressBar()
|
||||
self.progress_bar.setRange(0, 100)
|
||||
self.progress_bar.setValue(0)
|
||||
layout.addWidget(self.progress_bar)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def update_progress(self, value, message=None):
|
||||
"""更新进度值和提示信息"""
|
||||
self.progress_bar.setValue(value)
|
||||
if message:
|
||||
self.label.setText(message)
|
||||
# 当进度完成时,允许关闭
|
||||
if value >= 100:
|
||||
self.allow_close = True
|
||||
|
||||
def set_allow_close(self, allow):
|
||||
"""设置是否允许关闭对话框"""
|
||||
self.allow_close = allow
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""根据允许关闭标记决定是否关闭"""
|
||||
if self.allow_close:
|
||||
event.accept() # 允许关闭
|
||||
else:
|
||||
event.ignore() # 禁止关闭
|
||||
@ -76,18 +76,44 @@ def is_idl_alert_empty():
|
||||
def get_timeline_event_json():
|
||||
return zijin_event.get_event_json()
|
||||
|
||||
def start_diagnose(parseStatus):
|
||||
def start_diagnose(parseStatus, filepath, progress_callback=None):
|
||||
"""
|
||||
执行诊断任务,添加进度回调
|
||||
:param progress_callback: 进度回调函数,接收(value, message)参数
|
||||
"""
|
||||
try:
|
||||
if progress_callback:
|
||||
progress_callback(10, "正在初始化应用cache...")
|
||||
app_cache_init()
|
||||
|
||||
if progress_callback:
|
||||
progress_callback(20, "正在解压日志...")
|
||||
send_log_to_cache(filepath)
|
||||
|
||||
if progress_callback:
|
||||
progress_callback(30, "正在解析Sensor历史数据信息...")
|
||||
result_sensorhistory = sensorparse.program_main()
|
||||
parseStatus.set_sensorhistory_status(result_sensorhistory)
|
||||
|
||||
if progress_callback:
|
||||
progress_callback(50, "正在解析基础信息...")
|
||||
result_baseinfo = baseinfo.program_main()
|
||||
parseStatus.set_baseinfo_status(result_baseinfo)
|
||||
|
||||
if progress_callback:
|
||||
progress_callback(80, "正在解析告警信息...")
|
||||
result_parseidl = parseidl.program_main()
|
||||
parseStatus.set_parseidl_status(result_parseidl)
|
||||
|
||||
if progress_callback:
|
||||
progress_callback(95, "正在生成时间线...")
|
||||
result_eventline = zijin_event.program_main()
|
||||
parseStatus.set_eventline_status(result_eventline)
|
||||
|
||||
# 完成文件解析后将 diag_complete_status 置位
|
||||
parseStatus.diag_complete_status = True
|
||||
|
||||
except Exception as e:
|
||||
if progress_callback:
|
||||
progress_callback(-1, f"处理出错:{str(e)}")
|
||||
raise e
|
||||
@ -42,6 +42,21 @@ class UIInitializer:
|
||||
}
|
||||
""")
|
||||
|
||||
def init_textbrower_console_style(self):
|
||||
self.main_window.textBrowser_console.setStyleSheet("""
|
||||
QTextBrowser {
|
||||
font-family: 'SimHei';
|
||||
font-size: 20px;
|
||||
color: #2c3e50;
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
}
|
||||
""")
|
||||
message = "从文件打开日志压缩包或将压缩包拖入该窗口\n"
|
||||
self.main_window.textBrowser_console.insertPlainText(f"{message}\n")
|
||||
|
||||
def init_graphic_views(self):
|
||||
"""初始化图形视图(抗锯齿、场景绑定)"""
|
||||
# 创建图形场景
|
||||
|
||||
Loading…
Reference in New Issue
Block a user