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

Compare commits

...

14 Commits

Author SHA1 Message Date
Kenan Zhu 73aab7b957 feat(LibCheckin, gui.*): 支持校园网环境下图书馆远程签到;定时任务管理支持可重复性定时任务 (#5)
- feat(LibCheckin): 支持校园网环境下图书馆远程签到 
- feat(TimerUtils): 新增重复任务时间计算工具 
- feat(TimerTask): 新增任务执行历史对话框 
- feat(TimerTaskAddDialog): 添加重复任务 UI 支持 
- feat(TimerTaskManageWidget): 实现重复任务执行与历史记录 
- fix(ALTimerTaskAddDialog): 修改添加定时任务对话框的重复选项的 Label 描述和布局
- fix(ALTimerTaskAddDialog): 修改定时任务时间类型中相对时间控件的布局样式 
- fix(ALTimerTaskAddDialog): 删除定时任务数据中多余的字段 ‘repeat_records’
- fix(ALTimerTaskAddDialog): 修改添加定时任务对话框的重复选项的 Label 描述和布局 
- style(ALTimerTaskManageWidget): 统一 import 语句的格式 
- refactor(ALTimerTaskItemWidget): 一些变量重构
- optimze(gui): 优化删除按钮样式,使其更加醒目;优化 ALTimerTaskManageWidget 的宽度 
- optimize(gui): 优化定时任务管理功能 
- fix(ALTimerTaskManageWidget): 修复删除任务的信号槽参数传递问题
2026-03-17 16:04:59 +08:00
KenanZhu 0a94c344d5 ci(workflows): 修复 Release 工作流的触发条件
- 当创建 'release/v*' 分支时,自动进行 Release 构建

/! Release 流程必须手动创建分支,工作流结束后会将对应分支提交合并
/! 到 main 分支上,且对应分支会被删除
2026-03-17 15:46:32 +08:00
KenanZhu 68e002ba8e fix(ALTimerTaskManageWidget): 修复删除任务的信号槽参数传递问题
- 修复删除任务的信号槽参数传递问题,此次修复通过 lambda 表达式将当前的 task 作为参数传递,避免了闭包陷阱。
2026-03-17 15:27:03 +08:00
KenanZhu 94dc22819f optimize(gui): 优化定时任务管理功能
- 优化任务历史查看对话框的界面布局和交互体验
- 新增任务状态枚举值以支持更完整的状态管理
- 统一重复任务执行后的历史记录处理逻辑
- 增强删除任务时的确认机制,删除可重复任务前展示详细执行记录
- 完善批量清除任务的验证流程,检查运行中任务并确认重复任务删除
2026-03-17 14:51:55 +08:00
KenanZhu d55d2075cb optimze(gui): 优化删除按钮样式,使其更加醒目;优化 ALTimerTaskManageWidget 的宽度
- 优化了 ALConfigWidget, ALTimerTaskManageWidget 中的删除按钮样式(字体颜色更改为红色),使其更加醒目
- 优化了 ALTimerTaskManageWidget 的宽度,使其适应内容宽度
2026-03-17 14:46:19 +08:00
KenanZhu 82744e3a2d refactor(ALTimerTaskItemWidget): 一些变量重构 2026-03-17 14:42:47 +08:00
KenanZhu 67493349dd style(ALTimerTaskManageWidget): 统一 import 语句的格式
- 对 gui.ALTimerTaskAddDialog 的 import 语句进行格式化
2026-03-17 14:42:07 +08:00
KenanZhu 0aea9b1540 fix(ALTimerTaskAddDialog): 修改添加定时任务对话框的重复选项的 Label 描述和布局
- 对 (b73242be00) 的补充提交
2026-03-17 14:39:01 +08:00
KenanZhu c02c6ddbe3 fix(ALTimerTaskAddDialog): 删除定时任务数据中多余的字段 ‘repeat_records’ 2026-03-17 14:37:33 +08:00
KenanZhu c679a1c79e fix(ALTimerTaskAddDialog): 修改定时任务时间类型中相对时间控件的布局样式
- 由栅格布局改为水平布局,该区域的高度与绝对时间控件的高度一致
2026-03-17 14:35:47 +08:00
KenanZhu b73242be00 fix(ALTimerTaskAddDialog): 修改添加定时任务对话框的重复选项的 Label 描述和布局 2026-03-17 14:33:37 +08:00
KenanZhu 9accf5ddc1 ci(workflows): 添加 push 触发器 2026-03-16 21:20:54 +08:00
KenanZhu 60e055f6bb docs(readme): 添加 build-test 状态图标 2026-03-16 17:08:47 +08:00
Kenan Zhu cf8493565e ci(workflows): 修改一些字符格式 (#2) 2026-03-16 16:40:13 +08:00
9 changed files with 217 additions and 103 deletions
+4
View File
@@ -4,6 +4,10 @@ name: Build Test
# It is triggered when a pull request is opened, synchronized, or reopened against the main branch.
on:
push:
branches:
- main
pull_request:
branches:
- main
+2 -2
View File
@@ -40,9 +40,9 @@ name: Release
# and create a new release branch.
on:
create:
push:
branches:
- 'release/**'
- 'release/v*'
jobs:
#
+2 -1
View File
@@ -6,7 +6,8 @@
[![GitHub stars](https://img.shields.io/github/stars/KenanZhu/AutoLibrary.svg?style=social&label=Star)](https://github.com/KenanZhu/AutoLibrary)
![License](https://img.shields.io/github/license/KenanZhu/AutoLibrary?label=license)
[![Build](https://img.shields.io/github/actions/workflow/status/KenanZhu/AutoLibrary/release.yml?label=release&logo=github-actions&logoColor=white)](https://github.com/KenanZhu/AutoLibrary/actions/workflows/release.yml)
[![Build](https://img.shields.io/github/actions/workflow/status/KenanZhu/AutoLibrary/build-test.yml?label=build-test&logo=github-actions&logoColor=white)](https://github.com/KenanZhu/AutoLibrary/actions/workflows/build-test.yml)
[![Release](https://img.shields.io/github/actions/workflow/status/KenanZhu/AutoLibrary/release.yml?label=release&logo=github-actions&logoColor=white)](https://github.com/KenanZhu/AutoLibrary/actions/workflows/release.yml)
[![Release](https://img.shields.io/github/v/release/KenanZhu/AutoLibrary?label=latest&logo=github&logoColor=white)](https://github.com/KenanZhu/AutoLibrary/releases/latest)
![Downloads](https://img.shields.io/github/downloads/KenanZhu/AutoLibrary/total?label=downloads)
+8 -8
View File
@@ -27,6 +27,7 @@ class ALTimerTaskStatus(Enum):
EXECUTED = "已执行"
ERROR = "执行失败"
OUTDATED = "已过期"
UNKNOWN = "未知"
class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
@@ -60,28 +61,28 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
self.TimerConfigLayout.addWidget(self.SpecificTimerWidget)
self.RelativeTimerWidget = QWidget()
self.RelativeTimerLayout = QGridLayout(self.RelativeTimerWidget)
self.RelativeTimerLayout.addWidget(QLabel("相对时间:"), 0, 0)
self.RelativeTimerLayout = QHBoxLayout(self.RelativeTimerWidget)
self.RelativeTimerLayout.addWidget(QLabel("相对时间:"))
self.RelativeDaySpinBox = QSpinBox()
self.RelativeDaySpinBox.setMinimum(0)
self.RelativeDaySpinBox.setMaximum(365)
self.RelativeDaySpinBox.setMaximum(364)
self.RelativeDaySpinBox.setSuffix("")
self.RelativeTimerLayout.addWidget(self.RelativeDaySpinBox, 1, 0)
self.RelativeTimerLayout.addWidget(self.RelativeDaySpinBox)
self.RelativeHourSpinBox = QSpinBox()
self.RelativeHourSpinBox.setMinimum(0)
self.RelativeHourSpinBox.setMaximum(23)
self.RelativeHourSpinBox.setSuffix("")
self.RelativeTimerLayout.addWidget(self.RelativeHourSpinBox, 1, 1)
self.RelativeTimerLayout.addWidget(self.RelativeHourSpinBox)
self.RelativeMinuteSpinBox = QSpinBox()
self.RelativeMinuteSpinBox.setMinimum(0)
self.RelativeMinuteSpinBox.setMaximum(59)
self.RelativeMinuteSpinBox.setSuffix("")
self.RelativeTimerLayout.addWidget(self.RelativeMinuteSpinBox, 1, 2)
self.RelativeTimerLayout.addWidget(self.RelativeMinuteSpinBox)
self.RelativeSecondSpinBox = QSpinBox()
self.RelativeSecondSpinBox.setMinimum(0)
self.RelativeSecondSpinBox.setMaximum(59)
self.RelativeSecondSpinBox.setSuffix("")
self.RelativeTimerLayout.addWidget(self.RelativeSecondSpinBox, 1, 3)
self.RelativeTimerLayout.addWidget(self.RelativeSecondSpinBox)
self.TimerConfigLayout.addWidget(self.RelativeTimerWidget)
self.RelativeTimerWidget.setVisible(False)
@@ -128,7 +129,6 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
"status": ALTimerTaskStatus.PENDING,
"executed": False,
"repeat": self.RepeatCheckBox.isChecked(),
"repeat_records": []
}
if task_data["repeat"]:
repeat_days = []
+56 -33
View File
@@ -12,9 +12,12 @@ from datetime import datetime
from PySide6.QtCore import Slot, Qt
from PySide6.QtWidgets import (
QDialog, QTableWidget, QTableWidgetItem,
QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QHeaderView
QVBoxLayout, QHBoxLayout, QGridLayout,
QPushButton, QLabel, QHeaderView
)
from gui.ALTimerTaskAddDialog import ALTimerTaskStatus
class ALTimerTaskHistoryDialog(QDialog):
@@ -30,85 +33,105 @@ class ALTimerTaskHistoryDialog(QDialog):
self.__history = task_data.get("history", [])
self.modifyUi()
self.connectSignals()
def modifyUi(
self
):
self.setWindowTitle("定时任务执行历史 - AutoLibrary")
self.setMinimumSize(600, 400)
self.setMinimumSize(300, 300)
self.setMaximumSize(500, 400)
MainLayout = QVBoxLayout(self)
InfoLayout = QHBoxLayout()
InfoLayout = QGridLayout()
TaskNameLabel = QLabel(f"任务: {self.__task_data.get('name', '未命名')}")
TaskNameLabel.setStyleSheet("font-weight: bold; font-size: 14px;")
InfoLayout.addWidget(TaskNameLabel)
InfoLayout.addStretch()
InfoLayout.addWidget(TaskNameLabel, 0, 0)
TaskUUIDLabel = QLabel(f"UUID: {self.__task_data.get('task_uuid', '未命名')}")
TaskUUIDLabel.setStyleSheet("font-size: 10px;")
InfoLayout.addWidget(TaskUUIDLabel, 1, 0)
InfoLayout.setColumnStretch(0, 1)
if self.__task_data.get("repeat", False):
repeat_label = QLabel("重复任务")
repeat_label.setStyleSheet("color: #2294FF; font-weight: bold;")
InfoLayout.addWidget(repeat_label)
RepeatLabel = QLabel("重复任务")
RepeatLabel.setStyleSheet("color: #2294FF; font-weight: bold; font-size: 12px;")
InfoLayout.addWidget(RepeatLabel, 0, 1)
MainLayout.addLayout(InfoLayout)
self.HistoryTableWidget = QTableWidget()
self.HistoryTableWidget.setColumnCount(4)
self.HistoryTableWidget.setHorizontalHeaderLabels(["执行时间", "结果", "耗时(秒/s", "uuid"])
self.HistoryTableWidget.setColumnCount(3)
self.HistoryTableWidget.setHorizontalHeaderLabels(["执行时间", "结果", "耗时(秒/s"])
self.HistoryTableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch)
self.HistoryTableWidget.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
self.HistoryTableWidget.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
self.HistoryTableWidget.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
self.HistoryTableWidget.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch)
self.HistoryTableWidget.verticalHeader().setVisible(False)
self.HistoryTableWidget.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
self.HistoryTableWidget.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
self._loadHistory()
self.loadHistory()
MainLayout.addWidget(self.HistoryTableWidget)
ButtonLayout = QHBoxLayout()
ButtonLayout.addStretch()
self.CloseButton = QPushButton("关闭")
self.CloseButton.setFixedSize(80, 25)
self.CloseButton.clicked.connect(self.accept)
self.CloseButton.setDefault(True)
self.ClearHistoryButton = QPushButton("清空历史")
self.ClearHistoryButton.setFixedSize(80, 25)
self.ClearHistoryButton.clicked.connect(self._clearHistory)
self.ClearHistoryButton.setStyleSheet("color: #DC0000;")
ButtonLayout.addWidget(self.ClearHistoryButton)
ButtonLayout.addWidget(self.CloseButton)
MainLayout.addLayout(ButtonLayout)
def _loadHistory(
def connectSignals(
self
):
self.CloseButton.clicked.connect(self.accept)
self.ClearHistoryButton.clicked.connect(self.onClearHistoryButtonClicked)
def loadHistory(
self
):
self.HistoryTableWidget.setRowCount(len(self.__history))
for row, record in enumerate(self.__history):
self._addHistoryRow(row, record)
self.addHistoryRow(row, record)
def _addHistoryRow(
def addHistoryRow(
self,
row: int,
record: dict
):
execute_time_str = record.get("execute_time", "")
result = record.get("result", "未知")
execute_time = record.get("execute_time", "")
result = record.get("result", ALTimerTaskStatus.UNKNOWN)
duration = record.get("duration", 0)
uuid = record.get("uuid", "")
self.HistoryTableWidget.setItem(row, 0, QTableWidgetItem(execute_time_str))
self.HistoryTableWidget.setItem(row, 1, QTableWidgetItem(result))
duration_item = QTableWidgetItem(f"{duration:.2f}")
duration_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.HistoryTableWidget.setItem(row, 2, duration_item)
self.HistoryTableWidget.setItem(row, 3, QTableWidgetItem(uuid))
if result == "成功":
self.HistoryTableWidget.item(row, 1).setForeground(Qt.GlobalColor.green)
elif result == "失败":
self.HistoryTableWidget.item(row, 1).setForeground(Qt.GlobalColor.red)
ExecuteTimeItem = QTableWidgetItem(execute_time)
ExecuteTimeItem.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.HistoryTableWidget.setItem(row, 0, ExecuteTimeItem)
ResultItem = QTableWidgetItem(result.value)
ResultItem.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
match result:
case ALTimerTaskStatus.EXECUTED:
ResultItem.setForeground(Qt.GlobalColor.green)
case ALTimerTaskStatus.ERROR:
ResultItem.setForeground(Qt.GlobalColor.red)
case ALTimerTaskStatus.OUTDATED:
ResultItem.setForeground(Qt.GlobalColor.red)
case _:
ResultItem.setForeground(Qt.GlobalColor.black)
self.HistoryTableWidget.setItem(row, 1, ResultItem)
DurationItem = QTableWidgetItem(f"{duration:.2f}")
DurationItem.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.HistoryTableWidget.setItem(row, 2, DurationItem)
self.HistoryTableWidget.setRowHeight(row, 25)
@Slot()
def _clearHistory(
def onClearHistoryButtonClicked(
self
):
+131 -55
View File
@@ -21,8 +21,6 @@ from PySide6.QtWidgets import (
QDialog, QWidget, QListWidgetItem, QMessageBox,
QHBoxLayout, QVBoxLayout, QLabel, QPushButton
)
import gui.ALTimerTaskHistoryDialog as ALTimerTaskHistoryDialog
from PySide6.QtGui import (
QCloseEvent
)
@@ -32,6 +30,7 @@ import utils.TimerUtils as TimerUtils
from gui.resources.ui.Ui_ALTimerTaskManageWidget import Ui_ALTimerTaskManageWidget
from gui.ALTimerTaskAddDialog import ALTimerTaskAddDialog, ALTimerTaskStatus
from gui.ALTimerTaskHistoryDialog import ALTimerTaskHistoryDialog
class ALTimerTaskItemWidget(QWidget):
@@ -67,20 +66,22 @@ class ALTimerTaskItemWidget(QWidget):
ExecuteTimeStr = self.__timer_task["execute_time"].strftime("%Y-%m-%d %H:%M:%S")
if self.__timer_task.get("repeat", False):
repeat_days = self.__timer_task.get("repeat_days", [])
repeat_hour = self.__timer_task.get("repeat_hour", 0)
repeat_minute = self.__timer_task.get("repeat_minute", 0)
repeat_second = self.__timer_task.get("repeat_second", 0)
if len(repeat_days) == 7:
time_str = f"{self.__timer_task.get('repeat_hour', 0):02d}:{self.__timer_task.get('repeat_minute', 0):02d}:{self.__timer_task.get('repeat_second', 0):02d}"
time_str = f"{repeat_hour:02d}:{repeat_minute:02d}:{repeat_second:02d}"
ExecuteTimeLabel = QLabel(f"下次执行时间: {ExecuteTimeStr} (每日 {time_str})")
else:
day_names = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
selected_days = [day_names[d] for d in repeat_days]
time_str = f"{self.__timer_task.get('repeat_hour', 0):02d}:{self.__timer_task.get('repeat_minute', 0):02d}:{self.__timer_task.get('repeat_second', 0):02d}"
time_str = f"{repeat_hour:02d}:{repeat_minute:02d}:{repeat_second:02d}"
ExecuteTimeLabel = QLabel(f"下次执行时间: {ExecuteTimeStr} (每{','.join(selected_days)} {time_str})")
else:
ExecuteTimeLabel = QLabel(f"执行时间: {ExecuteTimeStr}")
ExecuteTimeLabel.setStyleSheet("color: #969696;")
ExecuteTimeLabel.setFixedHeight(20)
self.TaskInfoLayout.addWidget(ExecuteTimeLabel)
self.ItemWidgetLayout.addLayout(self.TaskInfoLayout)
self.ItemWidgetLayout.addStretch()
@@ -131,16 +132,17 @@ class ALTimerTaskItemWidget(QWidget):
TaskModeLabel.setFixedSize(60, 25)
self.ItemWidgetLayout.addWidget(TaskModeLabel)
self.DeleteButton = QPushButton("删除")
self.DeleteButton.setFixedSize(80, 25)
self.ItemWidgetLayout.addWidget(self.DeleteButton)
if self.__timer_task["status"] == ALTimerTaskStatus.READY\
or self.__timer_task["status"] == ALTimerTaskStatus.RUNNING:
self.DeleteButton.setEnabled(False)
if self.__timer_task.get("repeat", False):
self.HistoryButton = QPushButton("历史")
self.HistoryButton.setFixedSize(80, 25)
self.ItemWidgetLayout.addWidget(self.HistoryButton)
self.DeleteButton = QPushButton("删除")
self.DeleteButton.setFixedSize(80, 25)
self.DeleteButton.setStyleSheet("color: #DC0000;")
self.ItemWidgetLayout.addWidget(self.DeleteButton)
if self.__timer_task["status"] == ALTimerTaskStatus.READY\
or self.__timer_task["status"] == ALTimerTaskStatus.RUNNING:
self.DeleteButton.setEnabled(False)
self.setFixedHeight(55)
@@ -222,6 +224,9 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
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"] = ALTimerTaskStatus(task["status"])
if "history" in task:
for item in task["history"]:
item["result"] = ALTimerTaskStatus(item["result"])
return timer_tasks["timer_tasks"]
raise Exception("定时任务配置文件格式错误")
except Exception as e:
@@ -243,6 +248,9 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
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
if "history" in task:
for item in task["history"]:
item["result"] = item["result"].value
self.__cfg_mgr.set(ConfigManager.ConfigType.TIMERTASK, "", { "timer_tasks": timer_tasks })
return True
except Exception as e:
@@ -349,7 +357,7 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
item.setData(Qt.UserRole, timer_task)
widget = ALTimerTaskItemWidget(self, timer_task)
widget.DeleteButton.clicked.connect(
lambda _, uuid = timer_task["task_uuid"]: self.deleteTask(uuid)
lambda _, task = timer_task: self.deleteTask(task)
)
if timer_task.get("repeat", False) and hasattr(widget, "HistoryButton"):
widget.HistoryButton.clicked.connect(
@@ -371,11 +379,42 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.timerTasksChanged.emit()
def deleteTask(
self,
task_uuid: str
@staticmethod
def getTimerTaskDetailMessage(
timer_task: dict
):
return (
f"任务名称:{timer_task["name"]}\n"
f"添加时间:{timer_task["add_time"]}\n"
f"当前状态:{timer_task["status"].value}\n"
f"下次执行时间:{datetime.strftime(timer_task["execute_time"], "%Y-%m-%d %H:%M:%S")}\n"
f"已执行次数:{len(timer_task['history'] if 'history' in timer_task else 0)}"
)
def deleteTask(
self,
timer_task: dict
):
if timer_task["repeat"]: # when delete a repeat task
msgbox = QMessageBox(self)
msgbox.setIcon(QMessageBox.Icon.Question)
msgbox.setWindowTitle("警告 - AutoLibrary")
msgbox.setStandardButtons(
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
msgbox.setText("删除可重复性任务将同时删除所有已执行的记录 !\n是否继续 ?")
msgbox.setDetailedText(
"以下可重复性任务将被删除:\n"\
"\n"
f"{self.getTimerTaskDetailMessage(timer_task)}"
)
result = msgbox.exec()
if result != QMessageBox.StandardButton.Yes:
return
task_uuid = timer_task["task_uuid"]
self.__timer_tasks = [
x for x in self.__timer_tasks
if x["task_uuid"] != task_uuid
@@ -395,8 +434,9 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
"是否要清除所有定时任务 ?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if result is QMessageBox.StandardButton.No:
if result == QMessageBox.StandardButton.No:
return
# READY and RUNNING tasks cannot be cleared
in_queue_tasks = [
x for x in self.__timer_tasks
if x["status"] == ALTimerTaskStatus.READY
@@ -407,9 +447,40 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
QMessageBox.warning(
self,
"警告 - AutoLibrary",
"存在正在执行或已就绪的队列任务,无法清除所有定时任务 !"
f"存在 {in_queue_count}正在执行或已就绪的队列任务,无法清除所有定时任务 !"
)
self.__timer_tasks = in_queue_tasks
return
# repeat tasks ask before clear
repeat_tasks = [
x for x in self.__timer_tasks
if x.get("repeat", False)
]
repeat_tasks_count = len(repeat_tasks)
if repeat_tasks_count > 0:
msgbox = QMessageBox(self)
msgbox.setIcon(QMessageBox.Icon.Question)
msgbox.setWindowTitle("警告 - AutoLibrary")
msgbox.setStandardButtons(
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
msgbox.setText(
f"存在 {repeat_tasks_count} 个可重复性任务,\n"
"删除可重复性任务将同时删除所有已执行的记录 !\n"
"是否继续 ?"
)
delete_msgs = [
self.getTimerTaskDetailMessage(x) for x in repeat_tasks
]
msgbox.setDetailedText(
"以下可重复性任务将被删除:\n"\
"\n"
f"{"\n\n".join(delete_msgs)}"
)
result = msgbox.exec()
if result != QMessageBox.StandardButton.Yes:
return
# clear all tasks
self.__timer_tasks.clear()
self.timerTasksChanged.emit()
@@ -418,7 +489,7 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
task: dict
):
dialog = ALTimerTaskHistoryDialog.ALTimerTaskHistoryDialog(self, task)
dialog = ALTimerTaskHistoryDialog(self, task)
if dialog.exec() == QDialog.DialogCode.Accepted:
self.timerTasksChanged.emit()
@@ -436,7 +507,10 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
if timer_task["status"] is not ALTimerTaskStatus.PENDING:
continue
if timer_task["execute_time"] <= now + timedelta(seconds = -5):
timer_task["status"] = ALTimerTaskStatus.OUTDATED
if timer_task.get("repeat", False):
self.onRepeatTimerTaskIs(ALTimerTaskStatus.OUTDATED, timer_task)
else:
timer_task["status"] = ALTimerTaskStatus.OUTDATED
need_update = True
else:
timer_task["status"] = ALTimerTaskStatus.READY
@@ -491,9 +565,40 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
for task in self.__timer_tasks:
if task["task_uuid"] == timer_task["task_uuid"]:
task["status"] = ALTimerTaskStatus.RUNNING
break
self.timerTasksChanged.emit()
def onRepeatTimerTaskIs(
self,
status: ALTimerTaskStatus,
timer_task: dict
) -> dict:
if "history" not in timer_task:
timer_task["history"] = []
executed_time = datetime.now()
duration = (executed_time - timer_task["execute_time"]).total_seconds()
timer_task["history"].append({
"execute_time": timer_task["execute_time"].strftime("%Y-%m-%d %H:%M:%S"),
"executed_time": executed_time.strftime("%Y-%m-%d %H:%M:%S"),
"result": status,
"duration": duration if status is ALTimerTaskStatus.EXECUTED else 0,
"uuid": timer_task["task_uuid"]
})
next_time = TimerUtils.calculateNextRepeatTime(
timer_task["repeat_days"],
timer_task["repeat_hour"],
timer_task["repeat_minute"],
timer_task["repeat_second"]
)
if next_time:
timer_task["execute_time"] = next_time
timer_task["status"] = ALTimerTaskStatus.PENDING
timer_task["executed"] = False
else:
timer_task["status"] = status
@Slot(dict)
def onTimerTaskIsExecuted(
self,
@@ -503,31 +608,10 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
for task in self.__timer_tasks:
if task["task_uuid"] == timer_task["task_uuid"]:
if task.get("repeat", False):
if "history" not in task:
task["history"] = []
executed_time = datetime.now()
duration = (executed_time - task["execute_time"]).total_seconds()
task["history"].append({
"execute_time": task["execute_time"].strftime("%Y-%m-%d %H:%M:%S"),
"executed_time": executed_time.strftime("%Y-%m-%d %H:%M:%S"),
"result": "成功",
"duration": duration,
"uuid": timer_task["task_uuid"]
})
next_time = TimerUtils.calculateNextRepeatTime(
task["repeat_days"],
task["repeat_hour"],
task["repeat_minute"],
task["repeat_second"]
)
if next_time:
task["execute_time"] = next_time
task["status"] = ALTimerTaskStatus.PENDING
task["executed"] = False
else:
task["status"] = ALTimerTaskStatus.EXECUTED
self.onRepeatTimerTaskIs(ALTimerTaskStatus.EXECUTED, task)
else:
task["status"] = ALTimerTaskStatus.EXECUTED
break
self.timerTasksChanged.emit()
@Slot(dict)
@@ -539,16 +623,8 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
for task in self.__timer_tasks:
if task["task_uuid"] == timer_task["task_uuid"]:
if task.get("repeat", False):
if "history" not in task:
task["history"] = []
executed_time = datetime.now()
duration = (executed_time - task["execute_time"]).total_seconds()
task["history"].append({
"execute_time": task["execute_time"].strftime("%Y-%m-%d %H:%M:%S"),
"executed_time": executed_time.strftime("%Y-%m-%d %H:%M:%S"),
"result": "失败",
"duration": duration,
"uuid": timer_task["task_uuid"]
})
task["status"] = ALTimerTaskStatus.ERROR
self.onRepeatTimerTaskIs(ALTimerTaskStatus.ERROR, task)
else:
task["status"] = ALTimerTaskStatus.ERROR
break
self.timerTasksChanged.emit()
+5
View File
@@ -195,6 +195,11 @@
<height>25</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
color: #DC0000;
}</string>
</property>
<property name="text">
<string>删除用户</string>
</property>
+2 -2
View File
@@ -254,12 +254,12 @@
</size>
</property>
<property name="text">
<string>重复周期(全选为每日运行):</string>
<string>重复周期(全选或全不选都为每日运行):</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="RepeatCheckBoxLayout">
<layout class="QGridLayout" name="RepeatCheckBoxLayout" rowstretch="10,10" columnstretch="0,0,0,0" rowminimumheight="25,25">
<property name="spacing">
<number>0</number>
</property>
@@ -6,13 +6,13 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<width>500</width>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<width>500</width>
<height>400</height>
</size>
</property>
@@ -306,6 +306,11 @@
<height>25</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
color: #DC0000;
}</string>
</property>
<property name="text">
<string>清除全部</string>
</property>