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

refactor(style): 统一项目代码风格,整理导入顺序、间距规范与方法排列

- GUI 模块统一 QtCore → QtGui → QtWidgets 导入排列,各类独占一行按字母排序
- 统一类间两空行、类内方法间一空行、函数间一空行的间距规范
- 统一方法排列顺序:__init__ → setupUi → connectSignals → public → Slot → private
- 统一 _widgets 中 ConditionRowFrame/ActionStepFrame 方法命名(populate* / toScript / updateValueWidget)
- LibTimeSelector 迁入 operators/abs 抽象层

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 13:14:27 +08:00
parent a03ab38279
commit 5e898180c7
42 changed files with 780 additions and 1008 deletions
-15
View File
@@ -45,7 +45,6 @@ _DEFAULT_BY_TYPE: dict[str, str | int | float | bool] = {
"Boolean": False,
}
def _getLua(
):
"""
@@ -59,7 +58,6 @@ def _getLua(
_registerHelpers(_lua)
return _lua
def _sandbox(
lua,
) -> None:
@@ -92,7 +90,6 @@ def _sandbox(
end
""")
def _registerHelpers(
lua,
) -> None:
@@ -154,7 +151,6 @@ def _registerHelpers(
end
""")
def _navigatePath(
data: dict,
key_path: list,
@@ -171,7 +167,6 @@ def _navigatePath(
return default
return d.get(key_path[-1], default)
def _assignPath(
data: dict,
key_path: list,
@@ -186,7 +181,6 @@ def _assignPath(
d = d.setdefault(key, {})
d[key_path[-1]] = value
def _pyTypeToASType(
value
) -> str:
@@ -204,7 +198,6 @@ def _pyTypeToASType(
return "String"
return "Unknown"
def _checkDateFormat(
date_str: str,
var_name: str = "",
@@ -223,7 +216,6 @@ def _checkDateFormat(
f"应为 YYYY-MM-DD"
)
def _checkTimeFormat(
time_str: str,
var_name: str = "",
@@ -242,7 +234,6 @@ def _checkTimeFormat(
f"应为 HH:MM"
)
def _checkType(
var_name: str,
var_type: str,
@@ -306,7 +297,6 @@ def _checkType(
)
return
def addTargetVar(
name: str,
var_type: str,
@@ -328,7 +318,6 @@ def addTargetVar(
"key_path": key_path,
}
def resetEngine(
) -> None:
"""
@@ -340,7 +329,6 @@ def resetEngine(
_TARGET_VARS = {}
_lua = None
def _push(
target_data: dict,
) -> None:
@@ -384,7 +372,6 @@ def _push(
raw = _DEFAULT_BY_TYPE.get(vt, False)
g[var_name] = raw
def _pull(
target_data: dict,
) -> None:
@@ -413,7 +400,6 @@ def _pull(
_checkType(var_name, vt, lua_val)
_assignPath(target_data, info["key_path"], lua_val)
def _cleanLuaError(
raw_msg: str
) -> str:
@@ -427,7 +413,6 @@ def _cleanLuaError(
msg = msg[:stack_idx].strip()
return msg
def execute(
script_text: str,
target_data: dict,
-2
View File
@@ -55,7 +55,6 @@ _MOCK_TYPE_VALUES = {
"Float": 0.0,
}
def buildMockTargetData(
) -> dict:
"""
@@ -70,7 +69,6 @@ def buildMockTargetData(
d[key_path[-1]] = _MOCK_TYPE_VALUES.get(var_type, "")
return data
def registerDefaultTargetVars(
) -> None:
"""
-1
View File
@@ -29,7 +29,6 @@ class LibOperator(MsgBase):
super().__init__(input_queue, output_queue)
def _waitResponseLoad(
self
) -> bool:
-4
View File
@@ -58,7 +58,6 @@ class MsgBase:
except RuntimeError:
self._logger = None
def _showMsg(
self,
msg: str
@@ -66,7 +65,6 @@ class MsgBase:
self._output_queue.put(f"[{self._class_name:<15}] >>> : {msg}")
def _showTrace(
self,
msg: str,
@@ -79,7 +77,6 @@ class MsgBase:
if self._logger and not no_log:
self._logger.log(level, msg)
def _showLog(
self,
msg: str,
@@ -89,7 +86,6 @@ class MsgBase:
if self._logger:
self._logger.log(level, msg)
def _waitMsg(
self,
timeout: float = 1.0
+1 -2
View File
@@ -1,8 +1,7 @@
"""
Base module for the AutoLibrary project.
Here are the classes and modules in this package:
- MsgBase: Base class for messages.\
- MsgBase: Base class for messages.
- LibOperator: Base class for library operators.
"""
+12 -6
View File
@@ -16,7 +16,7 @@ from managers.config.ConfigManager import instance as configInstance
from managers.driver.WebDriverManager import instance as webdriverInstance
def initializeLogManager(
def _initializeLogManager(
) -> bool:
app_dir = QStandardPaths.writableLocation(QStandardPaths.StandardLocation.AppDataLocation)
@@ -27,7 +27,7 @@ def initializeLogManager(
logInstance(log_dir)
return True
def initializeConfigManager(
def _initializeConfigManager(
) -> bool:
logger = logInstance().getLogger("AppInitializer")
@@ -49,7 +49,7 @@ def initializeConfigManager(
configInstance(new_config_dir)
return True
def initializeWebDriverManager(
def _initializeWebDriverManager(
) -> bool:
logger = logInstance().getLogger("AppInitializer")
@@ -66,11 +66,17 @@ def initializeWebDriverManager(
def initializeApp(
) -> bool:
"""
Initialize the application components
if not initializeLogManager():
Order:
LogManager -> ConfigManager -> WebDriverManager
"""
if not _initializeLogManager():
return False
if not initializeConfigManager():
if not _initializeConfigManager():
return False
if not initializeWebDriverManager():
if not _initializeWebDriverManager():
return False
return True
+8 -11
View File
@@ -9,14 +9,17 @@ See the LICENSE file for details.
"""
import platform
from PySide6.QtCore import (
Qt,
QTimer
)
from PySide6.QtGui import (
QIcon, QFont
QFont,
QIcon
)
from PySide6.QtWidgets import (
QDialog, QApplication
)
from PySide6.QtCore import (
QTimer, Qt
QApplication,
QDialog
)
from gui.ALVersionInfo import (
@@ -38,7 +41,6 @@ class ALAboutDialog(QDialog, Ui_ALAboutDialog):
self.modifyUi()
self.connectSignals()
def modifyUi(
self
):
@@ -51,14 +53,12 @@ class ALAboutDialog(QDialog, Ui_ALAboutDialog):
self.AboutInfoBrowser.setFont(browser_font)
self.AboutInfoBrowser.setTextInteractionFlags(Qt.TextBrowserInteraction)
def connectSignals(
self
):
self.CopyButton.clicked.connect(self.copyAboutInfo)
def generateAboutText(
self
) -> str:
@@ -91,7 +91,6 @@ GitHub: <a href="https://www.github.com/KenanZhu" style="text-decoration: none;"
"""
return about_text
def getOSInfo(
self
):
@@ -123,7 +122,6 @@ GitHub: <a href="https://www.github.com/KenanZhu" style="text-decoration: none;"
'architecture': architecture
}
def getQtVersion(
self
):
@@ -134,7 +132,6 @@ GitHub: <a href="https://www.github.com/KenanZhu" style="text-decoration: none;"
except:
return "Unknown"
def copyAboutInfo(
self
):
+119 -133
View File
@@ -116,7 +116,6 @@ class ALScriptHighlighter(QSyntaxHighlighter):
commentFmt.setFontItalic(True)
self._rules.append((r"--[^\n]*", commentFmt))
def highlightBlock(
self,
text
@@ -169,7 +168,7 @@ class ALAutoScriptEditDialog(QDialog):
):
super().__init__(parent)
self._fontSize = 13
self._fontSize = 21
self._mockWidgets = {}
self.setupUi()
@@ -181,7 +180,6 @@ class ALAutoScriptEditDialog(QDialog):
if mockData:
self.setMockData(mockData)
def setupUi(
self
):
@@ -243,7 +241,7 @@ class ALAutoScriptEditDialog(QDialog):
"}"
)
layout.addWidget(self.textEdit)
self._createButtonPanel(layout)
self.createButtonPanel(layout)
self.btnBox = QDialogButtonBox(
QDialogButtonBox.StandardButton.Ok |
QDialogButtonBox.StandardButton.Cancel
@@ -252,8 +250,7 @@ class ALAutoScriptEditDialog(QDialog):
self.btnBox.button(QDialogButtonBox.StandardButton.Cancel).setText("取消")
layout.addWidget(self.btnBox)
def _createButtonPanel(
def createButtonPanel(
self,
parent_layout
):
@@ -273,11 +270,11 @@ class ALAutoScriptEditDialog(QDialog):
("结束 (end)", "end"),
("跳过 (pass)", "-- pass"),
]
self._addButtonsToGrid(basicLayout, controlButtons, 0, 0, 3)
self.addButtonsToGrid(basicLayout, controlButtons, 0, 0, 3)
assignButtons = [
("赋值 (=)", " = "),
]
self._addButtonsToGrid(basicLayout, assignButtons, 1, 2, 3)
self.addButtonsToGrid(basicLayout, assignButtons, 1, 2, 3)
tabWidget.addTab(basicWidget, "基本语法")
operatorWidget = QWidget()
operatorLayout = QGridLayout(operatorWidget)
@@ -288,7 +285,7 @@ class ALAutoScriptEditDialog(QDialog):
("加 (+)", " + "),
("减 (-)", " - "),
]
self._addButtonsToGrid(operatorLayout, arithmeticButtons, 0, 0, 3)
self.addButtonsToGrid(operatorLayout, arithmeticButtons, 0, 0, 3)
compareButtons = [
("等于 (==)", " == "),
("不等于 (~=)", " ~= "),
@@ -297,12 +294,12 @@ class ALAutoScriptEditDialog(QDialog):
("大于等于 (>=)", " >= "),
("小于等于 (<=)", " <= "),
]
self._addButtonsToGrid(operatorLayout, compareButtons, 1, 0, 3)
self.addButtonsToGrid(operatorLayout, compareButtons, 1, 0, 3)
logic_buttons = [
("且 (and)", " and "),
("或 (or)", " or "),
]
self._addButtonsToGrid(operatorLayout, logic_buttons, 2, 0, 3)
self.addButtonsToGrid(operatorLayout, logic_buttons, 2, 0, 3)
tabWidget.addTab(operatorWidget, "运算符")
literalWidget = QWidget()
literalLayout = QGridLayout(literalWidget)
@@ -313,18 +310,18 @@ class ALAutoScriptEditDialog(QDialog):
("真 (true)", "true"),
("假 (false)", "false"),
]
self._addButtonsToGrid(literalLayout, bool_buttons, 0, 0, 3)
self.addButtonsToGrid(literalLayout, bool_buttons, 0, 0, 3)
dateTimeButtons = [
("日期", '"2099-01-01"'),
("时间", '"00:00"'),
]
self._addButtonsToGrid(literalLayout, dateTimeButtons, 1, 0, 3)
self.addButtonsToGrid(literalLayout, dateTimeButtons, 1, 0, 3)
hintButtons = [
("字符串", '"请输入文本"'),
("数字", "123"),
("注释", "-- 请输入注释"),
]
self._addButtonsToGrid(literalLayout, hintButtons, 2, 0, 3)
self.addButtonsToGrid(literalLayout, hintButtons, 2, 0, 3)
tabWidget.addTab(literalWidget, "字面量")
varWidget = QWidget()
varLayout = QGridLayout(varWidget)
@@ -334,9 +331,9 @@ class ALAutoScriptEditDialog(QDialog):
varButtons = [
(display_name, name) for display_name, (name, _) in ALL_VARIABLES.items()
]
self._addButtonsToGrid(varLayout, varButtons, 0, 0, 3)
self.addButtonsToGrid(varLayout, varButtons, 0, 0, 3)
tabWidget.addTab(varWidget, "变量")
mockPanel = self._createMockPanel()
mockPanel = self.createMockPanel()
mockPanel.setMinimumWidth(260)
splitter.addWidget(tabWidget)
splitter.addWidget(mockPanel)
@@ -345,8 +342,7 @@ class ALAutoScriptEditDialog(QDialog):
splitter.setSizes([530, 530])
parent_layout.addWidget(splitter)
def _addButtonsToGrid(
def addButtonsToGrid(
self,
grid_layout,
buttons,
@@ -361,7 +357,7 @@ class ALAutoScriptEditDialog(QDialog):
for btn_text, template in buttons:
btn = QPushButton(btn_text)
btn.setProperty("template", template)
btn.clicked.connect(self._insertTemplate)
btn.clicked.connect(self.insertTemplate)
btn.setFixedWidth(100)
btn.setFixedHeight(25)
btn.setToolTip(f"插入: {template}")
@@ -371,22 +367,7 @@ class ALAutoScriptEditDialog(QDialog):
col = start_col
row += 1
@Slot()
def _insertTemplate(
self
):
btn = self.sender()
if not isinstance(btn, QPushButton):
return
template = btn.property("template")
if not template:
return
cursor = self.textEdit.textCursor()
cursor.insertText(template)
def _createMockPanel(
def createMockPanel(
self
) -> QGroupBox:
@@ -397,14 +378,13 @@ class ALAutoScriptEditDialog(QDialog):
self._mockWidgets = {}
for name, var_type, key_path, display_name in _TARGET_VAR_DEFS:
default = _MOCK_TYPE_VALUES.get(var_type, "")
widget = self._makeMockInput(var_type, default)
widget = self.makeMockInput(var_type, default)
label = QLabel(f"{display_name}: {name}({var_type})")
form.addRow(label, widget)
self._mockWidgets[name] = (widget, var_type, key_path)
return group
def _makeMockInput(
def makeMockInput(
self,
var_type: str,
default
@@ -447,7 +427,6 @@ class ALAutoScriptEditDialog(QDialog):
w.setText(str(default))
return w
def getMockData(
self
) -> dict:
@@ -455,14 +434,13 @@ class ALAutoScriptEditDialog(QDialog):
data = {}
for name, var_type, key_path, display_name in _TARGET_VAR_DEFS:
widget, _, _ = self._mockWidgets[name]
value = self._getMockValue(widget, var_type)
value = self.getMockValue(widget, var_type)
d = data
for key in key_path[:-1]:
d = d.setdefault(key, {})
d[key_path[-1]] = value
return data
def setMockData(
self,
data: dict
@@ -478,10 +456,9 @@ class ALAutoScriptEditDialog(QDialog):
except (KeyError, TypeError):
continue
widget, _, _ = self._mockWidgets[name]
self._setMockValue(widget, var_type, d)
self.setMockValue(widget, var_type, d)
def _getMockValue(
def getMockValue(
self,
widget: QWidget,
var_type: str
@@ -499,8 +476,7 @@ class ALAutoScriptEditDialog(QDialog):
return widget.value()
return widget.text()
def _setMockValue(
def setMockValue(
self,
widget: QWidget,
var_type: str,
@@ -520,6 +496,103 @@ class ALAutoScriptEditDialog(QDialog):
else:
widget.setText(str(value))
def connectSignals(
self
):
self.btnBox.accepted.connect(self.accept)
self.btnBox.rejected.connect(self.reject)
self.orchBtn.clicked.connect(self.onOpenOrchDialog)
self.debugBtn.clicked.connect(self.onDebugRun)
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 getScript(
self
) -> str:
return self.textEdit.toPlainText()
def updateFontSize(
self
):
self.textEdit.setStyleSheet(
"QPlainTextEdit {"
" font-family: 'Courier New', 'Consolas', monospace;"
f" font-size: {self._fontSize}px;"
"}"
)
self.zoomLabel.setText(f"{self._fontSize}px")
@Slot()
def insertTemplate(
self
):
btn = self.sender()
if not isinstance(btn, QPushButton):
return
template = btn.property("template")
if not template:
return
cursor = self.textEdit.textCursor()
cursor.insertText(template)
@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 = 21
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)
QTimer.singleShot(2000, lambda: (
self.copyBtn.setText(original),
self.copyBtn.setEnabled(True)
))
@Slot()
def onOpenOrchDialog(
self
):
from gui.ALAutoScriptOrchDialog import ALAutoScriptOrchDialog
dlg = ALAutoScriptOrchDialog(self)
if dlg.exec() == QDialog.DialogCode.Accepted:
script = dlg.getScript()
if script:
cursor = self.textEdit.textCursor()
cursor.insertText(script)
dlg.deleteLater()
@Slot()
def onDebugRun(
@@ -556,90 +629,3 @@ class ALAutoScriptEditDialog(QDialog):
dlg = _DebugResultDialog(changes, self)
dlg.exec()
dlg.deleteLater()
def connectSignals(
self
):
self.btnBox.accepted.connect(self.accept)
self.btnBox.rejected.connect(self.reject)
self.orchBtn.clicked.connect(self.onOpenOrchDialog)
self.debugBtn.clicked.connect(self.onDebugRun)
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 getScript(
self
) -> str:
return self.textEdit.toPlainText()
def updateFontSize(
self
):
self.textEdit.setStyleSheet(
"QPlainTextEdit {"
" font-family: 'Courier New', 'Consolas', monospace;"
f" font-size: {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)
QTimer.singleShot(2000, lambda: (
self.copyBtn.setText(original),
self.copyBtn.setEnabled(True)
))
@Slot()
def onOpenOrchDialog(
self
):
from gui.ALAutoScriptOrchDialog import ALAutoScriptOrchDialog
dlg = ALAutoScriptOrchDialog(self)
if dlg.exec() == QDialog.DialogCode.Accepted:
script = dlg.getScript()
if script:
cursor = self.textEdit.textCursor()
cursor.insertText(script)
dlg.deleteLater()
+15 -29
View File
@@ -47,7 +47,6 @@ class ConditionalBlock(QGroupBox):
self.connectSignals()
self.addInitialConditionRow()
def setupUi(
self
):
@@ -103,7 +102,6 @@ class ConditionalBlock(QGroupBox):
mainLayout.addWidget(self.addActionBtn)
self.setUpdatesEnabled(True)
def connectSignals(
self
):
@@ -112,7 +110,6 @@ class ConditionalBlock(QGroupBox):
self.addCondBtn.clicked.connect(self.addConditionRow)
self.addActionBtn.clicked.connect(self.addActionStep)
def addInitialConditionRow(
self
):
@@ -124,7 +121,6 @@ class ConditionalBlock(QGroupBox):
self._conditionRows.append(row)
self.condRowsLayout.addWidget(row)
def addConditionRow(
self
):
@@ -137,7 +133,6 @@ class ConditionalBlock(QGroupBox):
self._conditionRows.append(row)
self.condRowsLayout.addWidget(row)
def removeConditionRow(
self,
row: ConditionRowFrame
@@ -149,7 +144,6 @@ class ConditionalBlock(QGroupBox):
row.hide()
row.deleteLater()
def addActionStep(
self
):
@@ -159,7 +153,6 @@ class ConditionalBlock(QGroupBox):
self._actionWidgets.append(step)
self.actionsLayout.addWidget(step)
def removeActionStep(
self,
step: ActionStepFrame
@@ -171,48 +164,31 @@ class ConditionalBlock(QGroupBox):
step.hide()
step.deleteLater()
@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 执行步骤:"
)
def getBlockType(
self
) -> str:
return self.typeCombo.currentData()
def getConditionRows(
self
):
return list(self._conditionRows)
def getActionSteps(
self
):
return list(self._actionWidgets)
def countActionSteps(
self
) -> int:
return len(self._actionWidgets)
def toScriptLines(
def toScript(
self
) -> list:
"""
@@ -223,7 +199,7 @@ class ConditionalBlock(QGroupBox):
lines = []
if blockType in ("IF", "ELSE IF"):
condTexts = [
r.toConditionText() for r in self._conditionRows if r.toConditionText()
r.toScript() for r in self._conditionRows if r.toScript()
]
if not condTexts:
condTexts = ["true"]
@@ -245,12 +221,11 @@ class ConditionalBlock(QGroupBox):
else:
lines.append("else")
for step in self._actionWidgets:
scriptLine = step.toScriptLine()
scriptLine = step.toScript()
if scriptLine:
lines.append(scriptLine)
return lines
def refreshVarCombos(
self
):
@@ -260,7 +235,6 @@ class ConditionalBlock(QGroupBox):
for step in self._actionWidgets:
step.refreshVarCombos()
def setPrevBlockType(
self,
prevType: str | None
@@ -278,3 +252,15 @@ class ConditionalBlock(QGroupBox):
item.setEnabled(shouldEnable)
if prevType == "ELSE" and self.typeCombo.currentData() in ("ELSE IF", "ELSE"):
self.typeCombo.setCurrentIndex(0)
@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 执行步骤:"
)
+5 -11
View File
@@ -42,7 +42,6 @@ class ALAutoScriptOrchDialog(QDialog):
self.addBlock()
self.scrollLayout.addStretch()
def setupUi(
self
):
@@ -70,7 +69,6 @@ class ALAutoScriptOrchDialog(QDialog):
self.btnBox.button(QDialogButtonBox.StandardButton.Cancel).setText("取消")
mainLayout.addWidget(self.btnBox)
def connectSignals(
self
):
@@ -79,8 +77,7 @@ class ALAutoScriptOrchDialog(QDialog):
self.btnBox.rejected.connect(self.reject)
self.addBlockBtn.clicked.connect(self.addBlock)
def _updateBlockTypeRestrictions(
def updateBlockTypeRestrictions(
self
):
@@ -89,7 +86,6 @@ class ALAutoScriptOrchDialog(QDialog):
block.setPrevBlockType(prevType)
prevType = block.getBlockType()
def addBlock(
self
):
@@ -98,10 +94,10 @@ class ALAutoScriptOrchDialog(QDialog):
len(self._blocks), self._varMgr, parent=self
)
block.deleteBlockBtn.clicked.connect(lambda: self.removeBlock(block))
block.typeCombo.currentIndexChanged.connect(self._updateBlockTypeRestrictions)
block.typeCombo.currentIndexChanged.connect(self.updateBlockTypeRestrictions)
block.addActionStep()
self._blocks.append(block)
self._updateBlockTypeRestrictions()
self.updateBlockTypeRestrictions()
if self.scrollLayout.count() > 0:
lastItem = self.scrollLayout.itemAt(
self.scrollLayout.count() - 1
@@ -113,7 +109,6 @@ class ALAutoScriptOrchDialog(QDialog):
return
self.scrollLayout.addWidget(block)
def removeBlock(
self,
block: ConditionalBlock
@@ -135,8 +130,7 @@ class ALAutoScriptOrchDialog(QDialog):
else:
blk.typeCombo.setEnabled(True)
blk.refreshVarCombos()
self._updateBlockTypeRestrictions()
self.updateBlockTypeRestrictions()
def getScript(
self
@@ -151,7 +145,7 @@ class ALAutoScriptOrchDialog(QDialog):
blockType = block.getBlockType()
if blockType == "IF" and prevType is not None:
parts.append("end")
lines = block.toScriptLines()
lines = block.toScript()
parts.extend(lines)
prevType = blockType
if self._blocks and self._blocks[0].getBlockType() == "IF":
+188 -218
View File
@@ -95,181 +95,6 @@ DATE_OFFSET_UNITS = [
]
class VariableManager(QObject):
def __init__(
self,
parent = None
):
super().__init__(parent)
self._vars = []
self._nameMap = {}
self._initPresetVars()
def _initPresetVars(
self
):
for p in PRESET_VARIABLES:
entry = {"name": p["name"], "type": p["type"], "display": p["display"]}
self._vars.append(entry)
self._nameMap[p["name"]] = entry
def getInfoByName(
self,
name: str
):
return self._nameMap.get(name.upper().strip())
def populateCombo(
self,
combo: QComboBox
):
currentData = combo.currentData()
combo.blockSignals(True)
combo.clear()
for entry in self._vars:
combo.addItem(
entry["display"],
(entry["name"], entry["type"])
)
if currentData:
for i in range(combo.count()):
d = combo.itemData(i)
if d and d[0] == currentData[0]:
combo.setCurrentIndex(i)
break
combo.blockSignals(False)
def findExactNameEntry(
self,
combo: QComboBox,
name: str
) -> int:
name = name.upper().strip()
for i in range(combo.count()):
d = combo.itemData(i)
if d and len(d) >= 1 and d[0].upper().strip() == name:
return i
return -1
def makeValueWidget(
var_type: str,
parent: QWidget = None
) -> QWidget:
if var_type == "Int":
w = QSpinBox(parent)
w.setRange(-999999, 999999)
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "Float":
w = QDoubleSpinBox(parent)
w.setRange(-999999.0, 999999.0)
w.setDecimals(2)
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "String":
w = QLineEdit(parent)
w.setPlaceholderText("输入值")
w.setFixedHeight(25)
w.setMinimumWidth(120)
return w
if var_type == "Boolean":
w = QComboBox(parent)
w.addItem("是 (true)", "true")
w.addItem("否 (false)", "false")
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "Date":
return _DateInputContainer(parent)
if var_type == "Time":
return _TimeInputContainer(parent)
w = QLineEdit(parent)
w.setPlaceholderText("输入值")
w.setFixedHeight(25)
w.setMinimumWidth(120)
return w
def makeOffsetWidget(
var_type: str,
parent: QWidget = None
) -> QWidget:
if var_type == "Int":
w = QSpinBox(parent)
w.setRange(-999999, 999999)
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "Float":
w = QDoubleSpinBox(parent)
w.setRange(-999999.0, 999999.0)
w.setDecimals(2)
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "Date":
return _DateOffsetContainer(parent)
if var_type == "Time":
return _TimeOffsetContainer(parent)
w = QLabel("(不支持该操作)", parent)
w.setFixedHeight(25)
return w
def makeVarRefCombo(
parent: QWidget = None
) -> QComboBox:
cb = QComboBox(parent)
cb.setFixedHeight(25)
cb.setMinimumWidth(120)
cb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
return cb
def makeComboWidget(
items,
min_width: int = 80,
parent: QWidget = None
) -> QComboBox:
cb = QComboBox(parent)
for display, data in items:
cb.addItem(display, data)
cb.setFixedHeight(25)
cb.setMinimumWidth(min_width)
return cb
def makeLabel(
text: str,
parent: QWidget = None,
width: int = None
) -> QLabel:
lbl = QLabel(text, parent)
lbl.setFixedHeight(25)
if width:
lbl.setFixedWidth(width)
return lbl
class _DateInputContainer(QWidget):
def __init__(
@@ -281,7 +106,6 @@ class _DateInputContainer(QWidget):
self._dynamicItems = {} # index -> raw expression, for one-way parsed items
self.setupUi()
def setupUi(
self
):
@@ -327,7 +151,6 @@ class _DateInputContainer(QWidget):
return self._relCombo.currentText()
return self._dateEdit.date().toString("yyyy-MM-dd")
def setValue(
self,
expr: str
@@ -392,14 +215,12 @@ class _TimeInputContainer(QWidget):
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self._timeEdit)
def getValue(
self
) -> str:
return self._timeEdit.time().toString("HH:mm")
def setValue(
self,
expr: str
@@ -443,14 +264,12 @@ class _DateOffsetContainer(QWidget):
layout.addWidget(self._unitCombo)
layout.addStretch()
def getValue(
self
) -> str:
return str(self.getOffsetDays())
def setValue(
self,
expr: str
@@ -462,7 +281,6 @@ class _DateOffsetContainer(QWidget):
except ValueError:
pass
def getOffsetDays(
self
) -> int:
@@ -477,7 +295,6 @@ class _DateOffsetContainer(QWidget):
return val * 365
return val
def getRawValue(
self
) -> str:
@@ -502,14 +319,12 @@ class _TimeOffsetContainer(QWidget):
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self._spinBox)
def getValue(
self
) -> str:
return str(self.getOffsetHours())
def setValue(
self,
expr: str
@@ -521,14 +336,12 @@ class _TimeOffsetContainer(QWidget):
except ValueError:
pass
def getOffsetHours(
self
) -> int:
return self._spinBox.value()
def getRawValue(
self
) -> str:
@@ -536,6 +349,172 @@ class _TimeOffsetContainer(QWidget):
return str(self._spinBox.value())
class VariableManager(QObject):
def __init__(
self,
parent = None
):
super().__init__(parent)
self._vars = []
self._nameMap = {}
self._initPresetVars()
def _initPresetVars(
self
):
for p in PRESET_VARIABLES:
entry = {"name": p["name"], "type": p["type"], "display": p["display"]}
self._vars.append(entry)
self._nameMap[p["name"]] = entry
def getInfoByName(
self,
name: str
):
return self._nameMap.get(name.upper().strip())
def populateCombo(
self,
combo: QComboBox
):
currentData = combo.currentData()
combo.blockSignals(True)
combo.clear()
for entry in self._vars:
combo.addItem(
entry["display"],
(entry["name"], entry["type"])
)
if currentData:
for i in range(combo.count()):
d = combo.itemData(i)
if d and d[0] == currentData[0]:
combo.setCurrentIndex(i)
break
combo.blockSignals(False)
def findExactNameEntry(
self,
combo: QComboBox,
name: str
) -> int:
name = name.upper().strip()
for i in range(combo.count()):
d = combo.itemData(i)
if d and len(d) >= 1 and d[0].upper().strip() == name:
return i
return -1
def makeValueWidget(
var_type: str,
parent: QWidget = None
) -> QWidget:
if var_type == "Int":
w = QSpinBox(parent)
w.setRange(-999999, 999999)
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "Float":
w = QDoubleSpinBox(parent)
w.setRange(-999999.0, 999999.0)
w.setDecimals(2)
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "String":
w = QLineEdit(parent)
w.setPlaceholderText("输入值")
w.setFixedHeight(25)
w.setMinimumWidth(120)
return w
if var_type == "Boolean":
w = QComboBox(parent)
w.addItem("是 (true)", "true")
w.addItem("否 (false)", "false")
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "Date":
return _DateInputContainer(parent)
if var_type == "Time":
return _TimeInputContainer(parent)
w = QLineEdit(parent)
w.setPlaceholderText("输入值")
w.setFixedHeight(25)
w.setMinimumWidth(120)
return w
def makeOffsetWidget(
var_type: str,
parent: QWidget = None
) -> QWidget:
if var_type == "Int":
w = QSpinBox(parent)
w.setRange(-999999, 999999)
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "Float":
w = QDoubleSpinBox(parent)
w.setRange(-999999.0, 999999.0)
w.setDecimals(2)
w.setFixedHeight(25)
w.setMinimumWidth(100)
return w
if var_type == "Date":
return _DateOffsetContainer(parent)
if var_type == "Time":
return _TimeOffsetContainer(parent)
w = QLabel("(不支持该操作)", parent)
w.setFixedHeight(25)
return w
def makeVarRefCombo(
parent: QWidget = None
) -> QComboBox:
cb = QComboBox(parent)
cb.setFixedHeight(25)
cb.setMinimumWidth(120)
cb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
return cb
def makeComboWidget(
items,
min_width: int = 80,
parent: QWidget = None
) -> QComboBox:
cb = QComboBox(parent)
for display, data in items:
cb.addItem(display, data)
cb.setFixedHeight(25)
cb.setMinimumWidth(min_width)
return cb
def makeLabel(
text: str,
parent: QWidget = None,
width: int = None
) -> QLabel:
lbl = QLabel(text, parent)
lbl.setFixedHeight(25)
if width:
lbl.setFixedWidth(width)
return lbl
def getValueFromWidget(
w: QWidget
) -> str:
@@ -556,8 +535,7 @@ def getValueFromWidget(
return w.text()
return ""
def setWidgetValue(
def setValueToWidget(
w: QWidget,
var_type: str,
expr: str
@@ -619,7 +597,6 @@ def setWidgetValue(
inner = inner[1:-1].replace('\\"', '"')
w.setText(inner)
def encodeValueStr(
raw_value: str,
var_type: str
@@ -632,7 +609,7 @@ def encodeValueStr(
"""
if var_type in ("Date", "Time"):
return _encodeDateOrTime(str(raw_value), var_type)
return encodeDateOrTime(str(raw_value), var_type)
if isinstance(raw_value, bool):
return "true" if raw_value else "false"
s = str(raw_value)
@@ -648,8 +625,7 @@ def encodeValueStr(
return f'"{escaped}"'
return s
def _encodeDateOrTime(
def encodeDateOrTime(
raw_value: str,
var_type: str
) -> str:
@@ -707,7 +683,6 @@ def _encodeDateOrTime(
return s
return f'"{s}"'
def stripOuterParens(
s: str
) -> str:
@@ -725,12 +700,10 @@ def stripOuterParens(
return s[1:-1].strip()
return s
# Pre-compiled patterns for detecting arithmetic expressions (A + B / A - B)
_RE_ARITH_SPACED = re.compile(r'^(.+?)\s+([+-])\s+(.+)$')
_RE_ARITH_NOSPACE = re.compile(r'^([A-Za-z_]\w*)([+-])(\d+|[A-Za-z_]\w*)$')
def isArithExpr(
expr: str
) -> bool:
@@ -741,7 +714,6 @@ def isArithExpr(
s = expr.strip()
return bool(_RE_ARITH_SPACED.match(s) or _RE_ARITH_NOSPACE.match(s))
def isVarReference(
expr: str
) -> bool:
@@ -764,27 +736,7 @@ def isVarReference(
return False
return bool(re.match(r"^[A-Z_][A-Z0-9_]*$", up))
def findOperatorIn(
text: str,
operators: list
) -> tuple[int, str] | None:
for op in operators:
op_upper = op.upper()
start = 0
while True:
idx = text.upper().find(op_upper, start)
if idx < 0:
break
if _isInsideLiteral(text, idx):
start = idx + 1
continue
return (idx, op)
return None
def _isInsideLiteral(
def isInsideLiteral(
text: str,
pos: int
) -> bool:
@@ -799,3 +751,21 @@ def _isInsideLiteral(
elif ch == '"' and not in_single:
in_double = not in_double
return in_single or in_double
def findOperatorIn(
text: str,
operators: list
) -> tuple[int, str] | None:
for op in operators:
op_upper = op.upper()
start = 0
while True:
idx = text.upper().find(op_upper, start)
if idx < 0:
break
if isInsideLiteral(text, idx):
start = idx + 1
continue
return (idx, op)
return None
+110 -120
View File
@@ -58,7 +58,6 @@ class ConditionRowFrame(QFrame):
self.setupUi()
self.connectSignals()
def setupUi(
self
):
@@ -90,15 +89,7 @@ class ConditionRowFrame(QFrame):
layout.addWidget(self._compTypeCombo)
self.rhsStack = QStackedWidget(self)
self.rhsStack.setFixedHeight(25)
self.literalStack = QStackedWidget(self)
self.literalStack.setFixedHeight(25)
self.literalWidgets = {}
for vt in VAR_TYPE_ORDER:
w = makeValueWidget(vt, self.literalStack)
self.literalWidgets[vt] = w
self.literalStack.addWidget(w)
self.literalStack.setCurrentWidget(self.literalWidgets.get("String"))
self.rhsStack.addWidget(self.literalStack)
self.initLiteralStack()
self.rhsVarCombo = makeVarRefCombo(self)
self.rhsStack.addWidget(self.rhsVarCombo)
self.rhsStack.setCurrentIndex(0)
@@ -113,7 +104,6 @@ class ConditionRowFrame(QFrame):
layout.addStretch()
self.setUpdatesEnabled(True)
def populateLeftVarCombo(
self
):
@@ -136,13 +126,25 @@ class ConditionRowFrame(QFrame):
self.leftVarCombo.setCurrentIndex(ci)
break
def populateRhsVarCombo(
def populateRHSVarCombo(
self
):
self._varMgr.populateCombo(self.rhsVarCombo)
def initLiteralStack(
self
):
self.literalStack = QStackedWidget(self)
self.literalStack.setFixedHeight(25)
self._literalWidgets = {}
for vt in VAR_TYPE_ORDER:
w = makeValueWidget(vt, self.literalStack)
self._literalWidgets[vt] = w
self.literalStack.addWidget(w)
self.literalStack.setCurrentWidget(self._literalWidgets.get("String"))
self.rhsStack.addWidget(self.literalStack)
def connectSignals(
self
@@ -151,58 +153,22 @@ class ConditionRowFrame(QFrame):
self.leftVarCombo.currentIndexChanged.connect(self.onLeftVarChanged)
self._compTypeCombo.currentIndexChanged.connect(self.onCompTypeChanged)
@Slot(int)
def onLeftVarChanged(
self,
idx
):
self._rawRhsExpr = ""
if idx < 0:
return
data = self.leftVarCombo.itemData(idx)
if not data:
return
name, vartype = data
isBool = name in ("true", "false")
self._isBoolMode = isBool
self.opCombo.setVisible(not isBool)
self._compTypeCombo.setVisible(not isBool)
self.rhsStack.setVisible(not isBool)
if not isBool:
self.updateRhsLiteralWidget(vartype)
def updateRhsLiteralWidget(
self,
vartype: str
):
if vartype not in self.literalWidgets:
vartype = "String"
self.literalStack.setCurrentWidget(self.literalWidgets[vartype])
@Slot(int)
def onCompTypeChanged(
self,
idx
):
self._rawRhsExpr = ""
isVar = (self._compTypeCombo.currentData() == "variable")
self.rhsStack.setCurrentIndex(1 if isVar else 0)
if isVar:
self.populateRhsVarCombo()
def getLogic(
self
) -> str:
return self.logicCombo.currentData() if self.logicCombo else ""
def updateRHSLiteralWidget(
self,
vartype: str
):
def toConditionText(
if vartype not in self._literalWidgets:
vartype = "String"
self.literalStack.setCurrentWidget(self._literalWidgets[vartype])
def toScript(
self
) -> str:
@@ -230,20 +196,53 @@ class ConditionRowFrame(QFrame):
if rhsText:
return f"{name} {opSym} {rhsText}"
return ""
w = self.literalWidgets.get(vartype)
w = self._literalWidgets.get(vartype)
if w:
rawVal = getValueFromWidget(w)
encoded = encodeValueStr(rawVal, vartype)
return f"{name} {opSym} {encoded}"
return ""
def refreshVarCombos(
self
):
self.populateLeftVarCombo()
self.populateRhsVarCombo()
self.populateRHSVarCombo()
@Slot(int)
def onLeftVarChanged(
self,
idx
):
self._rawRhsExpr = ""
if idx < 0:
return
data = self.leftVarCombo.itemData(idx)
if not data:
return
name, vartype = data
isBool = name in ("true", "false")
self._isBoolMode = isBool
self.opCombo.setVisible(not isBool)
self._compTypeCombo.setVisible(not isBool)
self.rhsStack.setVisible(not isBool)
if not isBool:
self.updateRHSLiteralWidget(vartype)
@Slot(int)
def onCompTypeChanged(
self,
idx
):
self._rawRhsExpr = ""
isVar = (self._compTypeCombo.currentData() == "variable")
self.rhsStack.setCurrentIndex(1 if isVar else 0)
if isVar:
self.populateRHSVarCombo()
class ActionStepFrame(QFrame):
@@ -262,7 +261,6 @@ class ActionStepFrame(QFrame):
self.setupUi()
self.connectSignals()
def setupUi(
self
):
@@ -280,7 +278,7 @@ class ActionStepFrame(QFrame):
self.targetCombo = QComboBox(self)
self.targetCombo.setFixedHeight(25)
self.targetCombo.setMinimumWidth(120)
self.buildTargetCombo()
self.populateTargetCombo()
layout.addWidget(self.targetCombo)
layout.addWidget(makeLabel("", self))
self.valueSrcCombo = makeComboWidget([
@@ -301,8 +299,7 @@ class ActionStepFrame(QFrame):
layout.addWidget(self.deleteBtn)
self.setUpdatesEnabled(True)
def buildTargetCombo(
def populateTargetCombo(
self
):
@@ -319,7 +316,6 @@ class ActionStepFrame(QFrame):
)
self.targetCombo.blockSignals(False)
def initValueStacks(
self
):
@@ -338,7 +334,6 @@ class ActionStepFrame(QFrame):
self._offsetWidgets[vt] = lbl
self.valueStack.addWidget(lbl)
def connectSignals(
self
):
@@ -347,32 +342,14 @@ class ActionStepFrame(QFrame):
self.targetCombo.currentIndexChanged.connect(self.onTargetChanged)
self.valueSrcCombo.currentIndexChanged.connect(self.onValueSrcChanged)
@Slot(int)
def onTargetChanged(
self,
idx
):
def getTargetName(
self
) -> str:
if idx < 0:
return
data = self.targetCombo.itemData(idx)
if not data:
return
_, vartype = data
self._currentTargetType = vartype
self.updateRHSWidget()
self.onValueSrcChanged(self.valueSrcCombo.currentIndex())
data = self.targetCombo.currentData()
return data[0] if data else ""
@Slot(int)
def onOpTypeChanged(
self,
idx
):
self.updateRHSWidget()
def updateRHSWidget(
def updateValueWidget(
self
):
@@ -386,30 +363,7 @@ class ActionStepFrame(QFrame):
else:
self.valueStack.setCurrentWidget(self._literalWidgets.get("String"))
@Slot(int)
def onValueSrcChanged(
self,
idx
):
isVar = (self.valueSrcCombo.currentData() == "variable")
self.valueStack.setVisible(not isVar)
self.existingVarCombo.setVisible(isVar)
if isVar:
self._varMgr.populateCombo(self.existingVarCombo)
else:
self.updateRHSWidget()
def getTargetName(
self
) -> str:
data = self.targetCombo.currentData()
return data[0] if data else ""
def toScriptLine(
def toScript(
self
) -> str:
"""
@@ -422,7 +376,7 @@ class ActionStepFrame(QFrame):
return " -- pass"
if not target:
return ""
rawVal = self._getValueRaw()
rawVal = self.getValueRaw()
vartype = self._currentTargetType
if op == "set":
encoded = encodeValueStr(rawVal, vartype)
@@ -445,8 +399,7 @@ class ActionStepFrame(QFrame):
return f" {target} = {target} - {rawVal}"
return ""
def _getValueRaw(
def getValueRaw(
self
) -> str:
@@ -458,13 +411,12 @@ class ActionStepFrame(QFrame):
return getValueFromWidget(w)
return ""
def refreshVarCombos(
self
):
currentData = self.targetCombo.currentData()
self.buildTargetCombo()
self.populateTargetCombo()
if currentData:
for i in range(self.targetCombo.count()):
d = self.targetCombo.itemData(i)
@@ -472,3 +424,41 @@ class ActionStepFrame(QFrame):
self.targetCombo.setCurrentIndex(i)
break
self._varMgr.populateCombo(self.existingVarCombo)
@Slot(int)
def onTargetChanged(
self,
idx
):
if idx < 0:
return
data = self.targetCombo.itemData(idx)
if not data:
return
_, vartype = data
self._currentTargetType = vartype
self.updateValueWidget()
self.onValueSrcChanged(self.valueSrcCombo.currentIndex())
@Slot(int)
def onOpTypeChanged(
self,
idx
):
self.updateValueWidget()
@Slot(int)
def onValueSrcChanged(
self,
idx
):
isVar = (self.valueSrcCombo.currentData() == "variable")
self.valueStack.setVisible(not isVar)
self.existingVarCombo.setVisible(isVar)
if isVar:
self._varMgr.populateCombo(self.existingVarCombo)
else:
self.updateValueWidget()
+31 -46
View File
@@ -10,28 +10,46 @@ See the LICENSE file for details.
import os
from PySide6.QtCore import (
Qt, Signal, Slot, QTime, QDate, QDir, QFileInfo
)
from PySide6.QtWidgets import (
QDialog, QWidget, QLineEdit, QMessageBox, QFileDialog,
QTreeWidgetItem, QMenu, QInputDialog
QDate,
QDir,
QFileInfo,
Qt,
QTime,
Signal,
Slot
)
from PySide6.QtGui import (
QCloseEvent, QAction
QAction,
QCloseEvent
)
from PySide6.QtWidgets import (
QDialog,
QFileDialog,
QInputDialog,
QLineEdit,
QMenu,
QMessageBox,
QTreeWidgetItem,
QWidget
)
import managers.config.ConfigManager as ConfigManager
from utils.JSONReader import JSONReader
from utils.JSONWriter import JSONWriter
from interfaces.ConfigProvider import ConfigProvider, CfgKey
from managers.config.ConfigUtils import ConfigUtils
from gui.resources.ui.Ui_ALConfigWidget import Ui_ALConfigWidget
from gui.ALSeatMapSelectDialog import ALSeatMapSelectDialog
from gui.ALSeatMapTable import ALSeatMapTable
from gui.ALUserTreeWidget import ALUserTreeWidget, ALUserTreeItemType
from gui.ALUserTreeWidget import (
ALUserTreeItemType,
ALUserTreeWidget
)
from gui.ALWebDriverDownloadDialog import ALWebDriverDownloadDialog
from gui.resources.ui.Ui_ALConfigWidget import Ui_ALConfigWidget
from interfaces.ConfigProvider import (
CfgKey,
ConfigProvider
)
from managers.config.ConfigUtils import ConfigUtils
from utils.JSONReader import JSONReader
from utils.JSONWriter import JSONWriter
class ALConfigWidget(QWidget, Ui_ALConfigWidget):
@@ -54,7 +72,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
if not self.initializeConfigs():
self.close()
def modifyUi(
self
):
@@ -70,7 +87,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.initializeFloorRoomMap()
self.initializeUserInfoWidget()
def connectSignals(
self
):
@@ -94,7 +110,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.ConfirmButton.clicked.connect(self.onConfirmButtonClicked)
self.CancelButton.clicked.connect(self.onCancelButtonClicked)
def showEvent(
self,
event
@@ -118,7 +133,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
return result
def closeEvent(
self,
event: QCloseEvent
@@ -127,7 +141,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.configWidgetIsClosed.emit()
super().closeEvent(event)
def initializeFloorRoomMap(
self
):
@@ -161,7 +174,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
"五层": ["五层考研"]
}
def initializeConfigToWidget(
self,
which: str,
@@ -176,7 +188,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.setUsersToTreeWidget(config_data)
self.CurrentUserConfigEdit.setText(self.__config_paths["user"])
def initializeConfig(
self,
which: str
@@ -210,7 +221,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
is_success = False
return is_success
def initializeConfigs(
self
) -> bool:
@@ -223,7 +233,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.initializeConfigToWidget(which, self.__config_data[which])
return is_success
def defaultRunConfig(
self
) -> dict:
@@ -247,7 +256,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
}
}
def defaultUserConfig(
self
) -> dict:
@@ -257,7 +265,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
]
}
def collectRunConfigFromWidget(
self
) -> dict:
@@ -279,7 +286,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
run_config["mode"]["run_mode"] = run_mode
return run_config
def setRunConfigToWidget(
self,
run_config: dict
@@ -318,7 +324,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
"文件可能被意外修改或已经损坏\n"
)
def initializeUserInfoWidget(
self
):
@@ -343,7 +348,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.MaxRenewTimeDiffSpinBox.setValue(30)
self.PreferLateRenewTimeCheckBox.setChecked(False)
def collectUserFromWidget(
self
) -> dict:
@@ -376,7 +380,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
user["reserve_info"]["renew_time"]["prefer_early"] = not self.PreferLateRenewTimeCheckBox.isChecked()
return user
def collectUsersFromTreeWidget(
self
) -> dict:
@@ -399,7 +402,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
user_config["groups"].append(group_config)
return user_config
def setUserToWidget(
self,
user: dict
@@ -441,7 +443,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
"文件可能被意外修改或已经损坏\n"
)
def setUsersToTreeWidget(
self,
users: dict
@@ -483,7 +484,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
finally:
self.UserTreeWidget.itemChanged.connect(self.onUserTreeWidgetItemChanged)
def loadRunConfig(
self,
run_config_path: str
@@ -507,7 +507,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
)
return None
def saveRunConfig(
self,
run_config_path: str,
@@ -529,7 +528,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
)
return False
def loadUserConfig(
self,
user_config_path: str
@@ -563,7 +561,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
)
return None
def saveUserConfig(
self,
user_config_path: str,
@@ -585,7 +582,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
)
return False
def saveConfigs(
self,
run_config_path: str,
@@ -608,7 +604,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
return False
return True
def loadConfig(
self,
config_path: str
@@ -637,7 +632,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
except:
return False
def addGroup(
self,
group_name: str = ""
@@ -654,7 +648,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.UserTreeWidget.itemChanged.connect(self.onUserTreeWidgetItemChanged)
return group_item
def delGroup(
self,
group_item: QTreeWidgetItem = None
@@ -667,7 +660,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
index = self.UserTreeWidget.indexOfTopLevelItem(group_item)
self.UserTreeWidget.takeTopLevelItem(index)
def addUser(
self,
group_item: QTreeWidgetItem = None
@@ -722,7 +714,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.UserTreeWidget.itemChanged.connect(self.onUserTreeWidgetItemChanged)
return user_item
def delUser(
self,
user_item: QTreeWidgetItem = None
@@ -738,7 +729,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
if parent_item.childCount() == 0:
self.UserTreeWidget.setCurrentItem(None)
def renameItem(
self,
item: QTreeWidgetItem,
@@ -862,7 +852,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
is_checked = item.checkState(1) == Qt.CheckState.Checked
item.setText(1, "" if is_checked else "跳过")
def showTreeMenu(
self,
menu: QMenu
@@ -872,7 +861,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
add_group_action.triggered.connect(self.addGroup)
menu.addAction(add_group_action)
def showGroupMenu(
self,
menu: QMenu,
@@ -892,7 +880,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
if group_item.checkState(1) == Qt.CheckState.Unchecked:
add_user_action.setEnabled(False)
def showUserMenu(
self,
menu: QMenu,
@@ -952,7 +939,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
if browser_driver_path:
self.BrowseBrowserDriverEdit.setText(QDir.toNativeSeparators(browser_driver_path))
@Slot()
def onAutoDownloadWebDriverButtonClicked(
self
@@ -966,7 +952,6 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
self.BrowserTypeComboBox.setCurrentText(selected_driver_info.driver_type.value)
self.BrowseBrowserDriverEdit.setText(QDir.toNativeSeparators(str(selected_driver_info.driver_path)))
@Slot()
def onBrowseCurrentRunConfigButtonClicked(
self
+25 -25
View File
@@ -10,24 +10,37 @@ See the LICENSE file for details.
import queue
from PySide6.QtCore import (
Qt, Signal, Slot, QTimer, QUrl,
)
from PySide6.QtWidgets import (
QMainWindow, QMenu, QSystemTrayIcon, QMessageBox
QTimer,
QUrl,
Qt,
Signal,
Slot
)
from PySide6.QtGui import (
QTextCursor, QCloseEvent, QFont, QIcon, QDesktopServices
QCloseEvent,
QDesktopServices,
QFont,
QIcon,
QTextCursor
)
from PySide6.QtWidgets import (
QMainWindow,
QMenu,
QMessageBox,
QSystemTrayIcon
)
from base.MsgBase import MsgBase
from managers.config.ConfigUtils import ConfigUtils
from gui.resources.ui.Ui_ALMainWindow import Ui_ALMainWindow
from gui.resources import ALResource
from gui.ALConfigWidget import ALConfigWidget
from gui.ALTimerTaskManageWidget import ALTimerTaskManageWidget
from gui.ALAboutDialog import ALAboutDialog
from gui.ALMainWorkers import TimerTaskWorker, AutoLibWorker
from gui.ALConfigWidget import ALConfigWidget
from gui.ALMainWorkers import (
AutoLibWorker,
TimerTaskWorker
)
from gui.ALTimerTaskManageWidget import ALTimerTaskManageWidget
from gui.resources import ALResource
from gui.resources.ui.Ui_ALMainWindow import Ui_ALMainWindow
from managers.config.ConfigUtils import ConfigUtils
class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
@@ -59,7 +72,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.startTimerTaskPolling()
self._showLog("主窗口初始化完成")
def modifyUi(
self
):
@@ -90,7 +102,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.__alTimerTaskManageWidget.timerTaskManageWidgetIsClosed.connect(self.onTimerTaskManageWidgetClosed)
self.__alTimerTaskManageWidget.setWindowFlags(Qt.WindowType.Window|Qt.WindowType.WindowCloseButtonHint)
def onAboutActionTriggered(
self
):
@@ -98,7 +109,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
about_dialog = ALAboutDialog(self)
about_dialog.exec()
def onManualActionTriggered(
self
):
@@ -106,7 +116,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
url = QUrl("https://www.autolibrary.kenanzhu.com/manuals")
QDesktopServices.openUrl(url)
def setupTray(
self
):
@@ -128,7 +137,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.TrayIcon.activated.connect(self.onTrayIconActivated)
self.TrayIcon.show()
def hideToTray(
self
):
@@ -141,7 +149,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
2000
)
def onTrayIconActivated(
self,
reason: QSystemTrayIcon.ActivationReason
@@ -150,7 +157,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
if reason == QSystemTrayIcon.DoubleClick:
self.showNormal()
def connectSignals(
self
):
@@ -162,7 +168,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.SendButton.clicked.connect(self.onSendButtonClicked)
self.MessageEdit.returnPressed.connect(self.onSendButtonClicked)
def closeEvent(
self,
event: QCloseEvent
@@ -188,7 +193,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self._showLog("主窗口关闭")
QMainWindow.closeEvent(self, event)
def appendToTextEdit(
self,
text: str
@@ -202,7 +206,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
scrollbar = self.MessageIOTextEdit.verticalScrollBar()
scrollbar.setValue(scrollbar.maximum())
def startMsgPolling(
self
):
@@ -211,7 +214,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.__msg_queue_timer.timeout.connect(self.pollMsgQueue)
self.__msg_queue_timer.start(100)
def startTimerTaskPolling(
self
):
@@ -220,7 +222,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.__timer_task_timer.timeout.connect(self.pollTimerTaskQueue)
self.__timer_task_timer.start(500)
def pollTimerTaskQueue(
self
):
@@ -254,7 +255,6 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.__is_running_timer_task = False
pass
def setControlButtons(
self,
config_button_enabled: bool,
-6
View File
@@ -37,7 +37,6 @@ class AutoLibWorker(MsgBase, QThread):
QThread.__init__(self)
self.__config_paths = config_paths
def checkTimeAvailable(
self,
) -> bool:
@@ -52,7 +51,6 @@ class AutoLibWorker(MsgBase, QThread):
self._showLog(f"时间检查通过, 当前时间: {current_time}", self.TraceLevel.INFO)
return True
def checkConfigPaths(
self,
) -> bool:
@@ -68,7 +66,6 @@ class AutoLibWorker(MsgBase, QThread):
self._showLog(f"配置文件路径检查通过, 路径: {self.__config_paths}", self.TraceLevel.INFO)
return True
def loadConfigs(
self
) -> bool:
@@ -101,7 +98,6 @@ class AutoLibWorker(MsgBase, QThread):
)
return True
def run(
self
):
@@ -161,7 +157,6 @@ class TimerTaskWorker(AutoLibWorker):
self.autoLibWorkerIsFinished.connect(self.onTimerTaskIsFinished)
self.autoLibWorkerFinishedWithError.connect(self.onTimerTaskFinishedWithError)
def run(
self
):
@@ -206,7 +201,6 @@ class TimerTaskWorker(AutoLibWorker):
self._showTrace(f"定时任务 {self.__timer_task['name']} 运行结束")
self.timerTaskWorkerIsFinished.emit(False, self.__timer_task)
def applyRepeatAutoScript(
self
):
-4
View File
@@ -31,7 +31,6 @@ class ALSeatFrame(QFrame):
self.setupUi()
def setupUi(
self
):
@@ -55,7 +54,6 @@ class ALSeatFrame(QFrame):
self.Label.setAlignment(Qt.AlignCenter)
self.Label.setGeometry(0, 0, 60, 40)
def mousePressEvent(
self,
event
@@ -65,14 +63,12 @@ class ALSeatFrame(QFrame):
self.toggleSelection()
self.clicked.emit(self.__seat_number)
def isSelected(
self
):
return self.__is_selected
def toggleSelection(self):
self.__is_selected = not self.__is_selected
+10 -13
View File
@@ -8,15 +8,20 @@ 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 (
Qt, Slot, Signal
)
from PySide6.QtWidgets import (
QDialog, QLabel, QHBoxLayout, QVBoxLayout,
QPushButton,
Qt,
Signal,
Slot
)
from PySide6.QtGui import (
QCloseEvent
)
from PySide6.QtWidgets import (
QDialog,
QHBoxLayout,
QLabel,
QPushButton,
QVBoxLayout
)
from gui.ALSeatMapView import ALSeatMapView
@@ -42,7 +47,6 @@ class ALSeatMapSelectDialog(QDialog):
self.setupUi()
self.connectSignals()
def setupUi(
self
):
@@ -85,7 +89,6 @@ class ALSeatMapSelectDialog(QDialog):
self.SeatMapWidgetControlLayout.addWidget(self.ConfirmButton)
self.SeatMapWidgetMainLayout.addLayout(self.SeatMapWidgetControlLayout)
def connectSignals(
self
):
@@ -93,7 +96,6 @@ class ALSeatMapSelectDialog(QDialog):
self.ConfirmButton.clicked.connect(self.onConfirmButtonClicked)
self.CancelButton.clicked.connect(self.onCancelButtonClicked)
def showEvent(
self,
event
@@ -117,7 +119,6 @@ class ALSeatMapSelectDialog(QDialog):
return result
def closeEvent(
self,
event: QCloseEvent
@@ -131,7 +132,6 @@ class ALSeatMapSelectDialog(QDialog):
self.seatMapSelectDialogIsClosed.emit(self.getSelectedSeats())
super().closeEvent(event)
def selectSeat(
self,
seat_number: str
@@ -139,7 +139,6 @@ class ALSeatMapSelectDialog(QDialog):
self.SeatMapGraphicsView.selectSeat(seat_number)
def selectSeats(
self,
seat_numbers: list[str]
@@ -147,14 +146,12 @@ class ALSeatMapSelectDialog(QDialog):
return self.SeatMapGraphicsView.selectSeats(seat_numbers)
def getSelectedSeats(
self
) -> list[str]:
return self.SeatMapGraphicsView.getSelectedSeats()
def clearSelections(
self
):
+19 -22
View File
@@ -11,11 +11,16 @@ from PySide6.QtCore import (
Qt, Slot, QEvent
)
from PySide6.QtWidgets import (
QFrame, QWidget,
QGridLayout, QGraphicsView, QGraphicsScene, QGraphicsItem
QFrame,
QWidget,
QGridLayout,
QGraphicsView,
QGraphicsScene,
QGraphicsItem
)
from PySide6.QtGui import (
QPainter, QWheelEvent
QPainter,
QWheelEvent
)
from gui.ALSeatFrame import ALSeatFrame
@@ -35,18 +40,6 @@ class ALSeatMapView(QGraphicsView):
self.setupUi()
@staticmethod
def formatSeatNumber(
seat_number: str
) -> str:
if seat_number and not seat_number[-1].isdigit():
digits = seat_number[:-1]
letter = seat_number[-1]
return digits.zfill(3) + letter
return seat_number.zfill(3)
def eventFilter(
self,
watched,
@@ -61,7 +54,6 @@ class ALSeatMapView(QGraphicsView):
return True
return super().eventFilter(watched, event)
def zoomGraphicsView(
self,
event: QWheelEvent
@@ -80,7 +72,6 @@ class ALSeatMapView(QGraphicsView):
self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
self.scale(zoom_factor, zoom_factor)
def setupUi(
self
):
@@ -100,7 +91,6 @@ class ALSeatMapView(QGraphicsView):
self.ContainerProxy = self.SeatMapGraphicsScene.addWidget(self.SeatsContainerWidget)
self.ContainerProxy.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable, False)
def setupSeatMap(
self
):
@@ -125,7 +115,6 @@ class ALSeatMapView(QGraphicsView):
self.SeatsContainerLayout.setContentsMargins(20, 20, 20, 20)
self.SeatsContainerWidget.adjustSize()
def selectSeat(
self,
seat_number: str
@@ -142,7 +131,6 @@ class ALSeatMapView(QGraphicsView):
widget.toggleSelection()
self.__selected_seats.append(seat_number)
def selectSeats(
self,
selected_seats: list
@@ -152,14 +140,12 @@ class ALSeatMapView(QGraphicsView):
for seat_number in selected_seats:
self.selectSeat(seat_number)
def getSelectedSeats(
self
) -> list[str]:
return self.__selected_seats
def clearSelections(
self
):
@@ -186,3 +172,14 @@ class ALSeatMapView(QGraphicsView):
self.__selected_seats.append(seat_number)
else:
self.__seat_frames[seat_number].toggleSelection()
@staticmethod
def formatSeatNumber(
seat_number: str
) -> str:
if seat_number and not seat_number[-1].isdigit():
digits = seat_number[:-1]
letter = seat_number[-1]
return digits.zfill(3) + letter
return seat_number.zfill(3)
+11 -9
View File
@@ -9,14 +9,20 @@ See the LICENSE file for details.
"""
from enum import Enum
from PySide6.QtWidgets import (
QLabel
)
from PySide6.QtCore import (
Qt, Property, QPropertyAnimation, QEasingCurve
Property,
QEasingCurve,
QPropertyAnimation,
Qt
)
from PySide6.QtGui import (
QPainter, QColor, QConicalGradient, QPalette
QColor,
QConicalGradient,
QPainter,
QPalette
)
from PySide6.QtWidgets import (
QLabel
)
@@ -44,7 +50,6 @@ class ALStatusLabel(QLabel):
self.setupUi()
def setupUi(
self
):
@@ -59,14 +64,12 @@ class ALStatusLabel(QLabel):
self.RunningAnimation.setLoopCount(-1)
self.RunningAnimation.setEasingCurve(QEasingCurve.Type.Linear)
def isDarkMode(
self
) -> bool:
return self.palette().color(QPalette.ColorRole.Window).value() < 128
def getMarkColor(
self
) -> QColor:
@@ -111,7 +114,6 @@ class ALStatusLabel(QLabel):
self.__icon_angle = value
self.update()
def paintEvent(
self,
event
+5 -9
View File
@@ -49,7 +49,6 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
if self.__edit_timer_task:
self.loadTask(self.__edit_timer_task)
def modifyUi(
self
):
@@ -101,10 +100,10 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
self.AutoScriptLayout.setContentsMargins(3, 3, 3, 3)
self.AutoScriptLayout.setSpacing(3)
autoScriptBtnLayout = QHBoxLayout()
self.AutoScriptPreviewButton = QPushButton("编辑")
self.AutoScriptPreviewButton.setMinimumHeight(25)
self.AutoScriptPreviewButton.setFixedWidth(60)
autoScriptBtnLayout.addWidget(self.AutoScriptPreviewButton)
self.AutoScriptEditButton = QPushButton("编辑")
self.AutoScriptEditButton.setMinimumHeight(25)
self.AutoScriptEditButton.setFixedWidth(80)
autoScriptBtnLayout.addWidget(self.AutoScriptEditButton)
autoScriptBtnLayout.addStretch()
self.AutoScriptHelpButton = QPushButton("?")
self.AutoScriptHelpButton.setFixedSize(20, 20)
@@ -133,7 +132,6 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
self.__auto_script = ""
self.__mock_target_data = None
def loadTask(
self,
task: dict
@@ -174,7 +172,6 @@ class ALTimerTaskAddDialog(QDialog, Ui_ALTimerTaskAddDialog):
self.__mock_target_data = mock_data
self.ConfirmButton.setText("保存")
def connectSignals(
self
):
@@ -183,10 +180,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.AutoScriptPreviewButton.clicked.connect(self.onPreviewAutoScript)
self.AutoScriptEditButton.clicked.connect(self.onPreviewAutoScript)
self.AutoScriptHelpButton.clicked.connect(self.onAutoScriptHelp)
def getTimerTask(
self
) -> dict:
+5 -10
View File
@@ -34,7 +34,6 @@ class ALTimerTaskHistoryDialog(QDialog):
self.setupUi()
self.connectSignals()
def setupUi(
self
):
@@ -82,7 +81,6 @@ class ALTimerTaskHistoryDialog(QDialog):
ButtonLayout.addWidget(self.CloseButton)
MainLayout.addLayout(ButtonLayout)
def connectSignals(
self
):
@@ -90,7 +88,6 @@ class ALTimerTaskHistoryDialog(QDialog):
self.CloseButton.clicked.connect(self.accept)
self.ClearHistoryButton.clicked.connect(self.onClearHistoryButtonClicked)
def loadHistory(
self
):
@@ -99,6 +96,11 @@ class ALTimerTaskHistoryDialog(QDialog):
for row, record in enumerate(self.__history):
self.addHistoryRow(row, record)
def getHistory(
self
) -> list:
return self.__history
def addHistoryRow(
self,
@@ -129,13 +131,6 @@ 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
+27 -29
View File
@@ -15,24 +15,40 @@ from enum import Enum
from datetime import datetime, timedelta
from PySide6.QtCore import (
Qt, Signal, Slot, QTimer
)
from PySide6.QtWidgets import (
QDialog, QWidget, QListWidgetItem, QMessageBox,
QHBoxLayout, QVBoxLayout, QLabel, QPushButton, QMenu
QTimer,
Qt,
Signal,
Slot
)
from PySide6.QtGui import (
QCloseEvent, QAction
QAction,
QCloseEvent
)
from PySide6.QtWidgets import (
QDialog,
QHBoxLayout,
QLabel,
QListWidgetItem,
QMenu,
QMessageBox,
QPushButton,
QVBoxLayout,
QWidget
)
import managers.config.ConfigManager as ConfigManager
from utils.TimerUtils import TimerUtils
from interfaces.ConfigProvider import ConfigProvider, CfgKey
from gui.resources.ui.Ui_ALTimerTaskManageWidget import Ui_ALTimerTaskManageWidget
from gui.ALTimerTaskAddDialog import ALTimerTaskAddDialog, ALTimerTaskStatus
from gui.ALTimerTaskAddDialog import (
ALTimerTaskAddDialog,
ALTimerTaskStatus
)
from gui.ALTimerTaskHistoryDialog import ALTimerTaskHistoryDialog
from gui.resources.ui.Ui_ALTimerTaskManageWidget import Ui_ALTimerTaskManageWidget
from interfaces.ConfigProvider import (
CfgKey,
ConfigProvider
)
from utils.TimerUtils import TimerUtils
class ALTimerTaskItemWidget(QWidget):
@@ -53,7 +69,6 @@ class ALTimerTaskItemWidget(QWidget):
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.customContextMenuRequested.connect(self.showContextMenu)
def modifyUi(
self
):
@@ -204,7 +219,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
if not self.initializeTimerTasks():
raise Exception("定时任务配置文件初始化失败 !")
def connectSignals(
self
):
@@ -215,7 +229,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.TimerTaskSortOrderToggleButton.clicked.connect(self.onSortOrderToggleButtonClicked)
self.timerTasksChanged.connect(self.onTimerTasksChanged)
def setupTimer(
self
):
@@ -224,7 +237,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.__check_timer.timeout.connect(self.checkTasks)
self.__check_timer.start(500)
def initializeTimerTasks(
self
) -> bool:
@@ -240,7 +252,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
return True
return False
def getTimerTasks(
self
) -> list:
@@ -265,7 +276,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
)
return None
def setTimerTasks(
self,
timer_tasks: list
@@ -289,7 +299,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
)
return False
def showEvent(
self,
event
@@ -313,7 +322,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
return result
def closeEvent(
self,
event: QCloseEvent
@@ -323,7 +331,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.timerTaskManageWidgetIsClosed.emit()
event.ignore()
def sortTimerTasks(
self,
policy: SortPolicy = SortPolicy.BY_EXECUTE_TIME,
@@ -346,7 +353,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
reverse = order is Qt.SortOrder.DescendingOrder
)
def updateStat(
self
):
@@ -373,7 +379,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.ExecutedTaskLabel.setText(f"已执行:{executed}")
self.InvalidTaskLabel.setText(f"无效的:{invalid}")
def updateTimerTaskList(
self
):
@@ -396,7 +401,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.TimerTasksListWidget.addItem(item)
self.TimerTasksListWidget.setItemWidget(item, widget)
def addTask(
self
):
@@ -407,7 +411,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.__timer_tasks.append(timer_task)
self.timerTasksChanged.emit()
def editTask(
self,
timer_task: dict
@@ -440,7 +443,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
f"已记录次数:{history_count}"
)
def deleteTask(
self,
timer_task: dict
@@ -469,7 +471,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
]
self.timerTasksChanged.emit()
def clearAllTasks(
self
):
@@ -531,7 +532,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
self.__timer_tasks.clear()
self.timerTasksChanged.emit()
def showTaskHistory(
self,
task: dict
@@ -541,7 +541,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
if dialog.exec() == QDialog.DialogCode.Accepted:
self.timerTasksChanged.emit()
def checkTasks(
self
):
@@ -615,7 +614,6 @@ class ALTimerTaskManageWidget(QWidget, Ui_ALTimerTaskManageWidget):
break
self.timerTasksChanged.emit()
def onRepeatTimerTaskIs(
self,
status: ALTimerTaskStatus,
+12 -10
View File
@@ -10,14 +10,22 @@ See the LICENSE file for details.
from enum import Enum
from PySide6.QtCore import (
Qt, QSize, QCoreApplication, QRect, QPoint
Qt,
QSize,
QCoreApplication,
QRect,
QPoint
)
from PySide6.QtWidgets import (
QAbstractScrollArea, QAbstractItemView,
QTreeWidget, QTreeWidgetItem
QAbstractScrollArea,
QAbstractItemView,
QTreeWidget,
QTreeWidgetItem
)
from PySide6.QtGui import (
QDragEnterEvent, QDragMoveEvent, QDropEvent
QDragEnterEvent,
QDragMoveEvent,
QDropEvent
)
@@ -39,7 +47,6 @@ class ALUserTreeWidget(QTreeWidget):
self.setupUi()
self.translateUi()
def setupUi(
self
):
@@ -70,7 +77,6 @@ class ALUserTreeWidget(QTreeWidget):
self.header().setHighlightSections(False)
self.header().setProperty(u"showSortIndicator", True)
def translateUi(
self
):
@@ -78,7 +84,6 @@ class ALUserTreeWidget(QTreeWidget):
___qtreewidgetitem = self.headerItem()
___qtreewidgetitem.setText(1, QCoreApplication.translate("ALConfigWidget", u"\u72b6\u6001", None));
@staticmethod
def isDragPositionValid(
target_rect: QRect,
@@ -90,7 +95,6 @@ class ALUserTreeWidget(QTreeWidget):
y_offset < target_rect.height()*0.8)
return valid
def dragEnterEvent(
self,
event: QDragEnterEvent
@@ -98,7 +102,6 @@ class ALUserTreeWidget(QTreeWidget):
super().dragEnterEvent(event)
def dragMoveEvent(
self,
event: QDragMoveEvent
@@ -136,7 +139,6 @@ class ALUserTreeWidget(QTreeWidget):
return
event.acceptProposedAction()
def dropEvent(
self,
event: QDropEvent
+137 -140
View File
@@ -11,20 +11,30 @@ import threading
from typing import Optional
from PySide6.QtCore import (
Qt, Slot, QThread, Signal
Qt,
Slot,
QThread,
Signal
)
from PySide6.QtWidgets import (
QDialog, QLabel, QComboBox, QProgressBar,
QPushButton, QVBoxLayout, QHBoxLayout,
QMessageBox, QFrame, QLineEdit
)
from PySide6.QtGui import (
QCloseEvent
QDialog,
QLabel,
QComboBox,
QProgressBar,
QPushButton,
QVBoxLayout,
QHBoxLayout,
QMessageBox,
QFrame,
QLineEdit
)
from PySide6.QtGui import QCloseEvent
from managers.driver.WebDriverManager import (
instance as webdriver_manager_instance,
WebDriverManager, WebDriverInfo, WebDriverType,
instance as webdriverManagerInstance,
WebDriverManager,
WebDriverInfo,
WebDriverType,
WebDriverStatus
)
from gui.ALStatusLabel import ALStatusLabel
@@ -142,7 +152,6 @@ class ALWebDriverDownloadDialog(QDialog):
self.initializeDriverManager()
self.refreshDriverList()
def showEvent(
self,
event
@@ -165,7 +174,6 @@ class ALWebDriverDownloadDialog(QDialog):
self.move(target_pos)
return result
def setupUi(
self
):
@@ -237,7 +245,6 @@ class ALWebDriverDownloadDialog(QDialog):
self.ControlLayout.addWidget(self.ConfirmButton)
self.MainLayout.addLayout(self.ControlLayout)
def connectSignals(
self
):
@@ -249,18 +256,16 @@ class ALWebDriverDownloadDialog(QDialog):
self.ConfirmButton.clicked.connect(self.onConfirmButtonClicked)
self.DriverComboBox.currentIndexChanged.connect(self.onDriverComboBoxChanged)
def initializeDriverManager(
self
):
try:
self.__driver_manager = webdriver_manager_instance(self.__driver_dir)
self.__driver_manager = webdriverManagerInstance(self.__driver_dir)
except ValueError as e:
QMessageBox.warning(self, "初始化失败", f"WebDriverManager 初始化失败:\n{str(e)}")
self.reject()
def refreshDriverList(
self
):
@@ -270,18 +275,20 @@ class ALWebDriverDownloadDialog(QDialog):
self.__driver_manager.refresh()
self.__driver_infos = self.__driver_manager.getDriverInfos()
self.DriverComboBox.clear()
installed = 0
installed_idx = 0
for i, driver_info in enumerate(self.__driver_infos):
if driver_info.driver_status == WebDriverStatus.INSTALLED:
installed_idx = i # get the installed driver index
display_text = f"{driver_info.driver_type.value} - {driver_info.browser_version}"
if driver_info.driver_status == WebDriverStatus.INSTALLED:
installed += 1
installed_idx = i # get the installed driver index
display_text += " : 已安装"
self.DriverComboBox.addItem(display_text)
count = len(self.__driver_infos)
self.BrowserCountLabel.setText(f"检测到 {count} 个可用浏览器:")
self.BrowserCountLabel.setText(f"检测到 {count} 个可用浏览器{installed} 个已安装驱动")
if self.__driver_infos:
self.DriverComboBox.setCurrentIndex(installed_idx)
def onDriverComboBoxChanged(
self,
index: int
@@ -294,6 +301,116 @@ class ALWebDriverDownloadDialog(QDialog):
self.updateProgressBarStates(driver_info)
self.updateButtonStates(driver_info)
def closeEvent(
self,
event: QCloseEvent
):
if self.__download_thread and self.__download_thread.isRunning():
reply = QMessageBox.question(
self,
"确认关闭 - AutoLibrary",
"驱动正在下载中, 确定要取消并关闭对话框吗 ?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply == QMessageBox.StandardButton.No:
event.ignore()
return
self.__download_thread.stop()
if not self.__confirmed:
self.__selected_driver_info = None
event.accept()
super().closeEvent(event)
def onThreadFinished(
self
):
if self.__download_thread:
self.__download_thread.deleteLater()
self.__download_thread = None
def getSelectedDriverInfo(
self
) -> Optional[WebDriverInfo]:
return self.__selected_driver_info
def updateDriverInfoDisplay(
self,
driver_info: WebDriverInfo
):
if driver_info.driver_type == WebDriverType.CHROME:
driver_type = "Google Chrome"
elif driver_info.driver_type == WebDriverType.FIREFOX:
driver_type = "Mozilla Firefox"
elif driver_info.driver_type == WebDriverType.EDGE:
driver_type = "Microsoft Edge"
else:
driver_type = "未知"
self.BrowserTypeLabel.setText(f"类型:{driver_type}")
self.VersionLabel.setText(f"版本:{driver_info.driver_version}")
if driver_info.driver_path:
self.PathLabel.setText(str(driver_info.driver_path))
else:
self.PathLabel.setText("未安装")
match driver_info.driver_status:
case WebDriverStatus.NOT_INSTALLED:
self.StatusLabel.status = ALStatusLabel.Status.WAITING
case WebDriverStatus.INSTALLED:
self.StatusLabel.status = ALStatusLabel.Status.SUCCESS
case WebDriverStatus.DOWNLOADING:
self.StatusLabel.status = ALStatusLabel.Status.RUNNING
case WebDriverStatus.ERROR:
self.StatusLabel.status = ALStatusLabel.Status.FAILURE
def updateProgressBarStates(
self,
driver_info: WebDriverInfo
):
if driver_info.driver_status == WebDriverStatus.NOT_INSTALLED:
self.ProgressBar.setValue(0)
self.ProgressText.setText("未安装")
elif driver_info.driver_status == WebDriverStatus.INSTALLED:
self.ProgressBar.setValue(100)
self.ProgressText.setText("已安装")
elif driver_info.driver_status == WebDriverStatus.DOWNLOADING:
pass # update by worker thread
elif driver_info.driver_status == WebDriverStatus.ERROR:
self.ProgressBar.setValue(0)
self.ProgressText.setText("下载失败")
def updateButtonStates(
self,
driver_info: WebDriverInfo
):
if driver_info.driver_status == WebDriverStatus.NOT_INSTALLED:
self.RefreshButton.setEnabled(True)
self.DeleteButton.setEnabled(False)
self.DownloadButton.setEnabled(True)
self.CancelButton.setEnabled(True)
self.ConfirmButton.setEnabled(False)
elif driver_info.driver_status == WebDriverStatus.INSTALLED:
self.RefreshButton.setEnabled(True)
self.DownloadButton.setEnabled(False)
self.DeleteButton.setEnabled(True)
self.CancelButton.setEnabled(True)
self.ConfirmButton.setEnabled(True)
elif driver_info.driver_status == WebDriverStatus.DOWNLOADING:
self.RefreshButton.setEnabled(False)
self.DownloadButton.setEnabled(False)
self.DeleteButton.setEnabled(False)
self.CancelButton.setEnabled(True)
self.ConfirmButton.setEnabled(False)
elif driver_info.driver_status == WebDriverStatus.ERROR:
self.RefreshButton.setEnabled(True)
self.DownloadButton.setEnabled(True)
self.DeleteButton.setEnabled(False)
self.CancelButton.setEnabled(True)
self.ConfirmButton.setEnabled(False)
@Slot()
def onRefreshButtonClicked(
@@ -302,7 +419,6 @@ class ALWebDriverDownloadDialog(QDialog):
self.refreshDriverList()
@Slot()
def onDeleteButtonClicked(
self
@@ -355,7 +471,7 @@ class ALWebDriverDownloadDialog(QDialog):
self.__download_thread.downloadFinished.connect(self.onDownloadFinished)
self.__download_thread.downloadError.connect(self.onDownloadError)
self.__download_thread.downloadCancelled.connect(self.onDownloadCancelled)
self.__download_thread.finished.connect(self.__onThreadFinished)
self.__download_thread.finished.connect(self.onThreadFinished)
self.__download_thread.start()
@Slot()
@@ -406,7 +522,6 @@ class ALWebDriverDownloadDialog(QDialog):
self.updateButtonStates(driver_info)
QMessageBox.critical(self, "下载失败 - AutoLibrary", error_message)
@Slot()
def onDownloadCancelled(
self
@@ -423,7 +538,6 @@ class ALWebDriverDownloadDialog(QDialog):
self.updateButtonStates(driver_info)
self.ProgressText.setText("下载已取消")
@Slot()
def onConfirmButtonClicked(
self
@@ -439,7 +553,6 @@ class ALWebDriverDownloadDialog(QDialog):
self.__confirmed = True
self.accept()
@Slot()
def onCancelButtonClicked(
self
@@ -458,119 +571,3 @@ class ALWebDriverDownloadDialog(QDialog):
self.__confirmed = False
self.__selected_driver_info = None
self.reject()
def closeEvent(
self,
event: QCloseEvent
):
if self.__download_thread and self.__download_thread.isRunning():
reply = QMessageBox.question(
self,
"确认关闭 - AutoLibrary",
"驱动正在下载中, 确定要取消并关闭对话框吗 ?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply == QMessageBox.StandardButton.No:
event.ignore()
return
self.__download_thread.stop()
if not self.__confirmed:
self.__selected_driver_info = None
event.accept()
super().closeEvent(event)
def __onThreadFinished(
self
):
if self.__download_thread:
self.__download_thread.deleteLater()
self.__download_thread = None
def getSelectedDriverInfo(
self
) -> Optional[WebDriverInfo]:
return self.__selected_driver_info
def updateDriverInfoDisplay(
self,
driver_info: WebDriverInfo
):
if driver_info.driver_type == WebDriverType.CHROME:
driver_type = "Google Chrome"
elif driver_info.driver_type == WebDriverType.FIREFOX:
driver_type = "Mozilla Firefox"
elif driver_info.driver_type == WebDriverType.EDGE:
driver_type = "Microsoft Edge"
else:
driver_type = "未知"
self.BrowserTypeLabel.setText(f"类型:{driver_type}")
self.VersionLabel.setText(f"版本:{driver_info.driver_version}")
if driver_info.driver_path:
self.PathLabel.setText(str(driver_info.driver_path))
else:
self.PathLabel.setText("未安装")
match driver_info.driver_status:
case WebDriverStatus.NOT_INSTALLED:
self.StatusLabel.status = ALStatusLabel.Status.WAITING
case WebDriverStatus.INSTALLED:
self.StatusLabel.status = ALStatusLabel.Status.SUCCESS
case WebDriverStatus.DOWNLOADING:
self.StatusLabel.status = ALStatusLabel.Status.RUNNING
case WebDriverStatus.ERROR:
self.StatusLabel.status = ALStatusLabel.Status.FAILURE
def updateProgressBarStates(
self,
driver_info: WebDriverInfo
):
if driver_info.driver_status == WebDriverStatus.NOT_INSTALLED:
self.ProgressBar.setValue(0)
self.ProgressText.setText("未安装")
elif driver_info.driver_status == WebDriverStatus.INSTALLED:
self.ProgressBar.setValue(100)
self.ProgressText.setText("已安装")
elif driver_info.driver_status == WebDriverStatus.DOWNLOADING:
pass # update by worker thread
elif driver_info.driver_status == WebDriverStatus.ERROR:
self.ProgressBar.setValue(0)
self.ProgressText.setText("下载失败")
def updateButtonStates(
self,
driver_info: WebDriverInfo
):
if driver_info.driver_status == WebDriverStatus.NOT_INSTALLED:
self.RefreshButton.setEnabled(True)
self.DeleteButton.setEnabled(False)
self.DownloadButton.setEnabled(True)
self.CancelButton.setEnabled(True)
self.ConfirmButton.setEnabled(False)
elif driver_info.driver_status == WebDriverStatus.INSTALLED:
self.RefreshButton.setEnabled(True)
self.DownloadButton.setEnabled(False)
self.DeleteButton.setEnabled(True)
self.CancelButton.setEnabled(True)
self.ConfirmButton.setEnabled(True)
elif driver_info.driver_status == WebDriverStatus.DOWNLOADING:
self.RefreshButton.setEnabled(False)
self.DownloadButton.setEnabled(False)
self.DeleteButton.setEnabled(False)
self.CancelButton.setEnabled(True)
self.ConfirmButton.setEnabled(False)
elif driver_info.driver_status == WebDriverStatus.ERROR:
self.RefreshButton.setEnabled(True)
self.DownloadButton.setEnabled(True)
self.DeleteButton.setEnabled(False)
self.CancelButton.setEnabled(True)
self.ConfirmButton.setEnabled(False)
+2
View File
@@ -16,6 +16,7 @@ class ConfigType(Enum):
"""
Config type enum. Values represent the default filename.
"""
GLOBAL = "autolibrary.json"
BULLETIN = "bulletin.json"
TIMERTASK = "timer_task.json"
@@ -30,6 +31,7 @@ class ConfigPath:
Consumers pass this directly to ConfigProvider.get/set,
eliminating the need to import ConfigType separately.
"""
config_type: ConfigType
key: str = ""
+1 -7
View File
@@ -33,7 +33,6 @@ class ConfigTemplate:
self.__config_type = config_type
def template(
self
) -> dict:
@@ -83,7 +82,6 @@ class ConfigManager:
self.initialize()
def initialize(
self
):
@@ -91,7 +89,6 @@ class ConfigManager:
for config_type in ConfigType:
self.load(config_type)
def load(
self,
config_type: ConfigType
@@ -108,7 +105,6 @@ class ConfigManager:
self.__config_data[config_type.value] = ConfigTemplate(config_type).template()
JSONWriter(config_path, self.__config_data[config_type.value])
def get(
self,
key: ConfigPath,
@@ -126,7 +122,6 @@ class ConfigManager:
return default
return config_data.get(keys[-1], default)
def set(
self,
key: ConfigPath,
@@ -147,7 +142,6 @@ class ConfigManager:
config_data[keys[-1]] = value
self.save(key.config_type)
def save(
self,
config_type: ConfigType
@@ -156,7 +150,6 @@ class ConfigManager:
config_path = os.path.join(self.__config_dir, config_type.value)
JSONWriter(config_path, self.__config_data[config_type.value])
def configDir(
self
) -> str:
@@ -169,6 +162,7 @@ _config_manager_instance : ConfigManager | None = None
# Singleton instance of ConfigManager.
_instance_lock = threading.Lock()
def instance(
config_dir: str = ""
) -> ConfigManager:
+1 -2
View File
@@ -41,6 +41,7 @@ class WebBrowserArch(Enum):
MACX86_64 = 6
MACARM = 7
@dataclass
class WebBrowserInfo:
"""
@@ -70,7 +71,6 @@ class WebBrowserArchDetector:
pass
def detect(
self
) -> WebBrowserArch:
@@ -123,7 +123,6 @@ class WebBrowserDetector:
self.browser_arch = WebBrowserArchDetector().detect()
self.browser_infos : list[WebBrowserInfo] = []
def detect(
self
) -> list[WebBrowserInfo]:
+23 -31
View File
@@ -95,7 +95,6 @@ class WebDriverName:
self.driver_type = driver_type
def __str__(
self
) -> str:
@@ -125,7 +124,6 @@ class WebDriverExecName:
self.driver_type = driver_type
self.arch = arch
def __str__(
self
) -> str:
@@ -200,7 +198,6 @@ class WebDriverURL:
self.arch = arch
self.file_name = str(WebDriverFileName(self.version, self.driver_type, self.arch))
def __str__(
self
) -> str:
@@ -250,31 +247,6 @@ class WebDriverDownloader:
self.download_dir.mkdir(mode=0o0755, parents=True, exist_ok=True)
self.download_path = self.download_dir/str(WebDriverFileName(self.version, self.driver_type, self.arch))
def download(
self,
progress_callback: Optional[Callable[[float, int, float, str], None]] = None,
cancel_event: Optional[threading.Event] = None
) -> Optional[Path]:
try:
# downlaod file : 0% - 98%
if not self._download(progress_callback, cancel_event=cancel_event):
return None
# verify file : 98% - 99%
if not self._verify(progress_callback):
progress_callback(0, 100, 0.0, "验证失败")
return None
# extract file : 99% - 100%
driver_path = self._extract(progress_callback)
if not driver_path:
progress_callback(0, 100, 0.0, "解压失败")
return None
return driver_path
except Exception as e:
raise e
def _download(
self,
progress_callback: Optional[Callable[[float, int, float, str], None]] = None,
@@ -352,7 +324,6 @@ class WebDriverDownloader:
continue
raise e
def _verify(
self,
progress_callback: Optional[Callable[[float, int, float, str], None]] = None
@@ -361,7 +332,6 @@ class WebDriverDownloader:
progress_callback(98, 100, 0.0, "验证完成")
return True
def _extract(
self,
progress_callback: Optional[Callable[[float, int, float, str], None]] = None
@@ -397,7 +367,6 @@ class WebDriverDownloader:
except Exception:
return None
def _cleanup(
self,
driver_file: Path
@@ -410,6 +379,29 @@ class WebDriverDownloader:
else:
item.unlink()
def download(
self,
progress_callback: Optional[Callable[[float, int, float, str], None]] = None,
cancel_event: Optional[threading.Event] = None
) -> Optional[Path]:
try:
# downlaod file : 0% - 98%
if not self._download(progress_callback, cancel_event=cancel_event):
return None
# verify file : 98% - 99%
if not self._verify(progress_callback):
progress_callback(0, 100, 0.0, "验证失败")
return None
# extract file : 99% - 100%
driver_path = self._extract(progress_callback)
if not driver_path:
progress_callback(0, 100, 0.0, "解压失败")
return None
return driver_path
except Exception as e:
raise e
class ChromeDriverDownloader(WebDriverDownloader):
"""
-16
View File
@@ -81,7 +81,6 @@ class WebDriverManager:
self.initialize()
def initialize(
self
):
@@ -93,7 +92,6 @@ class WebDriverManager:
self._checkDriverStatus()
self.__initialized = True
def _detectBrowsers(
self
):
@@ -105,7 +103,6 @@ class WebDriverManager:
for info in browser_infos
]
def _checkDriverStatus(
self
):
@@ -117,7 +114,6 @@ class WebDriverManager:
driver_info.driver_path = driver_path
driver_info.driver_status = WebDriverStatus.INSTALLED
def _mapWebBrowserTypeToDriver(
self,
browser_type: WebBrowserType
@@ -132,7 +128,6 @@ class WebDriverManager:
else:
raise ValueError(f"不支持的 Web 浏览器类型 : {browser_type}")
def _mapWebBrowserArchToDriver(
self,
browser_type: WebBrowserType,
@@ -199,7 +194,6 @@ class WebDriverManager:
else:
raise ValueError(f"不支持的 Web 浏览器类型 : {browser_type}")
def _mapFirefoxDriverVersion(
self,
version: str
@@ -240,7 +234,6 @@ class WebDriverManager:
except Exception as e:
raise ValueError(f"无效的 Firefox 版本格式 : {version}") from e
def _getDriverInfo(
self,
browser_info: WebBrowserInfo
@@ -256,7 +249,6 @@ class WebDriverManager:
driver_info.browser_version = browser_info.browser_version
return driver_info
def _getDriverPath(
self,
driver_info: WebDriverInfo
@@ -286,7 +278,6 @@ class WebDriverManager:
driver_path = driver_dir/exe_name
return driver_path
def refresh(
self
):
@@ -294,7 +285,6 @@ class WebDriverManager:
self._detectBrowsers()
self._checkDriverStatus()
def getDriverInfos(
self
) -> list[WebDriverInfo]:
@@ -302,7 +292,6 @@ class WebDriverManager:
with self.__lock:
return self.__driver_infos.copy()
def getDriverInfo(
self,
driver_type: WebDriverType
@@ -315,7 +304,6 @@ class WebDriverManager:
if info.driver_type == driver_type
]
def getDriverPath(
self,
driver_info: WebDriverInfo
@@ -325,7 +313,6 @@ class WebDriverManager:
return driver_info.driver_path
return None
def installDriver(
self,
driver_info: WebDriverInfo,
@@ -390,7 +377,6 @@ class WebDriverManager:
driver_info.driver_status = WebDriverStatus.ERROR
raise e
def cancelDriverDownload(
self,
driver_info: WebDriverInfo
@@ -411,7 +397,6 @@ class WebDriverManager:
except Exception:
return False
def uninstallDriver(
self,
driver_info: WebDriverInfo,
@@ -441,7 +426,6 @@ class WebDriverManager:
driver_info.driver_status = WebDriverStatus.ERROR
raise
def driverDir(
self
) -> str:
+1 -4
View File
@@ -89,7 +89,6 @@ class LogManager:
self.initialize()
def initialize(
self
):
@@ -139,7 +138,6 @@ class LogManager:
self.__initialized = True
def getLogger(
self,
name: Optional[str] = None
@@ -149,7 +147,6 @@ class LogManager:
return self.__logger.getChild(name)
return self.__logger
def setLevel(
self,
level: int
@@ -158,7 +155,6 @@ class LogManager:
if self.__logger:
self.__logger.setLevel(level)
def logDir(
self
) -> str:
@@ -171,6 +167,7 @@ _log_manager_instance = None
# Singleton instance lock.
_instance_lock = threading.Lock()
def instance(
log_dir: str = ""
) -> LogManager:
-7
View File
@@ -49,7 +49,6 @@ class AutoLib(MsgBase):
raise Exception("浏览器驱动URL初始化失败 !")
self.__initLibOperators()
def __initBrowserDriver(
self
) -> bool:
@@ -142,7 +141,6 @@ class AutoLib(MsgBase):
self._showTrace(f"浏览器驱动已初始化, 类型: {self.__driver_type}, 路径: {self.__driver_path}")
return True
def __initLibOperators(
self
):
@@ -157,7 +155,6 @@ class AutoLib(MsgBase):
self.__lib_checkin = LibCheckin(self._input_queue, self._output_queue, self.__driver)
self.__lib_renew = LibRenew(self._input_queue, self._output_queue, self.__driver)
def __waitResponseLoad(
self
) -> bool:
@@ -184,7 +181,6 @@ class AutoLib(MsgBase):
self._showTrace(f"登录页面加载失败 !", self.TraceLevel.ERROR)
return False
def __initDriverUrl(
self,
) -> bool:
@@ -207,7 +203,6 @@ class AutoLib(MsgBase):
return False
return True
def __run(
self,
username: str,
@@ -292,7 +287,6 @@ class AutoLib(MsgBase):
return -1
return result
def run(
self,
user_config: dict
@@ -339,7 +333,6 @@ class AutoLib(MsgBase):
)
return
def close(
self
) -> bool:
-12
View File
@@ -33,7 +33,6 @@ class LibChecker(LibOperator):
self.__driver = driver
def _waitResponseLoad(
self
) -> bool:
@@ -50,7 +49,6 @@ class LibChecker(LibOperator):
seconds = int(seconds%60)
return f"{hours}{minutes}{seconds}"
def __navigateToReserveRecordPage(
self
) -> bool:
@@ -67,7 +65,6 @@ class LibChecker(LibOperator):
return False
return True
def __decodeReserveTime(
self,
time_element
@@ -105,7 +102,6 @@ class LibChecker(LibOperator):
}
}
def __decodeReserveInfo(
self,
info_elements
@@ -133,7 +129,6 @@ class LibChecker(LibOperator):
"status": status,
}
def __decodeReserveRecord(
self,
reservation
@@ -160,7 +155,6 @@ class LibChecker(LibOperator):
"info": info
}
def __loadReserveRecords(
self
) -> list:
@@ -177,7 +171,6 @@ class LibChecker(LibOperator):
self._showTrace("加载预约记录失败 !", self.TraceLevel.ERROR)
return None
def __showMoreReserveRecords(
self
) -> bool:
@@ -203,7 +196,6 @@ class LibChecker(LibOperator):
self._showTrace("加载更多预约记录失败 !", self.TraceLevel.ERROR)
return False
def __getReserveRecord(
self,
wanted_date: str,
@@ -253,7 +245,6 @@ class LibChecker(LibOperator):
break
return None
def canReserve(
self,
date: str
@@ -270,7 +261,6 @@ class LibChecker(LibOperator):
self._showTrace(f"用户在 {date} 已存在有效预约, 无法预约")
return False
def canCheckin(
self
) -> bool:
@@ -307,7 +297,6 @@ class LibChecker(LibOperator):
self._showTrace(f"用户在 {date} 没有有效预约记录, 无法签到")
return False
def canRenew(
self
) -> tuple[bool, dict]:
@@ -335,7 +324,6 @@ class LibChecker(LibOperator):
self._showTrace(f"用户在 {date} 没有有效预约记录, 无法续约")
return False, None
def postRenewCheck(
self,
record: dict
-3
View File
@@ -31,7 +31,6 @@ class LibCheckin(LibOperator):
self.__driver = driver
def _waitResponseLoad(
self
) -> bool:
@@ -87,7 +86,6 @@ class LibCheckin(LibOperator):
ok_btn.click()
return False
def __enableCheckinBtn(
self
) -> bool:
@@ -112,7 +110,6 @@ class LibCheckin(LibOperator):
self._showTrace("签到按钮启用失败", self.TraceLevel.WARNING)
return result
def checkin(
self,
username: str
-1
View File
@@ -33,7 +33,6 @@ class LibCheckout(LibOperator):
self.__driver = driver
def _waitResponseLoad(
self
) -> bool:
-8
View File
@@ -34,7 +34,6 @@ class LibLogin(LibOperator):
self.__driver = driver
self.__ddddocr = ddddocr.DdddOcr()
def _waitResponseLoad(
self
) -> bool:
@@ -58,7 +57,6 @@ class LibLogin(LibOperator):
)
return False
def __fillLogInElements(
self,
username: str,
@@ -78,7 +76,6 @@ class LibLogin(LibOperator):
return False
return True
def __autoRecognizeCaptcha(
self
) -> str:
@@ -100,7 +97,6 @@ class LibLogin(LibOperator):
self._showTrace(f"验证码识别失败 ! : {e}", self.TraceLevel.ERROR)
return ""
def __manualRecognizeCaptcha(
self
) -> str:
@@ -118,7 +114,6 @@ class LibLogin(LibOperator):
self._showTrace(f"输入验证码失败 ! : {e}", self.TraceLevel.ERROR)
return ""
def __refreshCaptcha(
self
):
@@ -134,7 +129,6 @@ class LibLogin(LibOperator):
self._showTrace(f"刷新验证码失败 ! : {e}", self.TraceLevel.ERROR)
return False
def __solveCaptcha(
self,
auto_captcha: bool = True
@@ -158,7 +152,6 @@ class LibLogin(LibOperator):
)
return ""
def __fillCaptchaElement(
self,
captcha_text: str
@@ -173,7 +166,6 @@ class LibLogin(LibOperator):
self._showTrace(f"验证码填写失败 ! : {e}", self.TraceLevel.ERROR)
return False
def login(
self,
username: str,
-2
View File
@@ -28,14 +28,12 @@ class LibLogout(LibOperator):
self.__driver = driver
def _waitResponseLoad(
self
) -> bool:
return True
def logout(
self,
username: str
+1 -7
View File
@@ -14,7 +14,7 @@ from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from base.LibTimeSelector import LibTimeSelector
from operators.abs.LibTimeSelector import LibTimeSelector
class LibRenew(LibTimeSelector):
@@ -30,7 +30,6 @@ class LibRenew(LibTimeSelector):
self.__driver = driver
def _waitResponseLoad(
self
) -> bool:
@@ -38,7 +37,6 @@ class LibRenew(LibTimeSelector):
self.__driver.refresh()
return True
def __waitRenewDialog(
self
) -> bool:
@@ -77,7 +75,6 @@ class LibRenew(LibTimeSelector):
return False
return True
def __selectNearestTime(
self,
record: dict,
@@ -116,7 +113,6 @@ class LibRenew(LibTimeSelector):
self._showTrace(f"当前可供续约的时间有: {free_times}")
return False
def __validateAndAdjustRenewTime(
self,
end_time: str,
@@ -139,7 +135,6 @@ class LibRenew(LibTimeSelector):
return True
return True
def __confirmRenewal(
self,
best_opt,
@@ -167,7 +162,6 @@ class LibRenew(LibTimeSelector):
self._showTrace("确认续约时发生错误 !", self.TraceLevel.ERROR)
return False
def renew(
self,
username: str,
+3 -22
View File
@@ -15,7 +15,7 @@ from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from base.LibTimeSelector import LibTimeSelector
from operators.abs.LibTimeSelector import LibTimeSelector
class LibReserve(LibTimeSelector):
@@ -48,7 +48,6 @@ class LibReserve(LibTimeSelector):
"8": "五层考研"
}
def _waitResponseLoad(
self,
) -> bool:
@@ -99,7 +98,6 @@ class LibReserve(LibTimeSelector):
self._showTrace(f"预约结果加载失败 !", self.TraceLevel.ERROR)
return False
def __containRequiredInfo(
self,
reserve_info: dict
@@ -135,7 +133,6 @@ class LibReserve(LibTimeSelector):
)
return False
def __isValidDate(
self,
reserve_info: dict
@@ -157,7 +154,6 @@ class LibReserve(LibTimeSelector):
reserve_info["date"] = cur_date_str
return True
def __isValidBeginTime(
self,
reserve_info: dict
@@ -177,7 +173,6 @@ class LibReserve(LibTimeSelector):
self._showTrace(f"是否优先选择更早开始时间未指定, 自动设置为 True")
return True
def __isValidExpectDuration(
self,
reserve_info: dict
@@ -192,7 +187,6 @@ class LibReserve(LibTimeSelector):
self._showTrace("需要满足预约持续时间, 但未指定, 使用默认时长为 4 小时")
return True
def __isValidEndTime(
self,
reserve_info: dict
@@ -222,7 +216,6 @@ class LibReserve(LibTimeSelector):
self._showTrace(f"是否优先选择较晚结束时间未指定, 自动设置为 True")
return True
def __finalCheck(
self,
reserve_info: dict
@@ -275,7 +268,6 @@ class LibReserve(LibTimeSelector):
reserve_info["end_time"]["time"] = self._minsToTimeStr(begin_mins + 8*60)
return True
def __checkReserveInfo(
self,
reserve_info: dict
@@ -305,7 +297,6 @@ class LibReserve(LibTimeSelector):
)
return True
def __clickElement(
self,
trigger_locator: tuple,
@@ -330,7 +321,6 @@ class LibReserve(LibTimeSelector):
self._showTrace(fail_msg)
return False
def __clickElementByJS(
self,
trigger_locator_id: str,
@@ -364,7 +354,6 @@ class LibReserve(LibTimeSelector):
self._showTrace(fail_msg)
return result
def __selectDate(
self,
date_str: str
@@ -384,7 +373,6 @@ class LibReserve(LibTimeSelector):
fail_msg=f"选择日期失败 ! : {date_str} 不可用"
)
def __selectPlace(
self,
place: str
@@ -406,7 +394,6 @@ class LibReserve(LibTimeSelector):
fail_msg=f"选择预约场所失败 ! : {display_place} 不可用"
)
def __selectFloor(
self,
floor: str
@@ -427,7 +414,6 @@ class LibReserve(LibTimeSelector):
fail_msg=f"选择楼层失败 ! : {display_floor} 不可用"
)
def __selectRoom(
self,
room: str
@@ -453,7 +439,6 @@ class LibReserve(LibTimeSelector):
self._showTrace(f"选择房间失败 ! : {display_room} 不可用", self.TraceLevel.ERROR)
return False
def __selectSeat(
self,
seat_id: str
@@ -492,7 +477,6 @@ class LibReserve(LibTimeSelector):
self._showTrace(f"座位选择失败 !", self.TraceLevel.ERROR)
return False
def __selectNearestTime(
self,
time_id: str,
@@ -547,7 +531,6 @@ class LibReserve(LibTimeSelector):
self._showTrace(f"当前可供预约的 {time_type} 有: {free_times}")
return -1
def __selectSeatTime(
self,
begin_time: dict,
@@ -583,7 +566,7 @@ class LibReserve(LibTimeSelector):
# If 'satisfy_duration' is True, select end time based on actual begin time
if satisfy_duration:
exp_end_mins = int(self.validateAndAdjustEndTime(act_beg_mins, expect_duration))
exp_end_mins = int(self.__validateAndAdjustEndTime(act_beg_mins, expect_duration))
exp_end_tm_str = self._minsToTimeStr(exp_end_mins)
self._showTrace(
f"需要满足期望预约持续时间: {expect_duration} 小时, "
@@ -607,8 +590,7 @@ class LibReserve(LibTimeSelector):
)
return True
def validateAndAdjustEndTime(
def __validateAndAdjustEndTime(
self,
begin_mins: int,
duration: int
@@ -627,7 +609,6 @@ class LibReserve(LibTimeSelector):
)
return expect_end_mins
def reserve(
self,
username: str,
@@ -16,7 +16,7 @@ from base.LibOperator import LibOperator
class LibTimeSelector(LibOperator):
"""
Base class for time selection operations.
Abstract base class for time selection operations.
This class provides common time selection logic for reservation and renewal
operations, including time conversion utilities and best time option finding.
@@ -60,7 +60,6 @@ class LibTimeSelector(LibOperator):
hour, minute = divmod(int(mins), 60)
return f"{hour:02d}:{minute:02d}"
def _formatTimeRelation(
self,
abs_diff: int,
@@ -78,7 +77,6 @@ class LibTimeSelector(LibOperator):
else:
return f"正好等于 {time_type}"
def _findBestTimeOption(
self,
time_options: list,
+6
View File
@@ -0,0 +1,6 @@
"""
Abstract layer class of the LibOperator
Here are the classes and modules in this package:
- LibTimeSelector: Abstract base class for time selection operations.
"""
-4
View File
@@ -42,7 +42,6 @@ class JSONReader:
self.__json_data = None
self.__read()
def __read(
self
):
@@ -59,7 +58,6 @@ class JSONReader:
except Exception as e:
raise Exception(f"读取文件时发生未知错误: {e}") from e
def read(
self
) -> bool:
@@ -70,14 +68,12 @@ class JSONReader:
return False
return True
def data(
self
) -> dict:
return self.__json_data.copy()
def path(
self
) -> str:
-3
View File
@@ -46,7 +46,6 @@ class JSONWriter:
self.__json_data = json_data.copy() if json_data is not None else {}
self.__write()
def __write(
self
):
@@ -63,7 +62,6 @@ class JSONWriter:
except Exception as e:
raise Exception(f"写入文件时发生未知错误: {e}") from e
def write(
self
) -> bool:
@@ -74,7 +72,6 @@ class JSONWriter:
return False
return True
def path(
self
) -> str: