1
1
mirror of https://github.com/KenanZhu/AutoLibrary.git synced 2026-06-18 23:43:02 +08:00

Compare commits

..

4 Commits

Author SHA1 Message Date
KenanZhu 577c651ef8 feat(ALMainWindow): 引入对新增定时器任务状态 - 执行失败的处理支持 (#18ae949)
同时,为了统一消息处理,我们将 ALMainWorkers 中的原信号
槽处理的消息逻辑更改为使用继承的 MsgBase 类的 showTrace 方法
2025-12-13 14:27:46 +08:00
KenanZhu 18ae949900 feat(ALTimerTaskWidget): 新增定时器任务状态 - 执行失败 2025-12-13 14:22:28 +08:00
KenanZhu ca9059d1db refactor(AutoLib): 初始化 AutoLib 时,发生错误则抛出异常 2025-12-13 14:21:26 +08:00
KenanZhu ad4deae0c6 fix(ALMainWindow): 修复停止时的按钮状态重置问题
函数更改于(#9255eec)
2025-12-13 14:15:28 +08:00
7 changed files with 113 additions and 74 deletions
+2 -2
View File
@@ -29,7 +29,7 @@ class MsgBase:
msg: str msg: str
): ):
self._output_queue.put(f"[{self._class_name:<12}] >>> : {msg}") self._output_queue.put(f"[{self._class_name:<15}] >>> : {msg}")
def _showTrace( def _showTrace(
@@ -38,7 +38,7 @@ class MsgBase:
): ):
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self._output_queue.put(f"{timestamp}-[{self._class_name:<12}] : {msg}") self._output_queue.put(f"{timestamp}-[{self._class_name:<15}] : {msg}")
def _waitMsg( def _waitMsg(
+1
View File
@@ -36,6 +36,7 @@ class TimerTaskStatus(Enum):
READY = "已就绪" READY = "已就绪"
RUNNING = "执行中" RUNNING = "执行中"
EXECUTED = "已执行" EXECUTED = "已执行"
ERROR = "执行失败"
OUTDATED = "已过期" OUTDATED = "已过期"
+17 -17
View File
@@ -38,6 +38,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
timerTaskIsRunning = Signal(dict) timerTaskIsRunning = Signal(dict)
timerTaskIsExecuted = Signal(dict) timerTaskIsExecuted = Signal(dict)
timerTaskIsError = Signal(dict)
def __init__( def __init__(
self self
@@ -84,6 +85,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.__alTimerTaskWidget = ALTimerTaskWidget(self, self.__config_paths["timer_task"]) self.__alTimerTaskWidget = ALTimerTaskWidget(self, self.__config_paths["timer_task"])
self.timerTaskIsRunning.connect(self.__alTimerTaskWidget.onTimerTaskIsRunning) self.timerTaskIsRunning.connect(self.__alTimerTaskWidget.onTimerTaskIsRunning)
self.timerTaskIsExecuted.connect(self.__alTimerTaskWidget.onTimerTaskIsExecuted) self.timerTaskIsExecuted.connect(self.__alTimerTaskWidget.onTimerTaskIsExecuted)
self.timerTaskIsError.connect(self.__alTimerTaskWidget.onTimerTaskIsError)
self.__alTimerTaskWidget.timerTaskIsReady.connect(self.onTimerTaskIsReady) self.__alTimerTaskWidget.timerTaskIsReady.connect(self.onTimerTaskIsReady)
self.__alTimerTaskWidget.timerTaskWidgetClosed.connect(self.onTimerTaskWidgetClosed) self.__alTimerTaskWidget.timerTaskWidgetClosed.connect(self.onTimerTaskWidgetClosed)
self.__alTimerTaskWidget.setWindowFlags(Qt.WindowType.Window|Qt.WindowType.WindowCloseButtonHint) self.__alTimerTaskWidget.setWindowFlags(Qt.WindowType.Window|Qt.WindowType.WindowCloseButtonHint)
@@ -229,7 +231,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.timerTaskIsRunning.emit(timer_task) self.timerTaskIsRunning.emit(timer_task)
self.__timer_task_timer.stop() self.__timer_task_timer.stop()
self.__is_running_timer_task = True self.__is_running_timer_task = True
self.setControlButtons(False, False, True) self.setControlButtons(True, True, False)
if not timer_task["silent"]: if not timer_task["silent"]:
self.TrayIcon.showMessage( self.TrayIcon.showMessage(
"定时任务 - AutoLibrary", "定时任务 - AutoLibrary",
@@ -245,8 +247,6 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.__config_paths self.__config_paths
) )
self.__current_timer_task_thread.finishedSignal_TimerWorker.connect(self.onTimerTaskFinished) self.__current_timer_task_thread.finishedSignal_TimerWorker.connect(self.onTimerTaskFinished)
self.__current_timer_task_thread.showTraceSignal.connect(self.showTrace)
self.__current_timer_task_thread.showMsgSignal.connect(self.showMsg)
self.__current_timer_task_thread.start() self.__current_timer_task_thread.start()
except queue.Empty: except queue.Empty:
self.__is_running_timer_task = False self.__is_running_timer_task = False
@@ -270,7 +270,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
msg: str msg: str
): ):
self.appendToTextEdit(f"[{self.__class_name:<12}] >>> : {msg}") self.__output_queue.put(f"[{self.__class_name:<15}] >>> : {msg}")
@Slot() @Slot()
def showTrace( def showTrace(
@@ -279,7 +279,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
): ):
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self.appendToTextEdit(f"{timestamp}-[{self.__class_name:<12}] : {msg}") self.__output_queue.put(f"{timestamp}-[{self.__class_name:<15}] : {msg}")
@Slot() @Slot()
def pollMsgQueue( def pollMsgQueue(
@@ -293,7 +293,6 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
except queue.Empty: except queue.Empty:
pass pass
@Slot() @Slot()
def onTimerTaskWidgetClosed( def onTimerTaskWidgetClosed(
self self
@@ -301,7 +300,6 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.TimerTaskWidgetButton.setEnabled(True) self.TimerTaskWidgetButton.setEnabled(True)
@Slot(dict) @Slot(dict)
def onConfigWidgetClosed( def onConfigWidgetClosed(
self, self,
@@ -326,13 +324,12 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
@Slot(dict) @Slot(dict)
def onTimerTaskFinished( def onTimerTaskFinished(
self, self,
is_error: bool,
timer_task: dict timer_task: dict
): ):
self.__current_timer_task_thread.wait(1000) self.__current_timer_task_thread.wait(1000)
self.__current_timer_task_thread.finishedSignal_TimerWorker.disconnect(self.onTimerTaskFinished) self.__current_timer_task_thread.finishedSignal_TimerWorker.disconnect(self.onTimerTaskFinished)
self.__current_timer_task_thread.showTraceSignal.disconnect(self.showTrace)
self.__current_timer_task_thread.showMsgSignal.disconnect(self.showMsg)
self.__current_timer_task_thread.deleteLater() self.__current_timer_task_thread.deleteLater()
self.__current_timer_task_thread = None self.__current_timer_task_thread = None
self.setControlButtons(True, False, True) self.setControlButtons(True, False, True)
@@ -341,12 +338,17 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
timer_task["executed"] = True timer_task["executed"] = True
self.TrayIcon.showMessage( self.TrayIcon.showMessage(
"定时任务 - AutoLibrary", "定时任务 - AutoLibrary",
f"\n定时任务 '{timer_task['name']}' 执行完成", f"\n定时任务 '{timer_task['name']}' 执行{'失败' if is_error else '完成'}",
QSystemTrayIcon.MessageIcon.Information, QSystemTrayIcon.MessageIcon.Information,
1000 1000
) )
self.showTrace(f"定时任务 {timer_task['name']} 执行完成, uuid: {timer_task['task_uuid']}") self.showTrace(
self.timerTaskIsExecuted.emit(timer_task) f"定时任务 {timer_task['name']} 执行{'失败' if is_error else '完成'}, uuid: {timer_task['task_uuid']}"
)
if not is_error:
self.timerTaskIsExecuted.emit(timer_task)
else:
self.timerTaskIsError.emit(timer_task)
@Slot() @Slot()
def onTimerTaskWidgetButtonClicked( def onTimerTaskWidgetButtonClicked(
@@ -379,7 +381,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self self
): ):
self.setControlButtons(False, False, True) self.setControlButtons(True, True, False)
if self.__auto_lib_thread is None: if self.__auto_lib_thread is None:
self.__auto_lib_thread = AutoLibWorker( self.__auto_lib_thread = AutoLibWorker(
self.__input_queue, self.__input_queue,
@@ -387,8 +389,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.__config_paths self.__config_paths
) )
self.__auto_lib_thread.finishedSignal.connect(self.onStopButtonClicked) self.__auto_lib_thread.finishedSignal.connect(self.onStopButtonClicked)
self.__auto_lib_thread.showMsgSignal.connect(self.showMsg) self.__auto_lib_thread.finishedWithErrorSignal.connect(self.onStopButtonClicked)
self.__auto_lib_thread.showTraceSignal.connect(self.showTrace)
self.__auto_lib_thread.start() self.__auto_lib_thread.start()
@Slot() @Slot()
@@ -400,9 +401,8 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.showTrace("正在停止操作......") self.showTrace("正在停止操作......")
self.__auto_lib_thread.wait(2000) self.__auto_lib_thread.wait(2000)
self.showTrace("操作已停止") self.showTrace("操作已停止")
self.__auto_lib_thread.showMsgSignal.disconnect(self.showMsg)
self.__auto_lib_thread.showTraceSignal.disconnect(self.showTrace)
self.__auto_lib_thread.finishedSignal.disconnect(self.onStopButtonClicked) self.__auto_lib_thread.finishedSignal.disconnect(self.onStopButtonClicked)
self.__auto_lib_thread.finishedWithErrorSignal.disconnect(self.onStopButtonClicked)
self.__auto_lib_thread.deleteLater() self.__auto_lib_thread.deleteLater()
self.__auto_lib_thread = None self.__auto_lib_thread = None
self.setControlButtons(True, False, True) self.setControlButtons(True, False, True)
+48 -53
View File
@@ -12,18 +12,18 @@ import time
import queue import queue
from PySide6.QtCore import ( from PySide6.QtCore import (
Signal, QThread Slot, Signal, QThread
) )
from base.MsgBase import MsgBase
from operators.AutoLib import AutoLib from operators.AutoLib import AutoLib
from utils.ConfigReader import ConfigReader from utils.ConfigReader import ConfigReader
class AutoLibWorker(QThread): class AutoLibWorker(QThread, MsgBase):
finishedSignal = Signal() finishedSignal = Signal()
showTraceSignal = Signal(str) finishedWithErrorSignal = Signal()
showMsgSignal = Signal(str)
def __init__( def __init__(
self, self,
@@ -32,10 +32,8 @@ class AutoLibWorker(QThread):
config_paths: dict config_paths: dict
): ):
super().__init__() super().__init__(input_queue = input_queue, output_queue = output_queue)
self.__input_queue = input_queue
self.__output_queue = output_queue
self.__config_paths = config_paths self.__config_paths = config_paths
@@ -45,6 +43,10 @@ class AutoLibWorker(QThread):
current_time = time.strftime("%H:%M", time.localtime()) current_time = time.strftime("%H:%M", time.localtime())
if current_time >= "23:30" or current_time <= "07:30": if current_time >= "23:30" or current_time <= "07:30":
self._showTrace(
"当前时间不在图书馆开放时间内\n"\
" 请在 07:30 - 23:30 之间尝试"
)
return False return False
return True return True
@@ -56,9 +58,7 @@ class AutoLibWorker(QThread):
if not all( if not all(
os.path.exists(path) for path in self.__config_paths.values() os.path.exists(path) for path in self.__config_paths.values()
): ):
self.showTraceSignal.emit( self._showTrace("配置文件路径不存在, 请检查配置文件路径是否正确。")
"配置文件路径不存在, 请检查配置文件路径是否正确。"
)
return False return False
return True return True
@@ -67,25 +67,24 @@ class AutoLibWorker(QThread):
self self
) -> bool: ) -> bool:
self.showTraceSignal.emit( self._showTrace(
f"正在加载配置文件, 运行配置文件路径: {self.__config_paths["run"]}" f"正在加载配置文件, 运行配置文件路径: {self.__config_paths["run"]}"
) )
self.__run_config = ConfigReader( self.__run_config = ConfigReader(
self.__config_paths["run"] self.__config_paths["run"]
).getConfigs() ).getConfigs()
self.showTraceSignal.emit( self._showTrace(
f"正在加载配置文件, 用户配置文件路径: {self.__config_paths["user"]}" f"正在加载配置文件, 用户配置文件路径: {self.__config_paths["user"]}"
) )
self.__user_config = ConfigReader( self.__user_config = ConfigReader(
self.__config_paths["user"] self.__config_paths["user"]
).getConfigs() ).getConfigs()
if self.__run_config is None or self.__user_config is None: if self.__run_config is None or self.__user_config is None:
self.showTraceSignal.emit( self._showTrace("配置文件加载失败, 请检查配置文件是否正确")
"配置文件加载失败, 请检查配置文件是否正确" self._showTrace("配置文件加载失败, 请检查配置文件是否正确")
)
return False return False
if not self.__user_config.get("groups"): if not self.__user_config.get("groups"):
self.showTraceSignal.emit( self._showTrace(
"用户配置文件中无有效任务组, 请检查用户配置文件是否正确" "用户配置文件中无有效任务组, 请检查用户配置文件是否正确"
) )
return False return False
@@ -99,55 +98,39 @@ class AutoLibWorker(QThread):
auto_lib = None auto_lib = None
try: try:
if not self.checkTimeAvailable(): if not self.checkTimeAvailable():
self.showTraceSignal.emit(
"当前时间不在图书馆开放时间内\n"\
" 请在 07:30 - 23:30 之间尝试"
)
return return
if not self.checkConfigPaths(): if not self.checkConfigPaths():
return return
self.showTraceSignal.emit("AutoLibrary 开始运行") self._showTrace("AutoLibrary 开始运行")
if not self.loadConfigs(): if not self.loadConfigs():
return raise Exception("配置文件加载失败")
auto_lib = AutoLib( auto_lib = AutoLib(
self.__input_queue, self._input_queue,
self.__output_queue, self._output_queue,
self.__run_config self.__run_config
) )
if auto_lib is None:
self.showTraceSignal.emit(
"AutoLibrary 初始化失败"
)
return
groups = self.__user_config.get("groups") groups = self.__user_config.get("groups")
for group in groups: for group in groups:
time.sleep(0.2) # wait for the message queue to be empty
if not group["enabled"]: if not group["enabled"]:
self.showTraceSignal.emit( self._showTrace(f"任务组 {group["name"]} 已跳过")
f"任务组 {group["name"]} 已跳过"
)
continue continue
self.showTraceSignal.emit( self._showTrace(f"正在运行任务组 {group["name"]}")
f"正在运行任务组 {group["name"]}"
)
auto_lib.run( auto_lib.run(
{ "users": group.get("users", []) } { "users": group.get("users", []) }
) )
except Exception as e: except Exception as e:
self.showTraceSignal.emit( self._showTrace(f"AutoLibrary 运行时发生异常 : {e}")
f"AutoLibrary 运行时发生异常 : {e}" self.finishedWithErrorSignal.emit()
) return
finally: if auto_lib:
if auto_lib: auto_lib.close()
auto_lib.close() self._showTrace("AutoLibrary 运行结束")
time.sleep(0.2) # wait for the message queue to be empty self.finishedSignal.emit()
self.showTraceSignal.emit("AutoLibrary 运行结束")
self.finishedSignal.emit()
class TimerTaskWorker(AutoLibWorker): class TimerTaskWorker(AutoLibWorker):
finishedSignal_TimerWorker = Signal(dict) finishedSignal_TimerWorker = Signal(bool, dict)
def __init__( def __init__(
self, self,
@@ -160,16 +143,28 @@ class TimerTaskWorker(AutoLibWorker):
super().__init__(input_queue, output_queue, config_paths) super().__init__(input_queue, output_queue, config_paths)
self.__timer_task = timer_task self.__timer_task = timer_task
self.finishedSignal.connect(self.onTimerTaskIsFinished)
self.finishedWithErrorSignal.connect(self.onTimerTaskIsError)
def run( def run(
self self
): ):
self.showTraceSignal.emit( self._showTrace(f"定时任务 {self.__timer_task['name']} 开始运行")
f"定时任务 {self.__timer_task['name']} 开始运行"
)
super().run() super().run()
self.showTraceSignal.emit(
f"定时任务 {self.__timer_task['name']} 运行结束" @Slot(dict)
) def onTimerTaskIsError(
self.finishedSignal_TimerWorker.emit(self.__timer_task) self
):
self._showTrace(f"定时任务 {self.__timer_task['name']} 运行时发生异常")
self.finishedSignal_TimerWorker.emit(True, self.__timer_task)
@Slot(dict)
def onTimerTaskIsFinished(
self
):
self._showTrace(f"定时任务 {self.__timer_task['name']} 运行结束")
self.finishedSignal_TimerWorker.emit(False, self.__timer_task)
+19
View File
@@ -94,6 +94,9 @@ class TimerTaskItemWidget(QWidget):
case TimerTaskStatus.EXECUTED: case TimerTaskStatus.EXECUTED:
TaskStatusText = "已执行" TaskStatusText = "已执行"
TaskStatusColor = "#4CAF50" TaskStatusColor = "#4CAF50"
case TimerTaskStatus.ERROR:
TaskStatusText = "执行失败"
TaskStatusColor = "#FF5722"
case TimerTaskStatus.OUTDATED: case TimerTaskStatus.OUTDATED:
TaskStatusText = "已过期" TaskStatusText = "已过期"
TaskStatusColor = "#FF5722" TaskStatusColor = "#FF5722"
@@ -315,6 +318,7 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
pending = 0 pending = 0
in_queue = 0 in_queue = 0
executed = 0 executed = 0
invalid = 0
total = len(self.__timer_tasks) total = len(self.__timer_tasks)
for timer_task in self.__timer_tasks: for timer_task in self.__timer_tasks:
if timer_task["status"] == TimerTaskStatus.PENDING: if timer_task["status"] == TimerTaskStatus.PENDING:
@@ -324,10 +328,14 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
in_queue += 1 in_queue += 1
elif timer_task["status"] == TimerTaskStatus.EXECUTED: elif timer_task["status"] == TimerTaskStatus.EXECUTED:
executed += 1 executed += 1
elif timer_task["status"] == TimerTaskStatus.ERROR\
or timer_task["status"] == TimerTaskStatus.OUTDATED:
invalid += 1
self.TotalTaskLabel.setText(f"总任务:{total}") self.TotalTaskLabel.setText(f"总任务:{total}")
self.PendingTaskLabel.setText(f"待执行:{pending}") self.PendingTaskLabel.setText(f"待执行:{pending}")
self.InQueueTaskLabel.setText(f"队列中:{in_queue}") self.InQueueTaskLabel.setText(f"队列中:{in_queue}")
self.ExecutedTaskLabel.setText(f"已执行:{executed}") self.ExecutedTaskLabel.setText(f"已执行:{executed}")
self.InvalidTaskLabel.setText(f"无效的:{invalid}")
def updateTimerTaskList( def updateTimerTaskList(
@@ -470,3 +478,14 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
if task["task_uuid"] == timer_task["task_uuid"]: if task["task_uuid"] == timer_task["task_uuid"]:
task["status"] = TimerTaskStatus.EXECUTED task["status"] = TimerTaskStatus.EXECUTED
self.timerTasksChanged.emit() self.timerTasksChanged.emit()
@Slot(dict)
def onTimerTaskIsError(
self,
timer_task: dict
):
for task in self.__timer_tasks:
if task["task_uuid"] == timer_task["task_uuid"]:
task["status"] = TimerTaskStatus.ERROR
self.timerTasksChanged.emit()
+24
View File
@@ -137,6 +137,30 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="InvalidTaskLabel">
<property name="minimumSize">
<size>
<width>70</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>25</width>
<height>70</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QLabel {
color: #FF5722
}</string>
</property>
<property name="text">
<string>无效的:0</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QFrame" name="TimerTaskSpaceFrame"> <widget class="QFrame" name="TimerTaskSpaceFrame">
<property name="minimumSize"> <property name="minimumSize">
+2 -2
View File
@@ -41,10 +41,10 @@ class AutoLib(MsgBase):
self.__user_config = None self.__user_config = None
self.__driver = None self.__driver = None
if not self.__initBrowserDriver(): if not self.__initBrowserDriver():
return None raise Exception("浏览器驱动初始化失败")
else: else:
if not self.__initDriverUrl(): if not self.__initDriverUrl():
return None raise Exception("浏览器驱动URL初始化失败")
self.__initLibOperators() self.__initLibOperators()