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

feat(ALTimerTask*): 实现定时任务编辑功能,统一代码规范并重命名重复任务历史字段

This commit is contained in:
2026-05-09 10:07:25 +08:00
parent 46b3447d1e
commit 27250dba2f
6 changed files with 344 additions and 223 deletions
+111 -91
View File
@@ -8,7 +8,7 @@ You may use, modify, and distribute this file under the terms of the MIT License
See the LICENSE file for details. See the LICENSE file for details.
""" """
from PySide6.QtCore import QTime, QDate from PySide6.QtCore import QTime, QDate, Slot
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
QDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QComboBox, QPushButton, QScrollArea, QTimeEdit, QComboBox, QPushButton, QScrollArea, QTimeEdit,
@@ -21,18 +21,15 @@ from utils.AutoScriptEngine import AutoScriptEngine
VARIABLE_META = AutoScriptEngine.VARIABLE_META VARIABLE_META = AutoScriptEngine.VARIABLE_META
_VAR_COMBO_ITEMS = [ _VAR_COMBO_ITEMS = [
(display, varname, vartype) (display, varname, vartype)
for display, (varname, vartype) in VARIABLE_META.items() for display, (varname, vartype) in VARIABLE_META.items()
] ]
_VAR_COMBO_ITEMS_SET = [ _VAR_COMBO_ITEMS_SET = [
(display, varname, vartype) (display, varname, vartype)
for display, (varname, vartype) in VARIABLE_META.items() for display, (varname, vartype) in VARIABLE_META.items()
if not varname.startswith("CURRENT_") if not varname.startswith("CURRENT_")
] ]
OP_ITEMS = [ OP_ITEMS = [
("等于", ".EQ."), ("等于", ".EQ."),
("不等于", ".NEQ."), ("不等于", ".NEQ."),
@@ -298,7 +295,7 @@ class ActionStepFrame(QFrame):
self.setupUi() self.setupUi()
self.connectSignals() self.connectSignals()
self._onTargetChanged(0) self.onTargetChanged(0)
def setupUi( def setupUi(
@@ -316,7 +313,7 @@ class ActionStepFrame(QFrame):
self.targetCombo = _makeSetVarCombo() self.targetCombo = _makeSetVarCombo()
self.valueWidgetStack = QStackedWidget() self.valueWidgetStack = QStackedWidget()
self.valueWidgetStack.setFixedHeight(25) self.valueWidgetStack.setFixedHeight(25)
self._initValueStack() self.initValueStack()
setLabel = QLabel("设置") setLabel = QLabel("设置")
setLabel.setFixedHeight(25) setLabel.setFixedHeight(25)
@@ -337,9 +334,10 @@ class ActionStepFrame(QFrame):
self self
): ):
self.targetCombo.currentIndexChanged.connect(self._onTargetChanged) self.targetCombo.currentIndexChanged.connect(self.onTargetChanged)
def _initValueStack(
def initValueStack(
self self
): ):
@@ -353,18 +351,6 @@ class ActionStepFrame(QFrame):
self._valueWidgets.get("String", self.valueWidgetStack.widget(0)) self._valueWidgets.get("String", self.valueWidgetStack.widget(0))
) )
def _onTargetChanged(
self,
idx
):
if idx < 0:
return
data = self.targetCombo.itemData(idx)
if data:
_, vartype = data
w = self._valueWidgets.get(vartype)
if w:
self.valueWidgetStack.setCurrentWidget(w)
def getTarget( def getTarget(
self self
@@ -373,6 +359,7 @@ class ActionStepFrame(QFrame):
data = self.targetCombo.currentData() data = self.targetCombo.currentData()
return data[0] if data else "" return data[0] if data else ""
def getTargetType( def getTargetType(
self self
) -> str: ) -> str:
@@ -380,6 +367,7 @@ class ActionStepFrame(QFrame):
data = self.targetCombo.currentData() data = self.targetCombo.currentData()
return data[1] if data else "String" return data[1] if data else "String"
def getValueRaw( def getValueRaw(
self self
) -> str: ) -> str:
@@ -390,6 +378,7 @@ class ActionStepFrame(QFrame):
return _getValueFromWidget(w) return _getValueFromWidget(w)
return "" return ""
def toScriptLine( def toScriptLine(
self self
) -> str: ) -> str:
@@ -405,6 +394,7 @@ class ActionStepFrame(QFrame):
return f" {target} .ADD. {hours}" return f" {target} .ADD. {hours}"
return f" SET {target} = {encoded}" return f" SET {target} = {encoded}"
def loadFromScript( def loadFromScript(
self, self,
targetVar: str, targetVar: str,
@@ -416,9 +406,10 @@ class ActionStepFrame(QFrame):
if data and data[0] == targetVar: if data and data[0] == targetVar:
self.targetCombo.setCurrentIndex(idx) self.targetCombo.setCurrentIndex(idx)
break break
self._setValueFromExpr(valueExpr) self.setValueFromExpr(valueExpr)
def _setValueFromExpr(
def setValueFromExpr(
self, self,
expr: str expr: str
): ):
@@ -429,6 +420,20 @@ class ActionStepFrame(QFrame):
return return
_setWidgetValue(w, targetType, expr) _setWidgetValue(w, targetType, expr)
@Slot(int)
def onTargetChanged(
self,
idx
):
if idx < 0:
return
data = self.targetCombo.itemData(idx)
if data:
_, vartype = data
w = self._valueWidgets.get(vartype)
if w:
self.valueWidgetStack.setCurrentWidget(w)
class ConditionalBlock(QGroupBox): class ConditionalBlock(QGroupBox):
@@ -444,7 +449,7 @@ class ConditionalBlock(QGroupBox):
self.setupUi() self.setupUi()
self.connectSignals() self.connectSignals()
self._onOperandChanged(0) self.onOperandChanged(0)
def setupUi( def setupUi(
@@ -453,7 +458,7 @@ class ConditionalBlock(QGroupBox):
self.setStyleSheet( self.setStyleSheet(
"QGroupBox { font-weight: bold; border: 1px solid #ccc; " "QGroupBox { font-weight: bold; border: 1px solid #ccc; "
"margin-top: 8px; padding-top: 8px; }" "margin-top: 5px; padding-top: 5px; }"
) )
self.setSizePolicy( self.setSizePolicy(
QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred,
@@ -522,41 +527,12 @@ class ConditionalBlock(QGroupBox):
self self
): ):
self.operandCombo.currentIndexChanged.connect(self._onOperandChanged) self.operandCombo.currentIndexChanged.connect(self.onOperandChanged)
self.typeCombo.currentIndexChanged.connect(self._onTypeChanged) self.typeCombo.currentIndexChanged.connect(self.onTypeChanged)
self.addActionBtn.clicked.connect(self._addActionStep) self.addActionBtn.clicked.connect(self.addActionStep)
def _onOperandChanged(
self,
idx
):
if idx < 0:
return
data = self.operandCombo.itemData(idx)
if data:
_, vartype = data
w = self._condValueWidgets.get(vartype)
if w:
self.condValueStack.setCurrentWidget(w)
def _onTypeChanged( def removeActionStep(
self,
idx
):
isCond = self.typeCombo.currentData() in ("IF", "ELSE IF")
self.conditionWidget.setVisible(isCond)
self.actionLabel.setText("执行步骤:" if isCond else "ELSE 执行步骤:")
def _addActionStep(
self
):
step = ActionStepFrame(self)
step.deleteBtn.clicked.connect(lambda: self._removeActionStep(step))
self._actionWidgets.append(step)
self.actionsLayout.addWidget(step)
def _removeActionStep(
self, self,
step: ActionStepFrame step: ActionStepFrame
): ):
@@ -567,12 +543,14 @@ class ConditionalBlock(QGroupBox):
step.hide() step.hide()
step.deleteLater() step.deleteLater()
def getBlockType( def getBlockType(
self self
) -> str: ) -> str:
return self.typeCombo.currentData() return self.typeCombo.currentData()
def toScriptLines( def toScriptLines(
self self
) -> list: ) -> list:
@@ -602,6 +580,7 @@ class ConditionalBlock(QGroupBox):
return lines return lines
def getConditionSummary( def getConditionSummary(
self self
) -> str: ) -> str:
@@ -617,6 +596,7 @@ class ConditionalBlock(QGroupBox):
rawVal = self.getConditionRawValuePreview() rawVal = self.getConditionRawValuePreview()
return f"{bt} ({operandDisplay} {opDisplay} {rawVal})" return f"{bt} ({operandDisplay} {opDisplay} {rawVal})"
def getConditionRawValuePreview( def getConditionRawValuePreview(
self self
) -> str: ) -> str:
@@ -630,12 +610,46 @@ class ConditionalBlock(QGroupBox):
return _getValueFromWidget(w) return _getValueFromWidget(w)
return "" return ""
def countActionSteps( def countActionSteps(
self self
) -> int: ) -> int:
return len(self._actionWidgets) return len(self._actionWidgets)
@Slot(int)
def onOperandChanged(
self,
idx
):
if idx < 0:
return
data = self.operandCombo.itemData(idx)
if data:
_, vartype = data
w = self._condValueWidgets.get(vartype)
if w:
self.condValueStack.setCurrentWidget(w)
@Slot(int)
def onTypeChanged(
self,
idx
):
isCond = self.typeCombo.currentData() in ("IF", "ELSE IF")
self.conditionWidget.setVisible(isCond)
self.actionLabel.setText("执行步骤:" if isCond else "ELSE 执行步骤:")
@Slot()
def addActionStep(
self
):
step = ActionStepFrame(self)
step.deleteBtn.clicked.connect(lambda: self.removeActionStep(step))
self._actionWidgets.append(step)
self.actionsLayout.addWidget(step)
class ALAutoScriptOrchDialog(QDialog): class ALAutoScriptOrchDialog(QDialog):
@@ -651,9 +665,9 @@ class ALAutoScriptOrchDialog(QDialog):
self.connectSignals() self.connectSignals()
if existingScript and existingScript.strip(): if existingScript and existingScript.strip():
self._loadFromScript(existingScript) self.loadFromScript(existingScript)
else: else:
self._addBlock() self.addBlock()
self._scrollLayout.addStretch() self._scrollLayout.addStretch()
@@ -695,28 +709,10 @@ class ALAutoScriptOrchDialog(QDialog):
self.btnBox.accepted.connect(self.accept) self.btnBox.accepted.connect(self.accept)
self.btnBox.rejected.connect(self.reject) self.btnBox.rejected.connect(self.reject)
self.addBlockBtn.clicked.connect(self._addBlock) self.addBlockBtn.clicked.connect(self.addBlock)
def _addBlock(
self
):
block = ConditionalBlock(len(self._blocks), self) def removeBlock(
block.deleteBlockBtn.clicked.connect(lambda: self._removeBlock(block))
self._blocks.append(block)
block._addActionStep()
if self._scrollLayout.count() > 0:
lastItem = self._scrollLayout.itemAt(
self._scrollLayout.count() - 1
)
if lastItem and lastItem.spacerItem():
self._scrollLayout.insertWidget(
self._scrollLayout.count() - 1, block
)
return
self._scrollLayout.addWidget(block)
def _removeBlock(
self, self,
block: ConditionalBlock block: ConditionalBlock
): ):
@@ -727,6 +723,7 @@ class ALAutoScriptOrchDialog(QDialog):
block.hide() block.hide()
block.deleteLater() block.deleteLater()
def getScript( def getScript(
self self
) -> str: ) -> str:
@@ -742,6 +739,7 @@ class ALAutoScriptOrchDialog(QDialog):
parts.append("ENDIF") parts.append("ENDIF")
return "\n".join(parts) return "\n".join(parts)
def getScriptPreview( def getScriptPreview(
self self
) -> str: ) -> str:
@@ -751,7 +749,8 @@ class ALAutoScriptOrchDialog(QDialog):
return s[:7] + "..." return s[:7] + "..."
return s return s
def _loadFromScript(
def loadFromScript(
self, self,
script: str script: str
): ):
@@ -759,7 +758,7 @@ class ALAutoScriptOrchDialog(QDialog):
import re import re
lines = [l.strip() for l in script.split("\n") if l.strip()] lines = [l.strip() for l in script.split("\n") if l.strip()]
if not lines: if not lines:
self._addBlock() self.addBlock()
return return
currentBlock = None currentBlock = None
@@ -773,11 +772,11 @@ class ALAutoScriptOrchDialog(QDialog):
typeIdxMap = {"IF": 0, "ELSE IF": 1, "ELSE": 2} typeIdxMap = {"IF": 0, "ELSE IF": 1, "ELSE": 2}
idx = typeIdxMap.get(currentBlockType, 0) idx = typeIdxMap.get(currentBlockType, 0)
currentBlock.typeCombo.setCurrentIndex(idx) currentBlock.typeCombo.setCurrentIndex(idx)
currentBlock._onTypeChanged(idx) currentBlock.onTypeChanged(idx)
for oldStep in list(currentBlock._actionWidgets): for oldStep in list(currentBlock._actionWidgets):
currentBlock._removeActionStep(oldStep) currentBlock.removeActionStep(oldStep)
for target, valueExpr in actionsBuffer: for target, valueExpr in actionsBuffer:
currentBlock._addActionStep() currentBlock.addActionStep()
step = currentBlock._actionWidgets[-1] step = currentBlock._actionWidgets[-1]
step.loadFromScript(target, valueExpr) step.loadFromScript(target, valueExpr)
self._blocks.clear() self._blocks.clear()
@@ -792,24 +791,24 @@ class ALAutoScriptOrchDialog(QDialog):
flushBlock() flushBlock()
currentBlockType = "IF" currentBlockType = "IF"
actionsBuffer = [] actionsBuffer = []
self._addBlock() self.addBlock()
currentBlock = self._blocks[-1] currentBlock = self._blocks[-1]
self._parseConditionToBlock(currentBlock, ifMatch.group(1)) self.parseConditionToBlock(currentBlock, ifMatch.group(1))
continue continue
elifIfMatch = re.match(r"^ELSE\s+IF\((.+)\)\s*THEN\s*$", upper) elifIfMatch = re.match(r"^ELSE\s+IF\((.+)\)\s*THEN\s*$", upper)
if elifIfMatch: if elifIfMatch:
flushBlock() flushBlock()
currentBlockType = "ELSE IF" currentBlockType = "ELSE IF"
actionsBuffer = [] actionsBuffer = []
self._addBlock() self.addBlock()
currentBlock = self._blocks[-1] currentBlock = self._blocks[-1]
self._parseConditionToBlock(currentBlock, elifIfMatch.group(1)) self.parseConditionToBlock(currentBlock, elifIfMatch.group(1))
continue continue
if upper == "ELSE": if upper == "ELSE":
flushBlock() flushBlock()
currentBlockType = "ELSE" currentBlockType = "ELSE"
actionsBuffer = [] actionsBuffer = []
self._addBlock() self.addBlock()
currentBlock = self._blocks[-1] currentBlock = self._blocks[-1]
currentBlock.conditionWidget.setVisible(False) currentBlock.conditionWidget.setVisible(False)
continue continue
@@ -833,9 +832,10 @@ class ALAutoScriptOrchDialog(QDialog):
continue continue
flushBlock() flushBlock()
if not self._blocks: if not self._blocks:
self._addBlock() self.addBlock()
def _parseConditionToBlock(
def parseConditionToBlock(
self, self,
block: ConditionalBlock, block: ConditionalBlock,
condStr: str condStr: str
@@ -862,3 +862,23 @@ class ALAutoScriptOrchDialog(QDialog):
if w: if w:
_setWidgetValue(w, vartype, rightPart) _setWidgetValue(w, vartype, rightPart)
return return
@Slot()
def addBlock(
self
):
block = ConditionalBlock(len(self._blocks), self)
block.deleteBlockBtn.clicked.connect(lambda: self.removeBlock(block))
self._blocks.append(block)
block.addActionStep()
if self._scrollLayout.count() > 0:
lastItem = self._scrollLayout.itemAt(
self._scrollLayout.count() - 1
)
if lastItem and lastItem.spacerItem():
self._scrollLayout.insertWidget(
self._scrollLayout.count() - 1, block
)
return
self._scrollLayout.addWidget(block)
+47 -45
View File
@@ -8,6 +8,8 @@ You may use, modify, and distribute this file under the terms of the MIT License
See the LICENSE file for details. See the LICENSE file for details.
""" """
from PySide6.QtCore import Slot
from PySide6.QtGui import ( from PySide6.QtGui import (
QSyntaxHighlighter, QTextCharFormat, QColor, QFont, QIcon QSyntaxHighlighter, QTextCharFormat, QColor, QFont, QIcon
) )
@@ -162,53 +164,13 @@ class ALAutoScriptPreviewDialog(QDialog):
): ):
self._btnBox.rejected.connect(self.reject) self._btnBox.rejected.connect(self.reject)
self._zoomInBtn.clicked.connect(self._onZoomIn) self._zoomInBtn.clicked.connect(self.onZoomIn)
self._zoomOutBtn.clicked.connect(self._onZoomOut) self._zoomOutBtn.clicked.connect(self.onZoomOut)
self._zoomResetBtn.clicked.connect(self._onZoomReset) self._zoomResetBtn.clicked.connect(self.onZoomReset)
self._copyBtn.clicked.connect(self._onCopy) self._copyBtn.clicked.connect(self.onCopy)
def _onZoomIn( def updateFontSize(
self
):
self.__fontSize = min(self.__fontSize + 2, 40)
self._updateFontSize()
def _onZoomOut(
self
):
self.__fontSize = max(self.__fontSize - 2, 8)
self._updateFontSize()
def _onZoomReset(
self
):
self.__fontSize = 13
self._updateFontSize()
def _onCopy(
self
):
clipboard = QApplication.clipboard()
clipboard.setText(self._textEdit.toPlainText())
original = self._copyBtn.text()
self._copyBtn.setText("已复制")
self._copyBtn.setEnabled(False)
from PySide6.QtCore import QTimer
QTimer.singleShot(2000, lambda: (
self._copyBtn.setText(original),
self._copyBtn.setEnabled(True)
))
def _updateFontSize(
self self
): ):
@@ -222,3 +184,43 @@ class ALAutoScriptPreviewDialog(QDialog):
"}" "}"
) )
self._zoomLabel.setText(f"{self.__fontSize}px") self._zoomLabel.setText(f"{self.__fontSize}px")
@Slot()
def onZoomIn(
self
):
self.__fontSize = min(self.__fontSize + 2, 40)
self.updateFontSize()
@Slot()
def onZoomOut(
self
):
self.__fontSize = max(self.__fontSize - 2, 8)
self.updateFontSize()
@Slot()
def onZoomReset(
self
):
self.__fontSize = 13
self.updateFontSize()
@Slot()
def onCopy(
self
):
clipboard = QApplication.clipboard()
clipboard.setText(self._textEdit.toPlainText())
original = self._copyBtn.text()
self._copyBtn.setText("已复制")
self._copyBtn.setEnabled(False)
from PySide6.QtCore import QTimer
QTimer.singleShot(2000, lambda: (
self._copyBtn.setText(original),
self._copyBtn.setEnabled(True)
))
+10 -10
View File
@@ -174,7 +174,7 @@ class TimerTaskWorker(AutoLibWorker):
try: try:
if not self.loadConfigs(): if not self.loadConfigs():
raise Exception("配置文件加载失败") raise Exception("配置文件加载失败")
self._applyRepeatAutoScript() self.applyRepeatAutoScript()
auto_lib = AutoLib( auto_lib = AutoLib(
self._input_queue, self._input_queue,
self._output_queue, self._output_queue,
@@ -207,7 +207,7 @@ class TimerTaskWorker(AutoLibWorker):
self.timerTaskWorkerIsFinished.emit(False, self.__timer_task) self.timerTaskWorkerIsFinished.emit(False, self.__timer_task)
def _applyRepeatAutoScript( def applyRepeatAutoScript(
self self
): ):
@@ -238,6 +238,14 @@ class TimerTaskWorker(AutoLibWorker):
self.TraceLevel.INFO self.TraceLevel.INFO
) )
@Slot()
def onTimerTaskIsFinished(
self
):
self._showTrace(f"定时任务 {self.__timer_task['name']} 运行结束")
self.timerTaskWorkerIsFinished.emit(False, self.__timer_task)
@Slot() @Slot()
def onTimerTaskFinishedWithError( def onTimerTaskFinishedWithError(
self self
@@ -248,11 +256,3 @@ class TimerTaskWorker(AutoLibWorker):
self.TraceLevel.ERROR self.TraceLevel.ERROR
) )
self.timerTaskWorkerIsFinished.emit(True, self.__timer_task) self.timerTaskWorkerIsFinished.emit(True, self.__timer_task)
@Slot()
def onTimerTaskIsFinished(
self
):
self._showTrace(f"定时任务 {self.__timer_task['name']} 运行结束")
self.timerTaskWorkerIsFinished.emit(False, self.__timer_task)
+113 -54
View File
@@ -36,15 +36,20 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
def __init__( def __init__(
self, self,
parent = None parent = None,
timer_task: dict = None
): ):
super().__init__(parent) super().__init__(parent)
self.__edit_timer_task = timer_task
self.setupUi(self) self.setupUi(self)
self.modifyUi() self.modifyUi()
self.connectSignals() self.connectSignals()
if self.__edit_timer_task:
self.loadTask(self.__edit_timer_task)
def modifyUi( def modifyUi(
self self
@@ -130,6 +135,45 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
self.__auto_script = "" self.__auto_script = ""
def loadTask(
self,
task: dict
):
self.TaskNameLineEdit.setText(task.get("name", ""))
time_type = task.get("time_type", "特定时间")
self.TimerTypeComboBox.setCurrentText(time_type)
self.SpecificDateTimeEdit.setDateTime(
QDateTime(task["execute_time"])
)
self.RelativeDaySpinBox.setValue(0)
self.RelativeHourSpinBox.setValue(0)
self.RelativeMinuteSpinBox.setValue(0)
self.RelativeSecondSpinBox.setValue(0)
if task.get("silent", False):
self.SilentlyRunRadioButton.setChecked(True)
else:
self.ShowBeforeRunRadioButton.setChecked(True)
repeat = task.get("repeat", False)
self.RepeatCheckBox.setChecked(repeat)
if repeat:
repeat_days = task.get("repeat_days", [])
self.MonCheckBox.setChecked(0 in repeat_days)
self.TueCheckBox.setChecked(1 in repeat_days)
self.WedCheckBox.setChecked(2 in repeat_days)
self.ThuCheckBox.setChecked(3 in repeat_days)
self.FriCheckBox.setChecked(4 in repeat_days)
self.SatCheckBox.setChecked(5 in repeat_days)
self.SunCheckBox.setChecked(6 in repeat_days)
auto_script = task.get("repeat_auto_script", "")
if auto_script:
self.__auto_script = auto_script
self.AutoScriptStatusLabel.setText("已设置")
self.AutoScriptStatusLabel.setStyleSheet("color: #4CAF50;")
self.AutoScriptPreviewButton.setEnabled(True)
self.ConfirmButton.setText("保存")
def connectSignals( def connectSignals(
self self
): ):
@@ -138,44 +182,9 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
self.ConfirmButton.clicked.connect(self.accept) self.ConfirmButton.clicked.connect(self.accept)
self.TimerTypeComboBox.currentIndexChanged.connect(self.onTimerTypeComboBoxIndexChanged) self.TimerTypeComboBox.currentIndexChanged.connect(self.onTimerTypeComboBoxIndexChanged)
self.RepeatCheckBox.toggled.connect(self.onRepeatCheckBoxToggled) self.RepeatCheckBox.toggled.connect(self.onRepeatCheckBoxToggled)
self.AutoScriptSetButton.clicked.connect(self._onSetAutoScript) self.AutoScriptSetButton.clicked.connect(self.onSetAutoScript)
self.AutoScriptPreviewButton.clicked.connect(self._onPreviewAutoScript) self.AutoScriptPreviewButton.clicked.connect(self.onPreviewAutoScript)
self.AutoScriptHelpButton.clicked.connect(self._onAutoScriptHelp) self.AutoScriptHelpButton.clicked.connect(self.onAutoScriptHelp)
@Slot()
def _onSetAutoScript(self):
dlg = ALAutoScriptOrchDialog(self, existingScript=self.__auto_script)
if dlg.exec() == QDialog.DialogCode.Accepted:
script = dlg.getScript()
self.__auto_script = script
if script:
self.AutoScriptStatusLabel.setText("已设置")
self.AutoScriptStatusLabel.setStyleSheet("color: #4CAF50;")
self.AutoScriptPreviewButton.setEnabled(True)
else:
self.AutoScriptStatusLabel.setText("未设置")
self.AutoScriptStatusLabel.setStyleSheet("color: #969696;")
self.AutoScriptPreviewButton.setEnabled(False)
dlg.deleteLater()
@Slot()
def _onPreviewAutoScript(self):
if not self.__auto_script:
return
from gui.ALAutoScriptPrevDialog import ALAutoScriptPreviewDialog
dlg = ALAutoScriptPreviewDialog(self, self.__auto_script)
dlg.exec()
dlg.deleteLater()
@Slot()
def _onAutoScriptHelp(
self
):
QDesktopServices.openUrl(
QUrl("https://www.autolibrary.kenanzhu.com/manuals/autoscript")
)
def getTimerTask( def getTimerTask(
@@ -200,20 +209,34 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
minutes = self.RelativeMinuteSpinBox.value(), minutes = self.RelativeMinuteSpinBox.value(),
seconds = self.RelativeSecondSpinBox.value() seconds = self.RelativeSecondSpinBox.value()
) )
task_data = {
"name": name, if self.__edit_timer_task:
"uuid": uuid.uuid4().hex.upper() + f"-{added_time.strftime("%Y%m%d%H%M%S")}", task_data = dict(self.__edit_timer_task)
"time_type": self.TimerTypeComboBox.currentText(), task_data["name"] = name
"execute_time": execute_time, task_data["execute_time"] = execute_time
"silent": silent, task_data["silent"] = silent
"added_time": added_time, task_data["status"] = ALTimerTaskStatus.PENDING
"status": ALTimerTaskStatus.PENDING, task_data["executed"] = False
"executed": False, task_data["repeat_auto_script"] = self.__auto_script
"repeat": self.RepeatCheckBox.isChecked(), else:
"repeat_auto_script": self.__auto_script, task_data = {
} "name": name,
if task_data["repeat"]: "uuid": uuid.uuid4().hex.upper() + f"-{added_time.strftime("%Y%m%d%H%M%S")}",
task_data["history"] = [] # repeat history "time_type": self.TimerTypeComboBox.currentText(),
"execute_time": execute_time,
"silent": silent,
"added_time": added_time,
"status": ALTimerTaskStatus.PENDING,
"executed": False,
"repeat": self.RepeatCheckBox.isChecked(),
"repeat_auto_script": self.__auto_script,
}
repeat = self.RepeatCheckBox.isChecked()
task_data["repeat"] = repeat
if repeat:
if "repeat_history" not in task_data:
task_data["repeat_history"] = []
repeat_days = [] repeat_days = []
if self.MonCheckBox.isChecked(): if self.MonCheckBox.isChecked():
repeat_days.append(0) repeat_days.append(0)
@@ -265,4 +288,40 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
self.FriCheckBox.setEnabled(checked) self.FriCheckBox.setEnabled(checked)
self.SatCheckBox.setEnabled(checked) self.SatCheckBox.setEnabled(checked)
self.SunCheckBox.setEnabled(checked) self.SunCheckBox.setEnabled(checked)
self.AutoScriptGroupBox.setVisible(checked) self.AutoScriptGroupBox.setVisible(checked)
@Slot()
def onSetAutoScript(self):
dlg = ALAutoScriptOrchDialog(self, existingScript=self.__auto_script)
if dlg.exec() == QDialog.DialogCode.Accepted:
script = dlg.getScript()
self.__auto_script = script
if script:
self.AutoScriptStatusLabel.setText("已设置")
self.AutoScriptStatusLabel.setStyleSheet("color: #4CAF50;")
self.AutoScriptPreviewButton.setEnabled(True)
else:
self.AutoScriptStatusLabel.setText("未设置")
self.AutoScriptStatusLabel.setStyleSheet("color: #969696;")
self.AutoScriptPreviewButton.setEnabled(False)
dlg.deleteLater()
@Slot()
def onPreviewAutoScript(self):
if not self.__auto_script:
return
from gui.ALAutoScriptPrevDialog import ALAutoScriptPreviewDialog
dlg = ALAutoScriptPreviewDialog(self, self.__auto_script)
dlg.exec()
dlg.deleteLater()
@Slot()
def onAutoScriptHelp(
self
):
QDesktopServices.openUrl(
QUrl("https://www.autolibrary.kenanzhu.com/manuals/autoscript")
)
+9 -9
View File
@@ -30,7 +30,7 @@ class ALTimerTaskHistoryDialog(QDialog):
super().__init__(parent) super().__init__(parent)
self.__task_data = task_data self.__task_data = task_data
self.__history = task_data.get("history", []) self.__history = task_data.get("repeat_history", [])
self.modifyUi() self.modifyUi()
self.connectSignals() self.connectSignals()
@@ -130,6 +130,13 @@ class ALTimerTaskHistoryDialog(QDialog):
self.HistoryTableWidget.setItem(row, 2, DurationItem) self.HistoryTableWidget.setItem(row, 2, DurationItem)
self.HistoryTableWidget.setRowHeight(row, 25) self.HistoryTableWidget.setRowHeight(row, 25)
def getHistory(
self
) -> list:
return self.__history
@Slot() @Slot()
def onClearHistoryButtonClicked( def onClearHistoryButtonClicked(
self self
@@ -137,11 +144,4 @@ class ALTimerTaskHistoryDialog(QDialog):
self.__history.clear() self.__history.clear()
self.HistoryTableWidget.setRowCount(0) self.HistoryTableWidget.setRowCount(0)
self.__task_data["history"] = self.__history self.__task_data["repeat_history"] = self.__history
def getHistory(
self
) -> list:
return self.__history
+54 -14
View File
@@ -19,10 +19,10 @@ from PySide6.QtCore import (
) )
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
QDialog, QWidget, QListWidgetItem, QMessageBox, QDialog, QWidget, QListWidgetItem, QMessageBox,
QHBoxLayout, QVBoxLayout, QLabel, QPushButton QHBoxLayout, QVBoxLayout, QLabel, QPushButton, QMenu
) )
from PySide6.QtGui import ( from PySide6.QtGui import (
QCloseEvent QCloseEvent, QAction
) )
import managers.config.ConfigManager as ConfigManager import managers.config.ConfigManager as ConfigManager
@@ -35,6 +35,8 @@ from gui.ALTimerTaskHistoryDialog import ALTimerTaskHistoryDialog
class ALTimerTaskItemWidget(QWidget): class ALTimerTaskItemWidget(QWidget):
editRequested = Signal(dict)
def __init__( def __init__(
self, self,
parent = None, parent = None,
@@ -45,6 +47,8 @@ class ALTimerTaskItemWidget(QWidget):
self.__timer_task = timer_task self.__timer_task = timer_task
self.modifyUi() self.modifyUi()
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.customContextMenuRequested.connect(self.showContextMenu)
def modifyUi( def modifyUi(
@@ -145,6 +149,27 @@ class ALTimerTaskItemWidget(QWidget):
self.DeleteButton.setEnabled(False) self.DeleteButton.setEnabled(False)
self.setFixedHeight(55) self.setFixedHeight(55)
@Slot(object)
def showContextMenu(
self,
pos
):
menu = QMenu(self)
edit_action = QAction("编辑", self)
edit_action.triggered.connect(
lambda: self.editRequested.emit(self.__timer_task)
)
menu.addAction(edit_action)
if self.__timer_task["status"] != ALTimerTaskStatus.RUNNING\
and self.__timer_task["status"] != ALTimerTaskStatus.READY:
delete_action = QAction("删除", self)
delete_action.triggered.connect(
lambda: self.parent().deleteTask(self.__timer_task)
)
menu.addAction(delete_action)
menu.exec(self.mapToGlobal(pos))
class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget): class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
@@ -224,8 +249,8 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
task["added_time"] = datetime.strptime(task["added_time"], "%Y-%m-%d %H:%M:%S") task["added_time"] = datetime.strptime(task["added_time"], "%Y-%m-%d %H:%M:%S")
task["execute_time"] = datetime.strptime(task["execute_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"]) task["status"] = ALTimerTaskStatus(task["status"])
if "history" in task: if "repeat_history" in task:
for item in task["history"]: for item in task["repeat_history"]:
item["result"] = ALTimerTaskStatus(item["result"]) item["result"] = ALTimerTaskStatus(item["result"])
return timer_tasks["timer_tasks"] return timer_tasks["timer_tasks"]
raise Exception("定时任务配置文件格式错误") raise Exception("定时任务配置文件格式错误")
@@ -248,8 +273,8 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
task["added_time"] = task["added_time"].strftime("%Y-%m-%d %H:%M:%S") task["added_time"] = task["added_time"].strftime("%Y-%m-%d %H:%M:%S")
task["execute_time"] = task["execute_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 task["status"] = task["status"].value
if "history" in task: if "repeat_history" in task:
for item in task["history"]: for item in task["repeat_history"]:
item["result"] = item["result"].value item["result"] = item["result"].value
self.__cfg_mgr.set(ConfigManager.ConfigType.TIMERTASK, "", { "timer_tasks": timer_tasks }) self.__cfg_mgr.set(ConfigManager.ConfigType.TIMERTASK, "", { "timer_tasks": timer_tasks })
return True return True
@@ -363,6 +388,7 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
widget.HistoryButton.clicked.connect( widget.HistoryButton.clicked.connect(
lambda _, task = timer_task: self.showTaskHistory(task) lambda _, task = timer_task: self.showTaskHistory(task)
) )
widget.editRequested.connect(self.editTask)
item.setSizeHint(widget.size()) item.setSizeHint(widget.size())
self.TimerTasksListWidget.addItem(item) self.TimerTasksListWidget.addItem(item)
self.TimerTasksListWidget.setItemWidget(item, widget) self.TimerTasksListWidget.setItemWidget(item, widget)
@@ -378,15 +404,30 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.__timer_tasks.append(timer_task) self.__timer_tasks.append(timer_task)
self.timerTasksChanged.emit() self.timerTasksChanged.emit()
def editTask(
self,
timer_task: dict
):
dialog = ALTimerTaskAddDialog(self, timer_task)
if dialog.exec() == QDialog.DialogCode.Accepted:
updated = dialog.getTimerTask()
for i, task in enumerate(self.__timer_tasks):
if task["uuid"] == updated["uuid"]:
self.__timer_tasks[i] = updated
break
self.timerTasksChanged.emit()
@staticmethod @staticmethod
def getTimerTaskDetailMessage( def getTimerTaskDetailMessage(
timer_task: dict timer_task: dict
): ):
if "history" not in timer_task: if "repeat_history" not in timer_task:
history = [] history = []
else: else:
history = timer_task["history"] history = timer_task["repeat_history"]
history_count = len(history) history_count = len(history)
return ( return (
f"任务名称:{timer_task["name"]}\n" f"任务名称:{timer_task["name"]}\n"
@@ -395,7 +436,7 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
f"下次执行时间:{datetime.strftime(timer_task["execute_time"], "%Y-%m-%d %H:%M:%S")}\n" f"下次执行时间:{datetime.strftime(timer_task["execute_time"], "%Y-%m-%d %H:%M:%S")}\n"
f"已记录次数:{history_count}" f"已记录次数:{history_count}"
) )
def deleteTask( def deleteTask(
self, self,
@@ -559,7 +600,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.updateTimerTaskList() self.updateTimerTaskList()
self.updateStat() self.updateStat()
@Slot(dict) @Slot(dict)
def onTimerTaskIsRunning( def onTimerTaskIsRunning(
self, self,
@@ -584,12 +624,12 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
ALTimerTaskStatus.OUTDATED} ALTimerTaskStatus.OUTDATED}
if status not in valid_statuses: if status not in valid_statuses:
return timer_task return timer_task
if "history" not in timer_task: if "repeat_history" not in timer_task:
timer_task["history"] = [] timer_task["repeat_history"] = []
if status != ALTimerTaskStatus.OUTDATED: if status != ALTimerTaskStatus.OUTDATED:
executed_time = datetime.now() executed_time = datetime.now()
duration = (executed_time - timer_task["execute_time"]).total_seconds() duration = (executed_time - timer_task["execute_time"]).total_seconds()
timer_task["history"].append({ timer_task["repeat_history"].append({
"execute_time": timer_task["execute_time"].strftime("%Y-%m-%d %H:%M:%S"), "execute_time": timer_task["execute_time"].strftime("%Y-%m-%d %H:%M:%S"),
"executed_time": executed_time.strftime("%Y-%m-%d %H:%M:%S"), "executed_time": executed_time.strftime("%Y-%m-%d %H:%M:%S"),
"result": status, "result": status,
@@ -603,7 +643,7 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
delta_days = (current_time - execute_time).days delta_days = (current_time - execute_time).days
for i in range(delta_days + 1): for i in range(delta_days + 1):
if (execute_weekday + i)%7 in timer_task["repeat_days"]: if (execute_weekday + i)%7 in timer_task["repeat_days"]:
timer_task["history"].append({ timer_task["repeat_history"].append({
"execute_time": (execute_time + timedelta(days=i)).strftime("%Y-%m-%d %H:%M:%S"), "execute_time": (execute_time + timedelta(days=i)).strftime("%Y-%m-%d %H:%M:%S"),
"executed_time": (execute_time + timedelta(days=i)).strftime("%Y-%m-%d %H:%M:%S"), "executed_time": (execute_time + timedelta(days=i)).strftime("%Y-%m-%d %H:%M:%S"),
"result": status, "result": status,