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

Compare commits

...

6 Commits

11 changed files with 537 additions and 200 deletions
+9 -9
View File
@@ -67,21 +67,21 @@ Version: {AL_VERSION}<br>
Python version: {platform.python_version()}<br> Python version: {platform.python_version()}<br>
Qt version: {self.getQtVersion()}<br> Qt version: {self.getQtVersion()}<br>
<h4>Author Information:</h4> <h4>System Information:</h4>
Developer: KenanZhu<br> Processor: {platform.processor()}<br>
Contact: nanoki_zh@163.com<br> Operating system: {os_info['system']}<br>
GitHub: <a href="https://www.github.com/KenanZhu" style="text-decoration: none;">https://www.github.com/KenanZhu</a><br> System version: {os_info['version']}<br>
System architecture: {os_info['architecture']}<br>
<h4>Project Information:</h4> <h4>Project Information:</h4>
License: MIT License<br> License: MIT License<br>
Project repository: <a href="https://www.github.com/KenanZhu/AutoLibrary" style="text-decoration: none;">https://www.github.com/KenanZhu/AutoLibrary</a><br> Project repository: <a href="https://www.github.com/KenanZhu/AutoLibrary" style="text-decoration: none;">https://www.github.com/KenanZhu/AutoLibrary</a><br>
Project website: <a href="https://www.autolibrary.cv/" style="text-decoration: none;">https://www.autolibrary.cv/</a><br> Project website: <a href="https://www.autolibrary.cv/" style="text-decoration: none;">https://www.autolibrary.cv/</a><br>
<h4>System Information:</h4> <h4>Author Information:</h4>
Processor: {platform.processor()}<br> Developer: KenanZhu<br>
Operating system: {os_info['system']}<br> Contact: nanoki_zh@163.com<br>
System version: {os_info['version']}<br> GitHub: <a href="https://www.github.com/KenanZhu" style="text-decoration: none;">https://www.github.com/KenanZhu</a><br>
System architecture: {os_info['architecture']}<br>
""" """
return about_text return about_text
+40 -5
View File
@@ -6,25 +6,28 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>300</width> <width>400</width>
<height>300</height> <height>400</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>300</width> <width>400</width>
<height>300</height> <height>400</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>800</width> <width>800</width>
<height>300</height> <height>400</height>
</size> </size>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>关于 - AutoLibrary</string> <string>关于 - AutoLibrary</string>
</property> </property>
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="ALAboutDialogLayout"> <layout class="QVBoxLayout" name="ALAboutDialogLayout">
<property name="spacing"> <property name="spacing">
<number>5</number> <number>5</number>
@@ -95,6 +98,36 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="AboutInfoLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame">
<property name="minimumSize">
<size>
<width>56</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>56</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Shape::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
</item>
<item> <item>
<widget class="QTextEdit" name="AboutInfoEdit"> <widget class="QTextEdit" name="AboutInfoEdit">
<property name="font"> <property name="font">
@@ -114,6 +147,8 @@
</property> </property>
</widget> </widget>
</item> </item>
</layout>
</item>
<item> <item>
<widget class="QPushButton" name="CopyButton"> <widget class="QPushButton" name="CopyButton">
<property name="minimumSize"> <property name="minimumSize">
+1
View File
@@ -31,6 +31,7 @@ from gui.Ui_ALAddTimerTaskDialog import Ui_ALAddTimerTaskDialog
class TimerTaskStatus(Enum): class TimerTaskStatus(Enum):
PENDING = "等待中" PENDING = "等待中"
READY = "已就绪" READY = "已就绪"
RUNNING = "执行中" RUNNING = "执行中"
+27 -3
View File
@@ -19,8 +19,8 @@ from PySide6.QtWidgets import (
from PySide6.QtGui import QCloseEvent from PySide6.QtGui import QCloseEvent
from gui.Ui_ALConfigWidget import Ui_ALConfigWidget from gui.Ui_ALConfigWidget import Ui_ALConfigWidget
from gui.SeatMapWidget import SeatMapWidget from gui.ALSeatMapWidget import ALSeatMapWidget
from gui.SeatMapTable import seats_maps from gui.ALSeatMapTable import seats_maps
from utils.ConfigReader import ConfigReader from utils.ConfigReader import ConfigReader
from utils.ConfigWriter import ConfigWriter from utils.ConfigWriter import ConfigWriter
@@ -84,6 +84,30 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.CancelButton.clicked.connect(self.onCancelButtonClicked) self.CancelButton.clicked.connect(self.onCancelButtonClicked)
def showEvent(
self,
event
):
result = super().showEvent(event)
screen_rect = self.screen().geometry()
target_pos = self.parent().geometry().center()
target_pos.setX(target_pos.x() - self.width()//2)
target_pos.setY(target_pos.y() - self.height()//2)
if target_pos.x() < 0:
target_pos.setX(0)
if target_pos.x() + self.width() > screen_rect.width():
target_pos.setX(screen_rect.width() - self.width())
if target_pos.y() < 0:
target_pos.setY(0)
if target_pos.y() + self.height() > screen_rect.height():
target_pos.setY(screen_rect.height() - self.height())
self.move(target_pos)
return result
def closeEvent( def closeEvent(
self, self,
event: QCloseEvent event: QCloseEvent
@@ -647,7 +671,7 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
floor_idx = self.__floor_rmap[floor] floor_idx = self.__floor_rmap[floor]
room_idx = self.__room_rmap[room] room_idx = self.__room_rmap[room]
if self.__seat_map_widget is None: if self.__seat_map_widget is None:
self.__seat_map_widget = SeatMapWidget( self.__seat_map_widget = ALSeatMapWidget(
self, self,
floor, floor,
room, room,
+28 -141
View File
@@ -13,7 +13,7 @@ import time
import queue import queue
from PySide6.QtCore import ( from PySide6.QtCore import (
Qt, Signal, Slot, QDir, QFileInfo, QTimer, QThread, QUrl, Qt, Signal, Slot, QDir, QFileInfo, QTimer, QUrl,
) )
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
QMainWindow, QMenu, QSystemTrayIcon QMainWindow, QMenu, QSystemTrayIcon
@@ -26,124 +26,12 @@ from gui.Ui_ALMainWindow import Ui_ALMainWindow
from gui.ALConfigWidget import ALConfigWidget from gui.ALConfigWidget import ALConfigWidget
from gui.ALTimerTaskWidget import ALTimerTaskWidget from gui.ALTimerTaskWidget import ALTimerTaskWidget
from gui.ALAboutDialog import ALAboutDialog from gui.ALAboutDialog import ALAboutDialog
from gui.ALMainWorkers import TimerTaskWorker, AutoLibWorker
from gui import AutoLibraryResource from gui import AutoLibraryResource
from operators.AutoLib import AutoLib
from utils.ConfigReader import ConfigReader from utils.ConfigReader import ConfigReader
from utils.ConfigWriter import ConfigWriter
class AutoLibWorker(QThread):
finishedSignal = Signal()
showTraceSignal = Signal(str)
showMsgSignal = Signal(str)
def __init__(
self,
input_queue: queue.Queue,
output_queue: queue.Queue,
config_paths: dict
):
super().__init__()
self.__input_queue = input_queue
self.__output_queue = output_queue
self.__config_paths = config_paths
def checkTimeAvailable(
self,
) -> bool:
current_time = time.strftime("%H:%M", time.localtime())
if current_time >= "23:30" or current_time <= "07:30":
return False
return True
def checkConfigPaths(
self,
) -> bool:
if not all(
os.path.exists(path) for path in self.__config_paths.values()
):
self.showTraceSignal.emit(
"配置文件路径不存在, 请检查配置文件路径是否正确。"
)
return False
return True
def run(
self
):
auto_lib = None
try:
if not self.checkTimeAvailable():
self.showTraceSignal.emit(
"当前时间不在图书馆开放时间内。\n"\
" 请在 07:30 - 23:30 之间尝试"
)
return
if not self.checkConfigPaths():
return
self.showTraceSignal.emit("AutoLibrary 开始运行")
auto_lib = AutoLib(
self.__input_queue,
self.__output_queue,
)
auto_lib.run(
ConfigReader(self.__config_paths["system"]),
ConfigReader(self.__config_paths["users"]),
)
except Exception as e:
self.showTraceSignal.emit(
f"AutoLibrary 运行时发生异常 : {e}"
)
finally:
if auto_lib:
auto_lib.close()
self.showTraceSignal.emit("AutoLibrary 运行结束")
self.finishedSignal.emit()
class TimerTaskWorker(AutoLibWorker):
finishedSignal_TimerWorker = Signal(dict)
def __init__(
self,
timer_task: dict,
input_queue: queue.Queue,
output_queue: queue.Queue,
config_paths: dict
):
super().__init__(
input_queue,
output_queue,
config_paths,
)
self.__timer_task = timer_task
self.__stopped = False
def run(
self
):
self.showTraceSignal.emit(
f"定时任务 {self.__timer_task['name']} 开始运行"
)
super().run()
self.showTraceSignal.emit(
f"定时任务 {self.__timer_task['name']} 运行结束"
)
self.finishedSignal_TimerWorker.emit(self.__timer_task)
class ALMainWindow(QMainWindow, Ui_ALMainWindow): class ALMainWindow(QMainWindow, Ui_ALMainWindow):
@@ -167,10 +55,10 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.__config_paths = { self.__config_paths = {
"system": QDir.toNativeSeparators(script_dir.absoluteFilePath("system.json")), "system": QDir.toNativeSeparators(script_dir.absoluteFilePath("system.json")),
"users": QDir.toNativeSeparators(script_dir.absoluteFilePath("users.json")), "users": QDir.toNativeSeparators(script_dir.absoluteFilePath("users.json")),
"timer_tasks": QDir.toNativeSeparators(script_dir.absoluteFilePath("timer_tasks.json")),
} }
self.__alTimerTaskWidget = None self.__alTimerTaskWidget = None
self.__alConfigWidget = None self.__alConfigWidget = None
self.__alAboutDialog = None
self.__auto_lib_thread = None self.__auto_lib_thread = None
self.__current_timer_task_thread = None self.__current_timer_task_thread = None
self.__is_running_timer_task = False self.__is_running_timer_task = False
@@ -192,14 +80,21 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.ManualAction.triggered.connect(self.onManualActionTriggered) self.ManualAction.triggered.connect(self.onManualActionTriggered)
self.AboutAction.triggered.connect(self.onAboutActionTriggered) self.AboutAction.triggered.connect(self.onAboutActionTriggered)
# initialize timer task widget, but not show it
self.__alTimerTaskWidget = ALTimerTaskWidget(self, self.__config_paths["timer_tasks"])
self.timerTaskIsRunning.connect(self.__alTimerTaskWidget.onTimerTaskIsRunning)
self.timerTaskIsExecuted.connect(self.__alTimerTaskWidget.onTimerTaskIsExecuted)
self.__alTimerTaskWidget.timerTaskIsReady.connect(self.onTimerTaskIsReady)
self.__alTimerTaskWidget.timerTaskWidgetClosed.connect(self.onTimerTaskWidgetClosed)
self.__alTimerTaskWidget.setWindowFlags(Qt.WindowType.Window|Qt.WindowType.WindowCloseButtonHint)
def onAboutActionTriggered( def onAboutActionTriggered(
self self
): ):
if self.__alAboutDialog is None: about_dialog = ALAboutDialog(self)
self.__alAboutDialog = ALAboutDialog(self) about_dialog.exec()
self.__alAboutDialog.show()
def onManualActionTriggered( def onManualActionTriggered(
@@ -274,8 +169,8 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
event: QCloseEvent event: QCloseEvent
): ):
if self.__timer and self.__timer.isActive(): if self.__msg_queue_timer and self.__msg_queue_timer.isActive():
self.__timer.stop() self.__msg_queue_timer.stop()
if self.__timer_task_timer and self.__timer_task_timer.isActive(): if self.__timer_task_timer and self.__timer_task_timer.isActive():
self.__timer_task_timer.stop() self.__timer_task_timer.stop()
if self.__is_running_timer_task: if self.__is_running_timer_task:
@@ -308,9 +203,9 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self self
): ):
self.__timer = QTimer() self.__msg_queue_timer = QTimer()
self.__timer.timeout.connect(self.pollMsgQueue) self.__msg_queue_timer.timeout.connect(self.pollMsgQueue)
self.__timer.start(100) self.__msg_queue_timer.start(100)
def startTimerTaskPolling( def startTimerTaskPolling(
@@ -361,13 +256,13 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
def setControlButtons( def setControlButtons(
self, self,
config_button_enabled: bool, config_button_enabled: bool,
start_button_enabled: bool, stop_button_enabled: bool,
stop_button_enabled: bool start_button_enabled: bool
): ):
self.ConfigButton.setEnabled(config_button_enabled) self.ConfigButton.setEnabled(config_button_enabled)
self.StartButton.setEnabled(start_button_enabled)
self.StopButton.setEnabled(stop_button_enabled) self.StopButton.setEnabled(stop_button_enabled)
self.StartButton.setEnabled(start_button_enabled)
@Slot() @Slot()
def showMsg( def showMsg(
@@ -417,13 +312,11 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.__alConfigWidget.configWidgetCloseSingal.disconnect(self.onConfigWidgetClosed) self.__alConfigWidget.configWidgetCloseSingal.disconnect(self.onConfigWidgetClosed)
self.__alConfigWidget.deleteLater() self.__alConfigWidget.deleteLater()
self.__alConfigWidget = None self.__alConfigWidget = None
self.ConfigButton.setEnabled(True) self.setControlButtons(True, False, True)
self.StartButton.setEnabled(True)
self.StopButton.setEnabled(False)
self.__config_paths = config_paths self.__config_paths = config_paths
@Slot(dict) @Slot(dict)
def onTimerTaskReady( def onTimerTaskIsReady(
self, self,
timer_task: dict timer_task: dict
): ):
@@ -442,7 +335,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.__current_timer_task_thread.showMsgSignal.disconnect(self.showMsg) 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, True, False) self.setControlButtons(True, False, True)
self.__is_running_timer_task = False self.__is_running_timer_task = False
self.__timer_task_timer.start(500) self.__timer_task_timer.start(500)
timer_task["executed"] = True timer_task["executed"] = True
@@ -459,13 +352,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
def onTimerTaskWidgetButtonClicked( def onTimerTaskWidgetButtonClicked(
self self
): ):
if self.__alTimerTaskWidget is None:
self.__alTimerTaskWidget = ALTimerTaskWidget(self)
self.timerTaskIsRunning.connect(self.__alTimerTaskWidget.onTimerTaskIsRunning)
self.timerTaskIsExecuted.connect(self.__alTimerTaskWidget.onTimerTaskIsExecuted)
self.__alTimerTaskWidget.timerTaskReady.connect(self.onTimerTaskReady)
self.__alTimerTaskWidget.timerTaskWidgetClosed.connect(self.onTimerTaskWidgetClosed)
self.__alTimerTaskWidget.setWindowFlags(Qt.Window)
self.__alTimerTaskWidget.show() self.__alTimerTaskWidget.show()
self.__alTimerTaskWidget.raise_() self.__alTimerTaskWidget.raise_()
self.__alTimerTaskWidget.activateWindow() self.__alTimerTaskWidget.activateWindow()
@@ -482,8 +369,8 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
self.__config_paths self.__config_paths
) )
self.__alConfigWidget.configWidgetCloseSingal.connect(self.onConfigWidgetClosed) self.__alConfigWidget.configWidgetCloseSingal.connect(self.onConfigWidgetClosed)
self.__alConfigWidget.setWindowFlags(Qt.Window) self.__alConfigWidget.setWindowFlags(Qt.WindowType.Window)
self.__alConfigWidget.setWindowModality(Qt.ApplicationModal) self.__alConfigWidget.setWindowModality(Qt.WindowModality.ApplicationModal)
self.__alConfigWidget.show() self.__alConfigWidget.show()
self.__alConfigWidget.raise_() self.__alConfigWidget.raise_()
self.__alConfigWidget.activateWindow() self.__alConfigWidget.activateWindow()
+132
View File
@@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
"""
Copyright (c) 2025 KenanZhu.
All rights reserved.
This software is provided "as is", without any warranty of any kind.
You may use, modify, and distribute this file under the terms of the MIT License.
See the LICENSE file for details.
"""
import os
import time
import queue
from PySide6.QtCore import (
Signal, QThread
)
from operators.AutoLib import AutoLib
from utils.ConfigReader import ConfigReader
class AutoLibWorker(QThread):
finishedSignal = Signal()
showTraceSignal = Signal(str)
showMsgSignal = Signal(str)
def __init__(
self,
input_queue: queue.Queue,
output_queue: queue.Queue,
config_paths: dict
):
super().__init__()
self.__input_queue = input_queue
self.__output_queue = output_queue
self.__config_paths = config_paths
def checkTimeAvailable(
self,
) -> bool:
current_time = time.strftime("%H:%M", time.localtime())
if current_time >= "23:30" or current_time <= "07:30":
return False
return True
def checkConfigPaths(
self,
) -> bool:
if not all(
os.path.exists(path) for path in self.__config_paths.values()
):
self.showTraceSignal.emit(
"配置文件路径不存在, 请检查配置文件路径是否正确。"
)
return False
return True
def run(
self
):
auto_lib = None
try:
if not self.checkTimeAvailable():
self.showTraceSignal.emit(
"当前时间不在图书馆开放时间内。\n"\
" 请在 07:30 - 23:30 之间尝试"
)
return
if not self.checkConfigPaths():
return
self.showTraceSignal.emit("AutoLibrary 开始运行")
auto_lib = AutoLib(
self.__input_queue,
self.__output_queue,
)
auto_lib.run(
ConfigReader(self.__config_paths["system"]),
ConfigReader(self.__config_paths["users"]),
)
except Exception as e:
self.showTraceSignal.emit(
f"AutoLibrary 运行时发生异常 : {e}"
)
finally:
if auto_lib:
auto_lib.close()
self.showTraceSignal.emit("AutoLibrary 运行结束")
self.finishedSignal.emit()
class TimerTaskWorker(AutoLibWorker):
finishedSignal_TimerWorker = Signal(dict)
def __init__(
self,
timer_task: dict,
input_queue: queue.Queue,
output_queue: queue.Queue,
config_paths: dict
):
super().__init__(
input_queue,
output_queue,
config_paths,
)
self.__timer_task = timer_task
self.__stopped = False
def run(
self
):
self.showTraceSignal.emit(
f"定时任务 {self.__timer_task['name']} 开始运行"
)
super().run()
self.showTraceSignal.emit(
f"定时任务 {self.__timer_task['name']} 运行结束"
)
self.finishedSignal_TimerWorker.emit(self.__timer_task)
@@ -15,7 +15,7 @@ from PySide6.QtWidgets import (
) )
class SeatFrame(QFrame): class ALSeatFrame(QFrame):
clicked = Signal(str) clicked = Signal(str)
@@ -18,10 +18,10 @@ from PySide6.QtWidgets import (
from PySide6.QtGui import ( from PySide6.QtGui import (
QPainter, QWheelEvent, QCloseEvent QPainter, QWheelEvent, QCloseEvent
) )
from gui.SeatFrame import SeatFrame from gui.ALSeatFrame import ALSeatFrame
class SeatMapWidget(QWidget): class ALSeatMapWidget(QWidget):
seatMapWidgetClosed = Signal(list) seatMapWidgetClosed = Signal(list)
@@ -115,6 +115,30 @@ class SeatMapWidget(QWidget):
self.CancelButton.clicked.connect(self.onCancelButtonClicked) self.CancelButton.clicked.connect(self.onCancelButtonClicked)
def showEvent(
self,
event
):
result = super().showEvent(event)
screen_rect = self.screen().geometry()
target_pos = self.parent().geometry().center()
target_pos.setX(target_pos.x() - self.width()//2)
target_pos.setY(target_pos.y() - self.height()//2)
if target_pos.x() < 0:
target_pos.setX(0)
if target_pos.x() + self.width() > screen_rect.width():
target_pos.setX(screen_rect.width() - self.width())
if target_pos.y() < 0:
target_pos.setY(0)
if target_pos.y() + self.height() > screen_rect.height():
target_pos.setY(screen_rect.height() - self.height())
self.move(target_pos)
return result
def closeEvent( def closeEvent(
self, self,
event: QCloseEvent event: QCloseEvent
@@ -160,7 +184,7 @@ class SeatMapWidget(QWidget):
seats_number = [seat.strip() for seat in row.split(",")] seats_number = [seat.strip() for seat in row.split(",")]
for seat_number in seats_number: for seat_number in seats_number:
if seat_number: if seat_number:
seat_widget = SeatFrame(seat_number) seat_widget = ALSeatFrame(seat_number)
seat_widget.clicked.connect(self.onSeatClicked) seat_widget.clicked.connect(self.onSeatClicked)
self.SeatsContainerLayout.addWidget(seat_widget, row_idx, col_idx) self.SeatsContainerLayout.addWidget(seat_widget, row_idx, col_idx)
self.__seat_frames[seat_number] = seat_widget self.__seat_frames[seat_number] = seat_widget
+179 -21
View File
@@ -10,6 +10,7 @@ See the LICENSE file for details.
import os import os
import sys import sys
import time import time
import copy
import queue import queue
from enum import Enum from enum import Enum
@@ -23,12 +24,22 @@ from PySide6.QtWidgets import (
QHBoxLayout, QVBoxLayout, QLabel, QPushButton QHBoxLayout, QVBoxLayout, QLabel, QPushButton
) )
from PySide6.QtGui import ( from PySide6.QtGui import (
QCloseEvent QCloseEvent, QScreen
) )
from gui.Ui_ALTimerTaskWidget import Ui_ALTimerTaskWidget from gui.Ui_ALTimerTaskWidget import Ui_ALTimerTaskWidget
from gui.ALAddTimerTaskDialog import ALAddTimerTaskWidget, TimerTaskStatus from gui.ALAddTimerTaskDialog import ALAddTimerTaskWidget, TimerTaskStatus
from utils.ConfigReader import ConfigReader
from utils.ConfigWriter import ConfigWriter
class SortPolicy(Enum):
BY_NAME = "按名称"
BY_ADD_TIME = "按添加时间"
BY_EXECUTE_TIME = "按执行时间"
class TimerTaskItemWidget(QWidget): class TimerTaskItemWidget(QWidget):
@@ -125,22 +136,38 @@ class TimerTaskItemWidget(QWidget):
class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget): class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
timerTasksChanged = Signal(list) timerTasksChanged = Signal()
timerTaskReady = Signal(dict) timerTaskIsReady = Signal(dict)
timerTaskWidgetClosed = Signal() timerTaskWidgetClosed = Signal()
def __init__( def __init__(
self, self,
parent = None parent = None,
timer_tasks_config_path: str = ""
): ):
super().__init__(parent) super().__init__(parent)
self.__timer_tasks = [] self.__timer_tasks = []
self.__check_timer = None self.__check_timer = None
self.__sort_policy = SortPolicy.BY_EXECUTE_TIME
self.__timer_tasks_config_path = timer_tasks_config_path
self.setupUi(self) self.setupUi(self)
self.connectSignals() self.connectSignals()
self.setupTimer() self.setupTimer()
if not self.initializeTimerTasks():
return
def connectSignals(
self
):
self.AddTimerTaskButton.clicked.connect(self.addTask)
self.ClearAllTimerTasksButton.clicked.connect(self.clearAllTasks)
self.TimerTaskSortTypeComboBox.currentIndexChanged.connect(self.onSortPolicyComboBoxChanged)
self.timerTasksChanged.connect(self.onTimerTasksChanged)
def setupTimer( def setupTimer(
@@ -152,12 +179,103 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
self.__check_timer.start(500) self.__check_timer.start(500)
def connectSignals( def initializeTimerTasks(
self self
) -> bool:
timer_tasks = self.loadTimerTasks(self.__timer_tasks_config_path)
if timer_tasks is not None:
self.__timer_tasks = timer_tasks
self.timerTasksChanged.emit()
return True
if self.saveTimerTasks(self.__timer_tasks_config_path, copy.deepcopy(timer_tasks)):
QMessageBox.information(
self,
"信息 - AutoLibrary",
f"定时任务配置文件初始化完成: \n{self.__timer_tasks_config_path}"
)
self.__timer_tasks = timer_tasks
self.updateTimerTaskList()
return True
return False
def loadTimerTasks(
self,
timer_tasks_config_path: str
) -> list:
try:
if not timer_tasks_config_path or not os.path.exists(timer_tasks_config_path):
raise Exception("定时任务配置文件不存在")
timer_tasks = ConfigReader(timer_tasks_config_path).getConfigs()
if timer_tasks and "timer_tasks" in timer_tasks:
for task in timer_tasks["timer_tasks"]:
task["add_time"] = datetime.strptime(task["add_time"], "%Y-%m-%d %H:%M:%S")
task["execute_time"] = datetime.strptime(task["execute_time"], "%Y-%m-%d %H:%M:%S")
task["status"] = TimerTaskStatus(task["status"])
return timer_tasks["timer_tasks"]
raise Exception("定时任务配置文件格式错误")
except Exception as e:
QMessageBox.warning(
self,
"警告 - AutoLibrary",
f"加载定时任务配置发生错误 ! : {e}\n"\
f"文件路径: {timer_tasks_config_path}"
)
return None
def saveTimerTasks(
self,
timer_tasks_config_path: str,
timer_tasks: list
) -> bool:
try:
if not timer_tasks_config_path:
raise Exception("配置文件路径为空")
for task in timer_tasks:
task["add_time"] = task["add_time"].strftime("%Y-%m-%d %H:%M:%S")
task["execute_time"] = task["execute_time"].strftime("%Y-%m-%d %H:%M:%S")
task["status"] = task["status"].value
ConfigWriter(
timer_tasks_config_path,
{ "timer_tasks": timer_tasks }
)
return True
except Exception as e:
QMessageBox.warning(
self,
"警告 - AutoLibrary",
f"保存定时任务配置发生错误 ! : {e}\n"\
f"文件路径: {timer_tasks_config_path}"
)
return False
def showEvent(
self,
event
): ):
self.AddTimerTaskButton.clicked.connect(self.addTask) result = super().showEvent(event)
self.ClearAllTimerTasksButton.clicked.connect(self.clearAllTasks)
screen_rect = self.screen().geometry()
target_pos = self.parent().geometry().center()
target_pos.setX(target_pos.x() - self.width()//2)
target_pos.setY(target_pos.y() - self.height()//2)
if target_pos.x() < 0:
target_pos.setX(0)
if target_pos.x() + self.width() > screen_rect.width():
target_pos.setX(screen_rect.width() - self.width())
if target_pos.y() < 0:
target_pos.setY(0)
if target_pos.y() + self.height() > screen_rect.height():
target_pos.setY(screen_rect.height() - self.height())
self.move(target_pos)
return result
def closeEvent( def closeEvent(
@@ -170,6 +288,25 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
event.ignore() event.ignore()
def sortTimerTasks(
self,
policy: SortPolicy = SortPolicy.BY_EXECUTE_TIME
):
if policy == SortPolicy.BY_NAME:
self.__timer_tasks.sort(
key = lambda x: x["name"]
)
elif policy == SortPolicy.BY_ADD_TIME:
self.__timer_tasks.sort(
key = lambda x: x["add_time"]
)
elif policy == SortPolicy.BY_EXECUTE_TIME:
self.__timer_tasks.sort(
key = lambda x: x["execute_time"]
)
def updateStat( def updateStat(
self self
): ):
@@ -197,9 +334,7 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
): ):
self.TimerTasksListWidget.clear() self.TimerTasksListWidget.clear()
self.__timer_tasks.sort( self.sortTimerTasks(self.__sort_policy)
key = lambda x: x["execute_time"]
)
for timer_task in self.__timer_tasks: for timer_task in self.__timer_tasks:
item = QListWidgetItem() item = QListWidgetItem()
item.setData(Qt.UserRole, timer_task) item.setData(Qt.UserRole, timer_task)
@@ -220,8 +355,7 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
if dialog.exec() == QDialog.DialogCode.Accepted: if dialog.exec() == QDialog.DialogCode.Accepted:
timer_task = dialog.getTimerTask() timer_task = dialog.getTimerTask()
self.__timer_tasks.append(timer_task) self.__timer_tasks.append(timer_task)
self.updateTimerTaskList() self.timerTasksChanged.emit()
self.updateStat()
def deleteTask( def deleteTask(
@@ -233,8 +367,7 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
x for x in self.__timer_tasks x for x in self.__timer_tasks
if x["task_uuid"] != task_uuid if x["task_uuid"] != task_uuid
] ]
self.updateTimerTaskList() self.timerTasksChanged.emit()
self.updateStat()
def clearAllTasks( def clearAllTasks(
@@ -264,14 +397,15 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
"存在正在执行或已就绪的队列任务,无法清除所有定时任务 !" "存在正在执行或已就绪的队列任务,无法清除所有定时任务 !"
) )
self.__timer_tasks = in_queue_tasks self.__timer_tasks = in_queue_tasks
self.updateTimerTaskList() self.timerTasksChanged.emit()
self.updateStat()
def checkTasks( def checkTasks(
self self
): ):
need_update = False
now = datetime.now() now = datetime.now()
for timer_task in self.__timer_tasks: for timer_task in self.__timer_tasks:
if timer_task["execute_time"] > now: if timer_task["execute_time"] > now:
@@ -280,9 +414,35 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
continue continue
if timer_task["execute_time"] <= now + timedelta(seconds = -5): if timer_task["execute_time"] <= now + timedelta(seconds = -5):
timer_task["status"] = TimerTaskStatus.OUTDATED timer_task["status"] = TimerTaskStatus.OUTDATED
need_update = True
else: else:
timer_task["status"] = TimerTaskStatus.READY timer_task["status"] = TimerTaskStatus.READY
self.timerTaskReady.emit(timer_task) self.timerTaskIsReady.emit(timer_task)
need_update = True
if need_update:
self.timerTasksChanged.emit()
@Slot(int)
def onSortPolicyComboBoxChanged(
self,
policy: int
):
mapping = {
0: SortPolicy.BY_NAME,
1: SortPolicy.BY_ADD_TIME,
2: SortPolicy.BY_EXECUTE_TIME
}
self.__sort_policy = mapping[policy]
self.updateTimerTaskList()
@Slot()
def onTimerTasksChanged(
self
):
self.saveTimerTasks(self.__timer_tasks_config_path, copy.deepcopy(self.__timer_tasks))
self.updateTimerTaskList() self.updateTimerTaskList()
self.updateStat() self.updateStat()
@@ -296,8 +456,7 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
for task in self.__timer_tasks: for task in self.__timer_tasks:
if task["task_uuid"] == timer_task["task_uuid"]: if task["task_uuid"] == timer_task["task_uuid"]:
task["status"] = TimerTaskStatus.RUNNING task["status"] = TimerTaskStatus.RUNNING
self.updateTimerTaskList() self.timerTasksChanged.emit()
self.updateStat()
@Slot(dict) @Slot(dict)
@@ -309,5 +468,4 @@ class ALTimerTaskWidget(QWidget, Ui_ALTimerTaskWidget):
for task in self.__timer_tasks: for task in self.__timer_tasks:
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.updateTimerTaskList() self.timerTasksChanged.emit()
self.updateStat()
+76
View File
@@ -161,6 +161,82 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="TimerTaskSortLayout">
<property name="spacing">
<number>5</number>
</property>
<item>
<widget class="QFrame" name="TimerTaskSortSpaceFrame">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Shape::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="TimerTaskSortLabel">
<property name="minimumSize">
<size>
<width>40</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>排序:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="TimerTaskSortTypeComboBox">
<property name="minimumSize">
<size>
<width>90</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>90</width>
<height>25</height>
</size>
</property>
<item>
<property name="text">
<string>按名称</string>
</property>
</item>
<item>
<property name="text">
<string>按添加时间</string>
</property>
</item>
<item>
<property name="text">
<string>按执行时间</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QListWidget" name="TimerTasksListWidget"> <widget class="QListWidget" name="TimerTasksListWidget">
<property name="enabled"> <property name="enabled">