From 27250dba2f1f67bee2a2c54563f2492af0cc6406 Mon Sep 17 00:00:00 2001 From: KenanZhu <3471685733@qq.com> Date: Sat, 9 May 2026 10:07:25 +0800 Subject: [PATCH] =?UTF-8?q?feat(ALTimerTask*):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E7=BC=96=E8=BE=91=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E7=BB=9F=E4=B8=80=E4=BB=A3=E7=A0=81=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E5=B9=B6=E9=87=8D=E5=91=BD=E5=90=8D=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=8E=86=E5=8F=B2=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gui/ALAutoScriptOrchDialog.py | 202 +++++++++++++++------------- src/gui/ALAutoScriptPrevDialog.py | 92 ++++++------- src/gui/ALMainWorkers.py | 20 +-- src/gui/ALTimerTaskAddDialog.py | 167 +++++++++++++++-------- src/gui/ALTimerTaskHistoryDialog.py | 18 +-- src/gui/ALTimerTaskManageWidget.py | 68 ++++++++-- 6 files changed, 344 insertions(+), 223 deletions(-) diff --git a/src/gui/ALAutoScriptOrchDialog.py b/src/gui/ALAutoScriptOrchDialog.py index 3ffa63d..d4b7e78 100644 --- a/src/gui/ALAutoScriptOrchDialog.py +++ b/src/gui/ALAutoScriptOrchDialog.py @@ -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. """ -from PySide6.QtCore import QTime, QDate +from PySide6.QtCore import QTime, QDate, Slot from PySide6.QtWidgets import ( QDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QComboBox, QPushButton, QScrollArea, QTimeEdit, @@ -21,18 +21,15 @@ from utils.AutoScriptEngine import AutoScriptEngine VARIABLE_META = AutoScriptEngine.VARIABLE_META - _VAR_COMBO_ITEMS = [ (display, varname, vartype) for display, (varname, vartype) in VARIABLE_META.items() ] - _VAR_COMBO_ITEMS_SET = [ (display, varname, vartype) for display, (varname, vartype) in VARIABLE_META.items() if not varname.startswith("CURRENT_") ] - OP_ITEMS = [ ("等于", ".EQ."), ("不等于", ".NEQ."), @@ -298,7 +295,7 @@ class ActionStepFrame(QFrame): self.setupUi() self.connectSignals() - self._onTargetChanged(0) + self.onTargetChanged(0) def setupUi( @@ -316,7 +313,7 @@ class ActionStepFrame(QFrame): self.targetCombo = _makeSetVarCombo() self.valueWidgetStack = QStackedWidget() self.valueWidgetStack.setFixedHeight(25) - self._initValueStack() + self.initValueStack() setLabel = QLabel("设置") setLabel.setFixedHeight(25) @@ -337,9 +334,10 @@ class ActionStepFrame(QFrame): self ): - self.targetCombo.currentIndexChanged.connect(self._onTargetChanged) + self.targetCombo.currentIndexChanged.connect(self.onTargetChanged) - def _initValueStack( + + def initValueStack( self ): @@ -353,18 +351,6 @@ class ActionStepFrame(QFrame): 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( self @@ -373,6 +359,7 @@ class ActionStepFrame(QFrame): data = self.targetCombo.currentData() return data[0] if data else "" + def getTargetType( self ) -> str: @@ -380,6 +367,7 @@ class ActionStepFrame(QFrame): data = self.targetCombo.currentData() return data[1] if data else "String" + def getValueRaw( self ) -> str: @@ -390,6 +378,7 @@ class ActionStepFrame(QFrame): return _getValueFromWidget(w) return "" + def toScriptLine( self ) -> str: @@ -405,6 +394,7 @@ class ActionStepFrame(QFrame): return f" {target} .ADD. {hours}" return f" SET {target} = {encoded}" + def loadFromScript( self, targetVar: str, @@ -416,9 +406,10 @@ class ActionStepFrame(QFrame): if data and data[0] == targetVar: self.targetCombo.setCurrentIndex(idx) break - self._setValueFromExpr(valueExpr) + self.setValueFromExpr(valueExpr) - def _setValueFromExpr( + + def setValueFromExpr( self, expr: str ): @@ -429,6 +420,20 @@ class ActionStepFrame(QFrame): return _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): @@ -444,7 +449,7 @@ class ConditionalBlock(QGroupBox): self.setupUi() self.connectSignals() - self._onOperandChanged(0) + self.onOperandChanged(0) def setupUi( @@ -453,7 +458,7 @@ class ConditionalBlock(QGroupBox): self.setStyleSheet( "QGroupBox { font-weight: bold; border: 1px solid #ccc; " - "margin-top: 8px; padding-top: 8px; }" + "margin-top: 5px; padding-top: 5px; }" ) self.setSizePolicy( QSizePolicy.Policy.Preferred, @@ -522,41 +527,12 @@ class ConditionalBlock(QGroupBox): self ): - self.operandCombo.currentIndexChanged.connect(self._onOperandChanged) - self.typeCombo.currentIndexChanged.connect(self._onTypeChanged) - self.addActionBtn.clicked.connect(self._addActionStep) + self.operandCombo.currentIndexChanged.connect(self.onOperandChanged) + self.typeCombo.currentIndexChanged.connect(self.onTypeChanged) + 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( - 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( + def removeActionStep( self, step: ActionStepFrame ): @@ -567,12 +543,14 @@ class ConditionalBlock(QGroupBox): step.hide() step.deleteLater() + def getBlockType( self ) -> str: return self.typeCombo.currentData() + def toScriptLines( self ) -> list: @@ -602,6 +580,7 @@ class ConditionalBlock(QGroupBox): return lines + def getConditionSummary( self ) -> str: @@ -617,6 +596,7 @@ class ConditionalBlock(QGroupBox): rawVal = self.getConditionRawValuePreview() return f"{bt} ({operandDisplay} {opDisplay} {rawVal})" + def getConditionRawValuePreview( self ) -> str: @@ -630,12 +610,46 @@ class ConditionalBlock(QGroupBox): return _getValueFromWidget(w) return "" + def countActionSteps( self ) -> int: 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): @@ -651,9 +665,9 @@ class ALAutoScriptOrchDialog(QDialog): self.connectSignals() if existingScript and existingScript.strip(): - self._loadFromScript(existingScript) + self.loadFromScript(existingScript) else: - self._addBlock() + self.addBlock() self._scrollLayout.addStretch() @@ -695,28 +709,10 @@ class ALAutoScriptOrchDialog(QDialog): self.btnBox.accepted.connect(self.accept) 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) - 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( + def removeBlock( self, block: ConditionalBlock ): @@ -727,6 +723,7 @@ class ALAutoScriptOrchDialog(QDialog): block.hide() block.deleteLater() + def getScript( self ) -> str: @@ -742,6 +739,7 @@ class ALAutoScriptOrchDialog(QDialog): parts.append("ENDIF") return "\n".join(parts) + def getScriptPreview( self ) -> str: @@ -751,7 +749,8 @@ class ALAutoScriptOrchDialog(QDialog): return s[:7] + "..." return s - def _loadFromScript( + + def loadFromScript( self, script: str ): @@ -759,7 +758,7 @@ class ALAutoScriptOrchDialog(QDialog): import re lines = [l.strip() for l in script.split("\n") if l.strip()] if not lines: - self._addBlock() + self.addBlock() return currentBlock = None @@ -773,11 +772,11 @@ class ALAutoScriptOrchDialog(QDialog): typeIdxMap = {"IF": 0, "ELSE IF": 1, "ELSE": 2} idx = typeIdxMap.get(currentBlockType, 0) currentBlock.typeCombo.setCurrentIndex(idx) - currentBlock._onTypeChanged(idx) + currentBlock.onTypeChanged(idx) for oldStep in list(currentBlock._actionWidgets): - currentBlock._removeActionStep(oldStep) + currentBlock.removeActionStep(oldStep) for target, valueExpr in actionsBuffer: - currentBlock._addActionStep() + currentBlock.addActionStep() step = currentBlock._actionWidgets[-1] step.loadFromScript(target, valueExpr) self._blocks.clear() @@ -792,24 +791,24 @@ class ALAutoScriptOrchDialog(QDialog): flushBlock() currentBlockType = "IF" actionsBuffer = [] - self._addBlock() + self.addBlock() currentBlock = self._blocks[-1] - self._parseConditionToBlock(currentBlock, ifMatch.group(1)) + self.parseConditionToBlock(currentBlock, ifMatch.group(1)) continue elifIfMatch = re.match(r"^ELSE\s+IF\((.+)\)\s*THEN\s*$", upper) if elifIfMatch: flushBlock() currentBlockType = "ELSE IF" actionsBuffer = [] - self._addBlock() + self.addBlock() currentBlock = self._blocks[-1] - self._parseConditionToBlock(currentBlock, elifIfMatch.group(1)) + self.parseConditionToBlock(currentBlock, elifIfMatch.group(1)) continue if upper == "ELSE": flushBlock() currentBlockType = "ELSE" actionsBuffer = [] - self._addBlock() + self.addBlock() currentBlock = self._blocks[-1] currentBlock.conditionWidget.setVisible(False) continue @@ -833,9 +832,10 @@ class ALAutoScriptOrchDialog(QDialog): continue flushBlock() if not self._blocks: - self._addBlock() + self.addBlock() - def _parseConditionToBlock( + + def parseConditionToBlock( self, block: ConditionalBlock, condStr: str @@ -862,3 +862,23 @@ class ALAutoScriptOrchDialog(QDialog): if w: _setWidgetValue(w, vartype, rightPart) 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) \ No newline at end of file diff --git a/src/gui/ALAutoScriptPrevDialog.py b/src/gui/ALAutoScriptPrevDialog.py index 78bd7ec..4becb08 100644 --- a/src/gui/ALAutoScriptPrevDialog.py +++ b/src/gui/ALAutoScriptPrevDialog.py @@ -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. """ +from PySide6.QtCore import Slot + from PySide6.QtGui import ( QSyntaxHighlighter, QTextCharFormat, QColor, QFont, QIcon ) @@ -162,53 +164,13 @@ class ALAutoScriptPreviewDialog(QDialog): ): self._btnBox.rejected.connect(self.reject) - self._zoomInBtn.clicked.connect(self._onZoomIn) - self._zoomOutBtn.clicked.connect(self._onZoomOut) - self._zoomResetBtn.clicked.connect(self._onZoomReset) - self._copyBtn.clicked.connect(self._onCopy) + self._zoomInBtn.clicked.connect(self.onZoomIn) + self._zoomOutBtn.clicked.connect(self.onZoomOut) + self._zoomResetBtn.clicked.connect(self.onZoomReset) + self._copyBtn.clicked.connect(self.onCopy) - def _onZoomIn( - 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( + def updateFontSize( self ): @@ -222,3 +184,43 @@ class ALAutoScriptPreviewDialog(QDialog): "}" ) 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) + )) diff --git a/src/gui/ALMainWorkers.py b/src/gui/ALMainWorkers.py index 4bb736f..9bc1c9f 100644 --- a/src/gui/ALMainWorkers.py +++ b/src/gui/ALMainWorkers.py @@ -174,7 +174,7 @@ class TimerTaskWorker(AutoLibWorker): try: if not self.loadConfigs(): raise Exception("配置文件加载失败") - self._applyRepeatAutoScript() + self.applyRepeatAutoScript() auto_lib = AutoLib( self._input_queue, self._output_queue, @@ -207,7 +207,7 @@ class TimerTaskWorker(AutoLibWorker): self.timerTaskWorkerIsFinished.emit(False, self.__timer_task) - def _applyRepeatAutoScript( + def applyRepeatAutoScript( self ): @@ -238,6 +238,14 @@ class TimerTaskWorker(AutoLibWorker): self.TraceLevel.INFO ) + @Slot() + def onTimerTaskIsFinished( + self + ): + + self._showTrace(f"定时任务 {self.__timer_task['name']} 运行结束") + self.timerTaskWorkerIsFinished.emit(False, self.__timer_task) + @Slot() def onTimerTaskFinishedWithError( self @@ -248,11 +256,3 @@ class TimerTaskWorker(AutoLibWorker): self.TraceLevel.ERROR ) 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) diff --git a/src/gui/ALTimerTaskAddDialog.py b/src/gui/ALTimerTaskAddDialog.py index cd4e8ac..dab9139 100644 --- a/src/gui/ALTimerTaskAddDialog.py +++ b/src/gui/ALTimerTaskAddDialog.py @@ -36,15 +36,20 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog): def __init__( self, - parent = None + parent = None, + timer_task: dict = None ): super().__init__(parent) + self.__edit_timer_task = timer_task self.setupUi(self) self.modifyUi() self.connectSignals() + if self.__edit_timer_task: + self.loadTask(self.__edit_timer_task) + def modifyUi( self @@ -130,6 +135,45 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog): 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( self ): @@ -138,44 +182,9 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog): self.ConfirmButton.clicked.connect(self.accept) self.TimerTypeComboBox.currentIndexChanged.connect(self.onTimerTypeComboBoxIndexChanged) self.RepeatCheckBox.toggled.connect(self.onRepeatCheckBoxToggled) - self.AutoScriptSetButton.clicked.connect(self._onSetAutoScript) - self.AutoScriptPreviewButton.clicked.connect(self._onPreviewAutoScript) - 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") - ) + self.AutoScriptSetButton.clicked.connect(self.onSetAutoScript) + self.AutoScriptPreviewButton.clicked.connect(self.onPreviewAutoScript) + self.AutoScriptHelpButton.clicked.connect(self.onAutoScriptHelp) def getTimerTask( @@ -200,20 +209,34 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog): minutes = self.RelativeMinuteSpinBox.value(), seconds = self.RelativeSecondSpinBox.value() ) - task_data = { - "name": name, - "uuid": uuid.uuid4().hex.upper() + f"-{added_time.strftime("%Y%m%d%H%M%S")}", - "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, - } - if task_data["repeat"]: - task_data["history"] = [] # repeat history + + if self.__edit_timer_task: + task_data = dict(self.__edit_timer_task) + task_data["name"] = name + task_data["execute_time"] = execute_time + task_data["silent"] = silent + task_data["status"] = ALTimerTaskStatus.PENDING + task_data["executed"] = False + task_data["repeat_auto_script"] = self.__auto_script + else: + task_data = { + "name": name, + "uuid": uuid.uuid4().hex.upper() + f"-{added_time.strftime("%Y%m%d%H%M%S")}", + "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 = [] if self.MonCheckBox.isChecked(): repeat_days.append(0) @@ -265,4 +288,40 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog): self.FriCheckBox.setEnabled(checked) self.SatCheckBox.setEnabled(checked) self.SunCheckBox.setEnabled(checked) - self.AutoScriptGroupBox.setVisible(checked) \ No newline at end of file + 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") + ) + + diff --git a/src/gui/ALTimerTaskHistoryDialog.py b/src/gui/ALTimerTaskHistoryDialog.py index f054b15..8500c96 100644 --- a/src/gui/ALTimerTaskHistoryDialog.py +++ b/src/gui/ALTimerTaskHistoryDialog.py @@ -30,7 +30,7 @@ class ALTimerTaskHistoryDialog(QDialog): super().__init__(parent) self.__task_data = task_data - self.__history = task_data.get("history", []) + self.__history = task_data.get("repeat_history", []) self.modifyUi() self.connectSignals() @@ -130,6 +130,13 @@ class ALTimerTaskHistoryDialog(QDialog): self.HistoryTableWidget.setItem(row, 2, DurationItem) self.HistoryTableWidget.setRowHeight(row, 25) + + def getHistory( + self + ) -> list: + + return self.__history + @Slot() def onClearHistoryButtonClicked( self @@ -137,11 +144,4 @@ class ALTimerTaskHistoryDialog(QDialog): self.__history.clear() self.HistoryTableWidget.setRowCount(0) - self.__task_data["history"] = self.__history - - - def getHistory( - self - ) -> list: - - return self.__history + self.__task_data["repeat_history"] = self.__history diff --git a/src/gui/ALTimerTaskManageWidget.py b/src/gui/ALTimerTaskManageWidget.py index 9dcf792..da1646b 100644 --- a/src/gui/ALTimerTaskManageWidget.py +++ b/src/gui/ALTimerTaskManageWidget.py @@ -19,10 +19,10 @@ from PySide6.QtCore import ( ) from PySide6.QtWidgets import ( QDialog, QWidget, QListWidgetItem, QMessageBox, - QHBoxLayout, QVBoxLayout, QLabel, QPushButton + QHBoxLayout, QVBoxLayout, QLabel, QPushButton, QMenu ) from PySide6.QtGui import ( - QCloseEvent + QCloseEvent, QAction ) import managers.config.ConfigManager as ConfigManager @@ -35,6 +35,8 @@ from gui.ALTimerTaskHistoryDialog import ALTimerTaskHistoryDialog class ALTimerTaskItemWidget(QWidget): + editRequested = Signal(dict) + def __init__( self, parent = None, @@ -45,6 +47,8 @@ class ALTimerTaskItemWidget(QWidget): self.__timer_task = timer_task self.modifyUi() + self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) + self.customContextMenuRequested.connect(self.showContextMenu) def modifyUi( @@ -145,6 +149,27 @@ class ALTimerTaskItemWidget(QWidget): self.DeleteButton.setEnabled(False) 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): @@ -224,8 +249,8 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget): 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["status"] = ALTimerTaskStatus(task["status"]) - if "history" in task: - for item in task["history"]: + if "repeat_history" in task: + for item in task["repeat_history"]: item["result"] = ALTimerTaskStatus(item["result"]) return timer_tasks["timer_tasks"] 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["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"]: + if "repeat_history" in task: + for item in task["repeat_history"]: item["result"] = item["result"].value self.__cfg_mgr.set(ConfigManager.ConfigType.TIMERTASK, "", { "timer_tasks": timer_tasks }) return True @@ -363,6 +388,7 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget): widget.HistoryButton.clicked.connect( lambda _, task = timer_task: self.showTaskHistory(task) ) + widget.editRequested.connect(self.editTask) item.setSizeHint(widget.size()) self.TimerTasksListWidget.addItem(item) self.TimerTasksListWidget.setItemWidget(item, widget) @@ -378,15 +404,30 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget): self.__timer_tasks.append(timer_task) 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 def getTimerTaskDetailMessage( timer_task: dict ): - if "history" not in timer_task: + if "repeat_history" not in timer_task: history = [] else: - history = timer_task["history"] + history = timer_task["repeat_history"] history_count = len(history) return ( 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"已记录次数:{history_count}" ) - + def deleteTask( self, @@ -559,7 +600,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget): self.updateTimerTaskList() self.updateStat() - @Slot(dict) def onTimerTaskIsRunning( self, @@ -584,12 +624,12 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget): ALTimerTaskStatus.OUTDATED} if status not in valid_statuses: return timer_task - if "history" not in timer_task: - timer_task["history"] = [] + if "repeat_history" not in timer_task: + timer_task["repeat_history"] = [] if status != ALTimerTaskStatus.OUTDATED: executed_time = datetime.now() 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"), "executed_time": executed_time.strftime("%Y-%m-%d %H:%M:%S"), "result": status, @@ -603,7 +643,7 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget): delta_days = (current_time - execute_time).days for i in range(delta_days + 1): 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"), "executed_time": (execute_time + timedelta(days=i)).strftime("%Y-%m-%d %H:%M:%S"), "result": status,