mirror of
https://github.com/KenanZhu/AutoLibrary.git
synced 2026-06-17 23:13:03 +08:00
refactor(pages): 统一命名规范并修复 SeatMapOverlay 元素等待目标错误
- AutoLibPages → AutoLib(移除实现细节后缀) - ReserveValidator → ReserveChecker(与 RecordChecker 命名一致) - CaptchaHandler → CaptchaSolver(语义更准确,职责是"求解"验证码) - ReserveChecker.validate() → check()(与 RecordChecker 风格统一) - 修复 SeatMapOverlay.selectSeat() 中 _waitClickable 等待页面全局 <a> 而非具体 seat_link 元素的时序缺陷 - ALMainWorkers 切换为 pages.AutoLib 新版实现 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@ from PySide6.QtCore import (
|
||||
)
|
||||
|
||||
from base.MsgBase import MsgBase
|
||||
from operators.AutoLib import AutoLib
|
||||
from pages.AutoLib import AutoLib
|
||||
from utils.JSONReader import JSONReader
|
||||
from autoscript import createEngine
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@ from pages.MainShell import MainShell
|
||||
from pages.flows.ReserveFlow import ReserveFlow, ReserveContext
|
||||
from pages.flows.CheckinFlow import CheckinFlow
|
||||
from pages.flows.RenewFlow import RenewFlow
|
||||
from pages.services.CaptchaHandler import CaptchaHandler
|
||||
from pages.services.ReserveValidator import ReserveValidator
|
||||
from pages.services.CaptchaSolver import CaptchaSolver
|
||||
from pages.services.ReserveChecker import ReserveChecker
|
||||
from pages.services.RecordChecker import RecordChecker
|
||||
|
||||
|
||||
class AutoLibPages(MsgBase):
|
||||
class AutoLib(MsgBase):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -46,9 +46,9 @@ class AutoLibPages(MsgBase):
|
||||
self.__driver_path: str = ""
|
||||
self.__login_page: LoginPage = None
|
||||
self.__shell: MainShell = None
|
||||
self.__captcha_handler: CaptchaHandler = None
|
||||
self.__captcha_solver: CaptchaSolver = None
|
||||
self.__record_checker: RecordChecker = None
|
||||
self.__reserve_validator: ReserveValidator = None
|
||||
self.__reserve_checker: ReserveChecker = None
|
||||
self.__reserve_flow: ReserveFlow = None
|
||||
self.__checkin_flow: CheckinFlow = None
|
||||
self.__renew_flow: RenewFlow = None
|
||||
@@ -189,7 +189,7 @@ class AutoLibPages(MsgBase):
|
||||
self._showTrace("浏览器驱动未初始化, 请先初始化浏览器驱动 !", self.TraceLevel.WARNING)
|
||||
return
|
||||
self.__shell = MainShell(self.__driver)
|
||||
self.__captcha_handler = CaptchaHandler(
|
||||
self.__captcha_solver = CaptchaSolver(
|
||||
input_queue=self._input_queue,
|
||||
output_queue=self._output_queue,
|
||||
)
|
||||
@@ -197,7 +197,7 @@ class AutoLibPages(MsgBase):
|
||||
input_queue=self._input_queue,
|
||||
output_queue=self._output_queue,
|
||||
)
|
||||
self.__reserve_validator = ReserveValidator(
|
||||
self.__reserve_checker = ReserveChecker(
|
||||
input_queue=self._input_queue,
|
||||
output_queue=self._output_queue,
|
||||
)
|
||||
@@ -242,7 +242,7 @@ class AutoLibPages(MsgBase):
|
||||
if not self.__login_page.login(
|
||||
username,
|
||||
password,
|
||||
captcha_solver=self.__captcha_handler.solveCaptcha,
|
||||
captcha_solver=self.__captcha_solver.solveCaptcha,
|
||||
auto_captcha=auto_captcha,
|
||||
max_attempts=login_config.get("max_attempt", 3),
|
||||
):
|
||||
@@ -256,7 +256,7 @@ class AutoLibPages(MsgBase):
|
||||
# reserve
|
||||
if run_mode["auto_reserve"]:
|
||||
if self.__record_checker.canReserve(self.__shell, reserve_info.get("date")):
|
||||
if self.__reserve_validator.validate(reserve_info):
|
||||
if self.__reserve_checker.check(reserve_info):
|
||||
ctx = ReserveContext(
|
||||
username=username,
|
||||
date=reserve_info["date"],
|
||||
@@ -7,7 +7,7 @@ This software is provided "as is", without any warranty of any kind.
|
||||
You may use, modify, and distribute this file under the terms of the MIT License.
|
||||
See the LICENSE file for details.
|
||||
"""
|
||||
from pages.AutoLibPages import AutoLibPages
|
||||
from pages.AutoLib import AutoLib
|
||||
from pages.LoginPage import LoginPage
|
||||
from pages.MainShell import MainShell
|
||||
from pages.ReserveView import ReserveView
|
||||
@@ -19,7 +19,7 @@ from pages.components.CheckinResultDialog import CheckinResultDialog
|
||||
from pages.components.RenewDialog import RenewDialog
|
||||
|
||||
__all__ = [
|
||||
"AutoLibPages",
|
||||
"AutoLib",
|
||||
"LoginPage",
|
||||
"MainShell",
|
||||
"ReserveView",
|
||||
|
||||
@@ -15,6 +15,8 @@ from selenium.common.exceptions import (
|
||||
)
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.remote.webdriver import WebDriver
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
from pages.components.Overlay import Overlay
|
||||
|
||||
@@ -48,7 +50,9 @@ class SeatMapOverlay(Overlay):
|
||||
try:
|
||||
seat_el = self._find(By.ID, f"seat_{int(seat_id):03d}")
|
||||
seat_link = seat_el.find_element(By.TAG_NAME, "a")
|
||||
self._waitClickable((By.TAG_NAME, "a"))
|
||||
WebDriverWait(self._driver, 2).until(
|
||||
EC.element_to_be_clickable(seat_link)
|
||||
)
|
||||
seat_link.click()
|
||||
return seat_link.get_attribute("title")
|
||||
except (NoSuchElementException, ValueError, TimeoutException,
|
||||
@@ -63,7 +67,9 @@ class SeatMapOverlay(Overlay):
|
||||
if not seat_id_upper == seat.text.lstrip('0'):
|
||||
continue
|
||||
seat_link = seat.find_element(By.TAG_NAME, "a")
|
||||
self._waitClickable((By.TAG_NAME, "a"))
|
||||
WebDriverWait(self._driver, 2).until(
|
||||
EC.element_to_be_clickable(seat_link)
|
||||
)
|
||||
seat_link.click()
|
||||
return seat_link.get_attribute("title")
|
||||
return None
|
||||
|
||||
@@ -42,16 +42,13 @@ class CheckinFlow(MsgBase):
|
||||
if not self._shell.waitCheckinButton():
|
||||
self._showTrace(f"用户 {username} 签到界面加载失败 !", self.TraceLevel.ERROR)
|
||||
return False
|
||||
|
||||
if self._shell.isCheckinButtonDisabled():
|
||||
self._showTrace("签到按钮不可用, 可能不在场馆内, 正在尝试启用......")
|
||||
if not self._shell.enableCheckinButtonByJS():
|
||||
self._showTrace(f"签到按钮启用失败 !", self.TraceLevel.ERROR)
|
||||
return False
|
||||
self._showTrace("签到按钮已启用")
|
||||
|
||||
self._shell.clickCheckinButton()
|
||||
|
||||
try:
|
||||
with CheckinResultDialog(self._driver) as dialog:
|
||||
result_msg = dialog.getResultMessage()
|
||||
|
||||
@@ -53,23 +53,18 @@ class RenewFlow(MsgBase):
|
||||
prefer_earlier = renew_info["prefer_early"]
|
||||
end_time = record["time"]["end"]
|
||||
target_renew_mins = timeStrToMins(end_time) + renew_info["expect_duration"] * 60
|
||||
|
||||
if not self._validateRenewTime(end_time, target_renew_mins):
|
||||
return False
|
||||
|
||||
if not self._shell.waitExtendButton():
|
||||
self._showTrace(f"用户 {username} 续约界面加载失败 !", self.TraceLevel.ERROR)
|
||||
return False
|
||||
|
||||
if self._shell.isExtendButtonDisabled():
|
||||
self._showTrace(
|
||||
f"用户 {username} 续约按钮不可用, 可能不在场馆内, "
|
||||
f"请连接图书馆网络后重试"
|
||||
)
|
||||
return False
|
||||
|
||||
self._shell.clickExtendButton()
|
||||
|
||||
try:
|
||||
with RenewDialog(self._driver) as dialog:
|
||||
if not dialog.waitUntilReady():
|
||||
@@ -82,14 +77,12 @@ class RenewFlow(MsgBase):
|
||||
self._shell.refresh()
|
||||
self._showTrace(f"用户 {username} 续约失败 !", self.TraceLevel.ERROR)
|
||||
return False
|
||||
|
||||
renew_ok_btn = dialog.getOkButton()
|
||||
renew_time_opts = dialog.getTimeOptions()
|
||||
if not renew_time_opts:
|
||||
self._showTrace("当前未查询到可用续约时间 !", self.TraceLevel.WARNING)
|
||||
self._shell.refresh()
|
||||
return False
|
||||
|
||||
best_opt, best_text, actual_diff, free_times = findBestTimeOption(
|
||||
renew_time_opts, target_renew_mins, max_diff, prefer_earlier,
|
||||
is_reserve=False,
|
||||
@@ -111,7 +104,6 @@ class RenewFlow(MsgBase):
|
||||
renew_ok_btn.click()
|
||||
self._shell.refresh()
|
||||
return True
|
||||
|
||||
self._showTrace(
|
||||
"无法选择最近的可用续约时间 ! "
|
||||
f"所有可选时间与目标时间相差都超过了 {max_diff} 分钟 !",
|
||||
|
||||
@@ -68,7 +68,6 @@ def findBestTimeOption(
|
||||
)
|
||||
actual_diff = time_val - target_time
|
||||
abs_diff = abs(actual_diff)
|
||||
|
||||
if abs_diff < best_time_diff or (
|
||||
abs_diff == best_time_diff
|
||||
and (
|
||||
@@ -79,7 +78,6 @@ def findBestTimeOption(
|
||||
best_time_diff = abs_diff
|
||||
best_actual_diff = actual_diff
|
||||
best_time_opt = time_opt
|
||||
|
||||
if best_time_opt is not None:
|
||||
return (best_time_opt, best_time_opt.text.strip(), best_actual_diff, free_times)
|
||||
return (None, None, None, free_times)
|
||||
|
||||
@@ -20,7 +20,7 @@ from base.MsgBase import MsgBase
|
||||
from pages.LoginPage import LoginPage
|
||||
|
||||
|
||||
class CaptchaHandler(MsgBase):
|
||||
class CaptchaSolver(MsgBase):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -15,7 +15,7 @@ from pages.ReserveView import ReserveView
|
||||
from pages.flows._helpers import timeStrToMins, minsToTimeStr
|
||||
|
||||
|
||||
class ReserveValidator(MsgBase):
|
||||
class ReserveChecker(MsgBase):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -150,7 +150,6 @@ class ReserveValidator(MsgBase):
|
||||
end_time = reserve_info["end_time"]
|
||||
begin_mins = timeStrToMins(begin_time["time"])
|
||||
end_mins = timeStrToMins(end_time["time"])
|
||||
|
||||
if end_mins < begin_mins and reserve_info["satisfy_duration"] is False:
|
||||
self._showTrace(
|
||||
f"结束时间 {end_time['time']} 早于开始时间 {begin_time['time']}, "
|
||||
@@ -161,7 +160,6 @@ class ReserveValidator(MsgBase):
|
||||
begin_time, end_time = end_time, begin_time
|
||||
begin_mins = timeStrToMins(begin_time["time"])
|
||||
end_mins = timeStrToMins(end_time["time"])
|
||||
|
||||
max_end_mins = timeStrToMins("23:30")
|
||||
if end_mins > max_end_mins:
|
||||
self._showTrace(
|
||||
@@ -170,7 +168,6 @@ class ReserveValidator(MsgBase):
|
||||
)
|
||||
reserve_info["end_time"]["time"] = "23:30"
|
||||
end_mins = max_end_mins
|
||||
|
||||
if reserve_info["satisfy_duration"]:
|
||||
if reserve_info["expect_duration"] > 8:
|
||||
self._showTrace(
|
||||
@@ -191,7 +188,7 @@ class ReserveValidator(MsgBase):
|
||||
reserve_info["end_time"]["time"] = minsToTimeStr(begin_mins + 8 * 60)
|
||||
return True
|
||||
|
||||
def validate(
|
||||
def check(
|
||||
self,
|
||||
reserve_info: dict,
|
||||
) -> bool:
|
||||
@@ -7,12 +7,12 @@ This software is provided "as is", without any warranty of any kind.
|
||||
You may use, modify, and distribute this file under the terms of the MIT License.
|
||||
See the LICENSE file for details.
|
||||
"""
|
||||
from pages.services.CaptchaHandler import CaptchaHandler
|
||||
from pages.services.ReserveValidator import ReserveValidator
|
||||
from pages.services.CaptchaSolver import CaptchaSolver
|
||||
from pages.services.ReserveChecker import ReserveChecker
|
||||
from pages.services.RecordChecker import RecordChecker
|
||||
|
||||
__all__ = [
|
||||
"CaptchaHandler",
|
||||
"ReserveValidator",
|
||||
"CaptchaSolver",
|
||||
"ReserveChecker",
|
||||
"RecordChecker",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user