mirror of
https://github.com/KenanZhu/AutoLibrary.git
synced 2026-06-18 23:43:02 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b24e4f473f | |||
| 8bb65be0b9 | |||
| 631785122b | |||
| 82ea40d3dc | |||
| 1244084c75 | |||
| 7a599c4f63 | |||
| d2cef258aa | |||
| a4c5ee299e | |||
| 7d92717136 | |||
| 3ef301f199 | |||
| b10d333eb2 | |||
| d5dc012ade | |||
| dac87068ef |
+24
-12
@@ -17,6 +17,7 @@ from selenium.webdriver.support import expected_conditions as EC
|
|||||||
from selenium.webdriver.edge.service import Service
|
from selenium.webdriver.edge.service import Service
|
||||||
|
|
||||||
from MsgBase import MsgBase
|
from MsgBase import MsgBase
|
||||||
|
from LibChecker import LibChecker
|
||||||
from LibLogin import LibLogin
|
from LibLogin import LibLogin
|
||||||
from LibLogout import LibLogout
|
from LibLogout import LibLogout
|
||||||
from LibReserve import LibReserve
|
from LibReserve import LibReserve
|
||||||
@@ -29,7 +30,7 @@ class AutoLib(MsgBase):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
input_queue: queue.Queue,
|
input_queue: queue.Queue,
|
||||||
output_queue: queue.Queue,
|
output_queue: queue.Queue
|
||||||
):
|
):
|
||||||
super().__init__(input_queue, output_queue)
|
super().__init__(input_queue, output_queue)
|
||||||
|
|
||||||
@@ -51,7 +52,8 @@ class AutoLib(MsgBase):
|
|||||||
edge_options.add_argument("--no-sandbox")
|
edge_options.add_argument("--no-sandbox")
|
||||||
edge_options.add_argument("--disable-dev-shm-usage")
|
edge_options.add_argument("--disable-dev-shm-usage")
|
||||||
|
|
||||||
edge_options.add_argument("--window-size=1280,720")
|
# must be 1920x1080, otherwise the page will cause some elements not accessible
|
||||||
|
edge_options.add_argument("--window-size=1920,1080")
|
||||||
edge_options.add_argument("--remote-allow-origins=*")
|
edge_options.add_argument("--remote-allow-origins=*")
|
||||||
|
|
||||||
# omit ssl errors and verbose log level
|
# omit ssl errors and verbose log level
|
||||||
@@ -95,16 +97,25 @@ class AutoLib(MsgBase):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._showTrace(f"浏览器驱动初始化失败: {e}")
|
self._showTrace(f"浏览器驱动初始化失败: {e}")
|
||||||
return False
|
return False
|
||||||
# init library operators
|
|
||||||
self.__lib_login = LibLogin(self._input_queue, self._output_queue, self.__driver)
|
|
||||||
self.__lib_logout = LibLogout(self._input_queue, self._output_queue, self.__driver)
|
|
||||||
self.__lib_reserve = LibReserve(self._input_queue, self._output_queue, self.__driver)
|
|
||||||
self._showTrace(f"浏览器驱动已初始化, 类型: {self.__driver_type}, 路径: {self.__driver_path}")
|
self._showTrace(f"浏览器驱动已初始化, 类型: {self.__driver_type}, 路径: {self.__driver_path}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def __initLibOperators(
|
||||||
|
self
|
||||||
|
):
|
||||||
|
|
||||||
|
if not self.__driver:
|
||||||
|
self._showTrace(f"浏览器驱动未初始化, 请先初始化浏览器驱动 !")
|
||||||
|
return
|
||||||
|
self.__lib_checker = LibChecker(self._input_queue, self._output_queue, self.__driver)
|
||||||
|
self.__lib_login = LibLogin(self._input_queue, self._output_queue, self.__driver)
|
||||||
|
self.__lib_logout = LibLogout(self._input_queue, self._output_queue, self.__driver)
|
||||||
|
self.__lib_reserve = LibReserve(self._input_queue, self._output_queue, self.__driver)
|
||||||
|
|
||||||
|
|
||||||
def __waitResponseLoad(
|
def __waitResponseLoad(
|
||||||
self,
|
self
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
# wait for page load
|
# wait for page load
|
||||||
@@ -144,7 +155,7 @@ class AutoLib(MsgBase):
|
|||||||
self,
|
self,
|
||||||
username: str,
|
username: str,
|
||||||
password: str,
|
password: str,
|
||||||
reserve_info: dict,
|
reserve_info: dict
|
||||||
) -> int:
|
) -> int:
|
||||||
|
|
||||||
# result : 0 - success, 1 - failed, 2 - passed
|
# result : 0 - success, 1 - failed, 2 - passed
|
||||||
@@ -169,7 +180,7 @@ class AutoLib(MsgBase):
|
|||||||
}
|
}
|
||||||
# reserve
|
# reserve
|
||||||
if run_mode["auto_reserve"]:
|
if run_mode["auto_reserve"]:
|
||||||
if self.__lib_reserve.canReserve(reserve_info.get("date")):
|
if self.__lib_checker.canReserve(reserve_info.get("date")):
|
||||||
if self.__lib_reserve.reserve(reserve_info):
|
if self.__lib_reserve.reserve(reserve_info):
|
||||||
self._showTrace(f"用户 {username} 预约成功 !")
|
self._showTrace(f"用户 {username} 预约成功 !")
|
||||||
result = 0
|
result = 0
|
||||||
@@ -192,7 +203,7 @@ class AutoLib(MsgBase):
|
|||||||
def run(
|
def run(
|
||||||
self,
|
self,
|
||||||
system_config_reader: ConfigReader,
|
system_config_reader: ConfigReader,
|
||||||
users_config_reader: ConfigReader,
|
users_config_reader: ConfigReader
|
||||||
):
|
):
|
||||||
|
|
||||||
self.__system_config_reader = system_config_reader
|
self.__system_config_reader = system_config_reader
|
||||||
@@ -202,6 +213,7 @@ class AutoLib(MsgBase):
|
|||||||
else:
|
else:
|
||||||
if not self.__initDriverUrl():
|
if not self.__initDriverUrl():
|
||||||
return
|
return
|
||||||
|
self.__initLibOperators()
|
||||||
|
|
||||||
user_counter = {"current": 0, "success": 0, "failed": 0, "passed": 0}
|
user_counter = {"current": 0, "success": 0, "failed": 0, "passed": 0}
|
||||||
users = self.__users_config_reader.get("users")
|
users = self.__users_config_reader.get("users")
|
||||||
@@ -234,7 +246,7 @@ class AutoLib(MsgBase):
|
|||||||
|
|
||||||
|
|
||||||
def close(
|
def close(
|
||||||
self,
|
self
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
if self.__driver:
|
if self.__driver:
|
||||||
@@ -243,5 +255,5 @@ class AutoLib(MsgBase):
|
|||||||
self._showTrace(f"浏览器驱动已关闭")
|
self._showTrace(f"浏览器驱动已关闭")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
self._showTrace(f"浏览器驱动未初始化,无需关闭")
|
self._showTrace(f"浏览器驱动未初始化, 无需关闭")
|
||||||
return False
|
return False
|
||||||
+172
-77
@@ -39,6 +39,16 @@ class LibChecker(LibOperator):
|
|||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __formatDiffTime(
|
||||||
|
seconds: float
|
||||||
|
) -> str:
|
||||||
|
|
||||||
|
hours = int(seconds // 3600)
|
||||||
|
minutes = int(seconds % 3600 // 60)
|
||||||
|
seconds = int(seconds % 60)
|
||||||
|
return f"{hours} 时 {minutes} 分 {seconds} 秒"
|
||||||
|
|
||||||
|
|
||||||
def __navigateToReserveRecordPage(
|
def __navigateToReserveRecordPage(
|
||||||
self
|
self
|
||||||
@@ -57,6 +67,83 @@ class LibChecker(LibOperator):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def __decodeReserveInfo(
|
||||||
|
self,
|
||||||
|
info_elements
|
||||||
|
) -> str:
|
||||||
|
|
||||||
|
location = ""
|
||||||
|
status = ""
|
||||||
|
for info in info_elements:
|
||||||
|
if "已预约" in info.text:
|
||||||
|
status = "已预约"
|
||||||
|
elif "使用中" in info.text:
|
||||||
|
status = "使用中"
|
||||||
|
elif "已完成" in info.text:
|
||||||
|
status = "已完成"
|
||||||
|
elif "已结束使用" in info.text:
|
||||||
|
status = "已结束使用"
|
||||||
|
elif "已取消" in info.text:
|
||||||
|
status = "已取消"
|
||||||
|
elif "失约" in info.text:
|
||||||
|
status = "失约"
|
||||||
|
elif "图书馆" in info.text:
|
||||||
|
location = info.text.strip()
|
||||||
|
return {
|
||||||
|
"location": location,
|
||||||
|
"status": status,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def __decodeReserveRecord(
|
||||||
|
self,
|
||||||
|
reservation
|
||||||
|
) -> dict:
|
||||||
|
|
||||||
|
try:
|
||||||
|
time_element = reservation.find_element(
|
||||||
|
By.CSS_SELECTOR, "dt"
|
||||||
|
)
|
||||||
|
info_elements = reservation.find_elements(
|
||||||
|
By.CSS_SELECTOR, "a"
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
# process time element to get the date string
|
||||||
|
time_str = time_element.text.strip()
|
||||||
|
today = datetime.now().date()
|
||||||
|
if "明天" in time_str:
|
||||||
|
target_date = today + timedelta(days=1)
|
||||||
|
date_str = target_date.strftime("%Y-%m-%d")
|
||||||
|
elif "今天" in time_str:
|
||||||
|
target_date = today
|
||||||
|
date_str = target_date.strftime("%Y-%m-%d")
|
||||||
|
elif "昨天" in time_str:
|
||||||
|
target_date = today - timedelta(days=1)
|
||||||
|
date_str = target_date.strftime("%Y-%m-%d")
|
||||||
|
else:
|
||||||
|
date_match = re.search(r"(\d{4}-\d{1,2}-\d{1,2})", time_str)
|
||||||
|
if date_match:
|
||||||
|
date_str = date_match.group(1)
|
||||||
|
else:
|
||||||
|
date_str = ""
|
||||||
|
time_match = re.search(r"(\d{1,2}:\d{2}) -- (\d{1,2}:\d{2})", time_str)
|
||||||
|
if time_match:
|
||||||
|
begin_time = time_match.group(1)
|
||||||
|
end_time = time_match.group(2)
|
||||||
|
else:
|
||||||
|
time_str = ""
|
||||||
|
info = self.__decodeReserveInfo(info_elements)
|
||||||
|
return {
|
||||||
|
"date": date_str,
|
||||||
|
"time": {
|
||||||
|
"begin": begin_time,
|
||||||
|
"end": end_time,
|
||||||
|
},
|
||||||
|
"info": info
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def __getReserveRecord(
|
def __getReserveRecord(
|
||||||
self,
|
self,
|
||||||
wanted_date: str,
|
wanted_date: str,
|
||||||
@@ -66,75 +153,57 @@ class LibChecker(LibOperator):
|
|||||||
if wanted_date is None:
|
if wanted_date is None:
|
||||||
self._showTrace("日期未指定, 无法检查当前预约状态")
|
self._showTrace("日期未指定, 无法检查当前预约状态")
|
||||||
return None
|
return None
|
||||||
self._showTrace(f"正在检查用户在日期 {wanted_date} 是否有预约状态为 {wanted_status} 的预约记录......")
|
self._showTrace(f"正在检查用户在 {wanted_date} 是否有预约状态为 {wanted_status} 的预约记录......")
|
||||||
date_obj = datetime.strptime(wanted_date, "%Y-%m-%d").date()
|
date_obj = datetime.strptime(wanted_date, "%Y-%m-%d").date()
|
||||||
|
|
||||||
checked_count = 0
|
checked_count = 0
|
||||||
max_check_times = 3 # we only check (3*4=)12 reservations
|
max_check_times = 6 # we only check (4*(6-1)=)20 reservations, the last time cant be checked
|
||||||
|
|
||||||
if not self.__navigateToReserveRecordPage():
|
if not self.__navigateToReserveRecordPage():
|
||||||
return None
|
return None
|
||||||
for _ in range(max_check_times):
|
for _ in range(max_check_times):
|
||||||
try:
|
try:
|
||||||
# check if there's any reservation on the date
|
# check if there's any reservation on the date
|
||||||
|
WebDriverWait(self.__driver, 2).until(
|
||||||
|
EC.presence_of_element_located((By.CSS_SELECTOR, ".myReserveList > dl"))
|
||||||
|
)
|
||||||
reservations = self.__driver.find_elements(
|
reservations = self.__driver.find_elements(
|
||||||
By.CSS_SELECTOR, ".myReserveList dl"
|
By.CSS_SELECTOR, ".myReserveList > dl:not(#moreBlock)"
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
self._showTrace("加载预约记录失败 !")
|
self._showTrace("加载预约记录失败 !")
|
||||||
return None
|
return None
|
||||||
for i in range(checked_count, len(reservations) - 1): # the last one is load button
|
for i in range(checked_count, len(reservations)): # the last one is load button
|
||||||
reservation = reservations[i]
|
reservation = reservations[i]
|
||||||
try:
|
record = self.__decodeReserveRecord(reservation)
|
||||||
time_element = reservation.find_element(
|
if record is None:
|
||||||
By.CSS_SELECTOR, "dt"
|
|
||||||
)
|
|
||||||
info_elements = reservation.find_elements(
|
|
||||||
By.CSS_SELECTOR, "a"
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
self._showTrace(f"解析第 {i + 1} 条预约记录时发生未知错误 !")
|
|
||||||
continue
|
continue
|
||||||
is_wanted = any(wanted_status in status.text for status in info_elements)
|
record_date = record["date"]
|
||||||
# process time element to get the date string
|
record_time = record["time"]
|
||||||
time_str = time_element.text.strip()
|
status = record["info"]["status"]
|
||||||
today = datetime.now().date()
|
location = record["info"]["location"]
|
||||||
if "明天" in time_str:
|
if record_date == "" or record_time == {"begin": "", "end": ""}:
|
||||||
target_date = today + timedelta(days=1)
|
continue
|
||||||
date_str = target_date.strftime("%Y-%m-%d")
|
is_wanted = (status == wanted_status)
|
||||||
elif "今天" in time_str:
|
|
||||||
target_date = today
|
|
||||||
date_str = target_date.strftime("%Y-%m-%d")
|
|
||||||
elif "昨天" in time_str:
|
|
||||||
target_date = today - timedelta(days=1)
|
|
||||||
date_str = target_date.strftime("%Y-%m-%d")
|
|
||||||
else:
|
|
||||||
date_match = re.search(r'(\d{4}-\d{1,2}-\d{1,2})', time_str)
|
|
||||||
if date_match:
|
|
||||||
date_str = date_match.group(1)
|
|
||||||
else:
|
|
||||||
self._showTrace(f"无法解析第 {i + 1} 条预约记录的日期 ! 该记录的时间为 {time_str}")
|
|
||||||
continue
|
|
||||||
# reservation is later than the given date, check the next one
|
# reservation is later than the given date, check the next one
|
||||||
if datetime.strptime(date_str, "%Y-%m-%d").date() > date_obj:
|
if datetime.strptime(record_date, "%Y-%m-%d").date() > date_obj:
|
||||||
continue
|
continue
|
||||||
# reservation is earlier than the given date, can reserve
|
# reservation is earlier than the given date, can reserve
|
||||||
if datetime.strptime(date_str, "%Y-%m-%d").date() < date_obj:
|
if datetime.strptime(record_date, "%Y-%m-%d").date() < date_obj:
|
||||||
return None
|
return None
|
||||||
# query the wanted status
|
# query the wanted status
|
||||||
if is_wanted:
|
if is_wanted:
|
||||||
self._showTrace(f"寻找到第 {i + 1} 条预约记录, 状态为 {wanted_status}")
|
self._showTrace(
|
||||||
time_match = re.search(r"(\d{1,2}:\d{2}) -- (\d{1,2}:\d{2})", time_str)
|
f"寻找到用户第 {i + 1} 条状态为 {wanted_status} 的预约记录, "
|
||||||
if time_match is None:
|
f"详细信息: {record_date} {record_time['begin']} - {record_time['end']} {location}"
|
||||||
self._showTrace(f"无法解析第 {i + 1} 条预约记录的时间 ! 该记录的时间为 {time_str}")
|
)
|
||||||
continue
|
|
||||||
return {
|
return {
|
||||||
"index": i,
|
"index": i,
|
||||||
"date": date_str,
|
"date": record_date,
|
||||||
"time_str": time_match.group(0),
|
"time": record_time,
|
||||||
"status": wanted_status
|
"status": wanted_status
|
||||||
}
|
}
|
||||||
checked_count = len(reservations) - 1
|
checked_count = len(reservations)
|
||||||
# load new reservations if still not sure
|
# load new reservations if still not sure
|
||||||
try:
|
try:
|
||||||
more_btn = self.__driver.find_element(By.ID, "moreBtn")
|
more_btn = self.__driver.find_element(By.ID, "moreBtn")
|
||||||
@@ -142,7 +211,7 @@ class LibChecker(LibOperator):
|
|||||||
self.__driver.execute_script("arguments[0].scrollIntoView(true);", more_btn)
|
self.__driver.execute_script("arguments[0].scrollIntoView(true);", more_btn)
|
||||||
self.__driver.execute_script("arguments[0].click();", more_btn)
|
self.__driver.execute_script("arguments[0].click();", more_btn)
|
||||||
else:
|
else:
|
||||||
self._showTrace("该用户无法加载更多预约记录")
|
self._showTrace("用户无法加载更多预约记录")
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
self._showTrace("加载更多预约记录失败 !")
|
self._showTrace("加载更多预约记录失败 !")
|
||||||
@@ -159,10 +228,11 @@ class LibChecker(LibOperator):
|
|||||||
# then can reserve
|
# then can reserve
|
||||||
if self.__getReserveRecord(date, "已预约") is None:
|
if self.__getReserveRecord(date, "已预约") is None:
|
||||||
if self.__getReserveRecord(date, "使用中") is None:
|
if self.__getReserveRecord(date, "使用中") is None:
|
||||||
self._showTrace(f"用户在日期 {date} 可以预约")
|
self._showTrace(f"用户在 {date} 可以预约")
|
||||||
return True
|
return True
|
||||||
self._showTrace(f"用户在日期 {date} 有使用中的预约, 无法预约")
|
self._showTrace(f"用户在 {date} 有使用中的预约, 无法预约")
|
||||||
self._showTrace(f"用户在日期 {date} 已存在有效预约, 无法预约")
|
return False
|
||||||
|
self._showTrace(f"用户在 {date} 已存在有效预约, 无法预约")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -174,34 +244,59 @@ class LibChecker(LibOperator):
|
|||||||
# have a reserved record in the given date
|
# have a reserved record in the given date
|
||||||
record = self.__getReserveRecord(date, "已预约")
|
record = self.__getReserveRecord(date, "已预约")
|
||||||
if record is not None:
|
if record is not None:
|
||||||
time_match = re.search(r"(\d{1,2}:\d{2})", record["time_str"])
|
begin_time = record["time"]["begin"]
|
||||||
if time_match:
|
begin_time = datetime.strptime(f"{date} {begin_time}", "%Y-%m-%d %H:%M")
|
||||||
begin_time = time_match.group(0)
|
time_diff = datetime.now() - begin_time
|
||||||
begin_time = datetime.strptime(f"{date} {begin_time}", "%Y-%m-%d %H:%M")
|
time_diff_seconds = time_diff.total_seconds()
|
||||||
time_diff = datetime.now() - begin_time
|
# before 30 minutes, cant checkin
|
||||||
time_diff_seconds = time_diff.total_seconds()
|
if time_diff_seconds < -30*60:
|
||||||
# before 30 minutes, cant checkin
|
self._showTrace(
|
||||||
if time_diff_seconds < -30*60:
|
f"用户在 {date} 的预约开始时间为 {begin_time}, "
|
||||||
self._showTrace(
|
f"距离当前时间还有 {self.__formatDiffTime(abs(time_diff_seconds))}, 无法签到"
|
||||||
f"用户在日期 {date} 的预约开始时间为 {begin_time}, "
|
)
|
||||||
f"距离当前时间还有 {abs(time_diff_seconds)/60:.2f} 分钟, 无法签到"
|
return False
|
||||||
)
|
# before in 30 minutes, can checkin
|
||||||
return False
|
elif -30*60 <= time_diff_seconds < 0:
|
||||||
# before in 30 minutes, can checkin
|
self._showTrace(
|
||||||
elif -30*60 <= time_diff_seconds < 0:
|
f"用户在 {date} 的预约开始时间为 {begin_time}, "
|
||||||
self._showTrace(
|
f"距离当前时间还有 {self.__formatDiffTime(abs(time_diff_seconds))}, 可以签到"
|
||||||
f"用户在日期 {date} 的预约开始时间为 {begin_time}, "
|
)
|
||||||
f"距离当前时间还有 {abs(time_diff_seconds)/60:.2f} 分钟, 可以签到"
|
return True
|
||||||
)
|
# past less than 30 minutes, can checkin
|
||||||
return True
|
elif 0 <= time_diff_seconds < 30*60:
|
||||||
# past less than 30 minutes, can checkin
|
self._showTrace(
|
||||||
elif 0 <= time_diff_seconds < 30*60:
|
f"用户在 {date} 的预约开始时间为 {begin_time}, "
|
||||||
self._showTrace(
|
f"当前时间已经 {self.__formatDiffTime(abs(time_diff_seconds))}, 可以签到"
|
||||||
f"用户在日期 {date} 的预约开始时间为 {begin_time}, "
|
)
|
||||||
f"当前时间已经 {abs(time_diff_seconds)/60:.2f} 分钟, 可以签到"
|
return True
|
||||||
)
|
self._showTrace(f"用户在 {date} 没有有效预约记录, 无法签到")
|
||||||
return True
|
return False
|
||||||
else:
|
|
||||||
self._showTrace(f"用户在日期 {date} 的预约时间格式错误, 无法签到")
|
|
||||||
self._showTrace(f"用户在日期 {date} 有没有有效预约记录, 无法签到")
|
def canRenew(
|
||||||
|
self,
|
||||||
|
date: str
|
||||||
|
) -> bool:
|
||||||
|
|
||||||
|
# have a using record in the given date
|
||||||
|
record = self.__getReserveRecord(date, "使用中")
|
||||||
|
if record is not None:
|
||||||
|
end_time = record["time"]["end"]
|
||||||
|
end_time = datetime.strptime(f"{date} {end_time}", "%Y-%m-%d %H:%M")
|
||||||
|
time_diff = end_time - datetime.now()
|
||||||
|
time_diff_seconds = time_diff.total_seconds()
|
||||||
|
# a using record is definitely after the begin time
|
||||||
|
if abs(time_diff_seconds) < 120*60:
|
||||||
|
self._showTrace(
|
||||||
|
f"用户在 {date} 的预约结束时间为 {end_time}, "
|
||||||
|
f"距离当前时间还有 {self.__formatDiffTime(abs(time_diff_seconds))}, 可以续约"
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self._showTrace(
|
||||||
|
f"用户在 {date} 的预约结束时间为 {end_time}, "
|
||||||
|
f"距离当前时间还有 {self.__formatDiffTime(abs(time_diff_seconds))}, 无法续约"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
self._showTrace(f"用户在 {date} 没有有效预约记录, 无法续约")
|
||||||
return False
|
return False
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ class LibCheckout(LibOperator):
|
|||||||
|
|
||||||
|
|
||||||
def _waitResponseLoad(
|
def _waitResponseLoad(
|
||||||
self,
|
self
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
pass
|
pass
|
||||||
+46
-17
@@ -36,7 +36,7 @@ class LibLogin(LibOperator):
|
|||||||
|
|
||||||
|
|
||||||
def _waitResponseLoad(
|
def _waitResponseLoad(
|
||||||
self,
|
self
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
# wait to verify login success
|
# wait to verify login success
|
||||||
@@ -59,7 +59,7 @@ class LibLogin(LibOperator):
|
|||||||
def __fillLogInElements(
|
def __fillLogInElements(
|
||||||
self,
|
self,
|
||||||
username: str,
|
username: str,
|
||||||
password: str,
|
password: str
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
# ensure elements presence and fill them
|
# ensure elements presence and fill them
|
||||||
@@ -77,7 +77,7 @@ class LibLogin(LibOperator):
|
|||||||
|
|
||||||
|
|
||||||
def __autoRecognizeCaptcha(
|
def __autoRecognizeCaptcha(
|
||||||
self,
|
self
|
||||||
) -> str:
|
) -> str:
|
||||||
|
|
||||||
# auto recognize captcha
|
# auto recognize captcha
|
||||||
@@ -99,7 +99,7 @@ class LibLogin(LibOperator):
|
|||||||
|
|
||||||
|
|
||||||
def __manualRecognizeCaptcha(
|
def __manualRecognizeCaptcha(
|
||||||
self,
|
self
|
||||||
) -> str:
|
) -> str:
|
||||||
|
|
||||||
# manual recognize captcha
|
# manual recognize captcha
|
||||||
@@ -117,7 +117,7 @@ class LibLogin(LibOperator):
|
|||||||
|
|
||||||
|
|
||||||
def __refreshCaptcha(
|
def __refreshCaptcha(
|
||||||
self,
|
self
|
||||||
):
|
):
|
||||||
|
|
||||||
# refresh captcha
|
# refresh captcha
|
||||||
@@ -134,12 +134,47 @@ class LibLogin(LibOperator):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def __solveCaptcha(
|
||||||
|
self,
|
||||||
|
auto_captcha: bool = True
|
||||||
|
) -> str:
|
||||||
|
|
||||||
|
max_attempts = 5
|
||||||
|
|
||||||
|
for _ in range(max_attempts):
|
||||||
|
if auto_captcha:
|
||||||
|
captcha_text = self.__autoRecognizeCaptcha()
|
||||||
|
else:
|
||||||
|
self._showTrace(f"用户未配置自动识别验证码, 请手动输入验证码 !")
|
||||||
|
captcha_text = self.__manualRecognizeCaptcha()
|
||||||
|
if captcha_text:
|
||||||
|
return captcha_text
|
||||||
|
self._showTrace(f"验证码识别失败 {max_attempts} 次, 请检查验证码是否正确 !")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def __fillCaptchaElement(
|
||||||
|
self,
|
||||||
|
captcha_text: str
|
||||||
|
) -> bool:
|
||||||
|
|
||||||
|
try:
|
||||||
|
captcha_element = self.__driver.find_element(By.NAME, "answer")
|
||||||
|
captcha_element.clear()
|
||||||
|
captcha_element.send_keys(captcha_text)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
self._showTrace(f"验证码填写失败 ! : {e}")
|
||||||
|
self.__refreshCaptcha()
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def login(
|
def login(
|
||||||
self,
|
self,
|
||||||
username: str,
|
username: str,
|
||||||
password: str,
|
password: str,
|
||||||
max_attempts: int = 5,
|
max_attempts: int = 5,
|
||||||
auto_captcha: bool = True,
|
auto_captcha: bool = True
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
if self.__driver is None:
|
if self.__driver is None:
|
||||||
@@ -153,17 +188,11 @@ class LibLogin(LibOperator):
|
|||||||
password,
|
password,
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
while True:
|
captcha_text = self.__solveCaptcha(auto_captcha)
|
||||||
if auto_captcha:
|
if not captcha_text:
|
||||||
captcha_text = self.__autoRecognizeCaptcha()
|
continue
|
||||||
else:
|
if not self.__fillCaptchaElement(captcha_text):
|
||||||
self._showTrace(f"用户未配置自动识别验证码, 请手动输入验证码 !")
|
continue
|
||||||
captcha_text = self.__manualRecognizeCaptcha()
|
|
||||||
if captcha_text:
|
|
||||||
break
|
|
||||||
captcha_element = self.__driver.find_element(By.NAME, "answer")
|
|
||||||
captcha_element.clear()
|
|
||||||
captcha_element.send_keys(captcha_text)
|
|
||||||
self._showTrace("尝试登录...")
|
self._showTrace("尝试登录...")
|
||||||
try:
|
try:
|
||||||
self.__driver.find_element(
|
self.__driver.find_element(
|
||||||
|
|||||||
+3
-9
@@ -22,7 +22,7 @@ class LibLogout(LibOperator):
|
|||||||
self,
|
self,
|
||||||
input_queue: queue.Queue,
|
input_queue: queue.Queue,
|
||||||
output_queue: queue.Queue,
|
output_queue: queue.Queue,
|
||||||
driver,
|
driver
|
||||||
):
|
):
|
||||||
|
|
||||||
super().__init__(input_queue, output_queue)
|
super().__init__(input_queue, output_queue)
|
||||||
@@ -31,7 +31,7 @@ class LibLogout(LibOperator):
|
|||||||
|
|
||||||
|
|
||||||
def _waitResponseLoad(
|
def _waitResponseLoad(
|
||||||
self,
|
self
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -39,24 +39,18 @@ class LibLogout(LibOperator):
|
|||||||
|
|
||||||
def logout(
|
def logout(
|
||||||
self,
|
self,
|
||||||
username: str,
|
username: str
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
if self.__driver is None:
|
if self.__driver is None:
|
||||||
self._showTrace("未提供有效 WebDriver 实例 !")
|
self._showTrace("未提供有效 WebDriver 实例 !")
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.__driver.find_element(
|
self.__driver.find_element(
|
||||||
By.XPATH, "//a[@href='/logout']"
|
By.XPATH, "//a[@href='/logout']"
|
||||||
).click()
|
).click()
|
||||||
|
|
||||||
self._showTrace(f"用户 {username} 注销成功 !")
|
self._showTrace(f"用户 {username} 注销成功 !")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._showTrace(f"用户 {username} 注销失败 ! : {e}")
|
self._showTrace(f"用户 {username} 注销失败 ! : {e}")
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|||||||
+2
-2
@@ -17,14 +17,14 @@ class LibOperator(MsgBase):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
input_queue: queue.Queue,
|
input_queue: queue.Queue,
|
||||||
output_queue: queue.Queue,
|
output_queue: queue.Queue
|
||||||
):
|
):
|
||||||
|
|
||||||
super().__init__(input_queue, output_queue)
|
super().__init__(input_queue, output_queue)
|
||||||
|
|
||||||
|
|
||||||
def _waitResponseLoad(
|
def _waitResponseLoad(
|
||||||
self,
|
self
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ class LibRenew(LibOperator):
|
|||||||
|
|
||||||
|
|
||||||
def _waitResponseLoad(
|
def _waitResponseLoad(
|
||||||
self,
|
self
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
pass
|
pass
|
||||||
+9
-98
@@ -83,9 +83,9 @@ class LibReserve(LibOperator):
|
|||||||
raise
|
raise
|
||||||
if "预定好了" in title or "预约成功" in title or "操作成功" in title:
|
if "预定好了" in title or "预约成功" in title or "操作成功" in title:
|
||||||
if len(contents) >= 6:
|
if len(contents) >= 6:
|
||||||
date_val = contents[1].split(" : ")[1].strip() if " : " in contents[1] else contents[1].strip()
|
date_val = contents[1].split(" : ")[1].strip() if " : " in contents[1] else contents[1].strip()
|
||||||
time_val = contents[2].split(" : ")[1].strip() if " : " in contents[2] else contents[2].strip()
|
time_val = contents[2].split(" : ")[1].strip() if " : " in contents[2] else contents[2].strip()
|
||||||
seat_val = contents[3].split(" : ")[1].strip() if " : " in contents[3] else contents[3].strip()
|
seat_val = contents[3].split(" : ")[1].strip() if " : " in contents[3] else contents[3].strip()
|
||||||
checkin_val = contents[5].strip()
|
checkin_val = contents[5].strip()
|
||||||
self._showTrace(f"\n"\
|
self._showTrace(f"\n"\
|
||||||
f" 预约成功 !\n"\
|
f" 预约成功 !\n"\
|
||||||
@@ -137,10 +137,12 @@ class LibReserve(LibOperator):
|
|||||||
raise ValueError(f"房间 '{reserve_info['room']}' 不存在")
|
raise ValueError(f"房间 '{reserve_info['room']}' 不存在")
|
||||||
if reserve_info.get("seat_id") is None:
|
if reserve_info.get("seat_id") is None:
|
||||||
raise ValueError("未指定座位")
|
raise ValueError("未指定座位")
|
||||||
|
if reserve_info["seat_id"] == "":
|
||||||
|
raise ValueError("未指定座位号")
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
self._showTrace(
|
self._showTrace(
|
||||||
f"预约信息错误 ! : {e}, "\
|
f"预约信息错误 ! : {e}, "\
|
||||||
f"由于缺少必要的预约信息, 无法开始预约流程, 请检查预约信息是否完整"
|
f"由于缺少必要的预约信息, 无法开始预约流程, 请检查预约信息是否完整"
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -224,7 +226,7 @@ class LibReserve(LibOperator):
|
|||||||
reserve_info["begin_time"]["time"], reserve_info["end_time"]["time"] = end_time_str, begin_time_str
|
reserve_info["begin_time"]["time"], reserve_info["end_time"]["time"] = end_time_str, begin_time_str
|
||||||
reserve_info["begin_time"]["prefer_early"], reserve_info["end_time"]["prefer_early"] = \
|
reserve_info["begin_time"]["prefer_early"], reserve_info["end_time"]["prefer_early"] = \
|
||||||
reserve_info["end_time"]["prefer_early"], reserve_info["begin_time"]["prefer_early"]
|
reserve_info["end_time"]["prefer_early"], reserve_info["begin_time"]["prefer_early"]
|
||||||
self._showTrace("预约开始时间晚于预约结束时间,自动调换开始时间和结束时间")
|
self._showTrace("预约开始时间晚于预约结束时间, 自动调换开始时间和结束时间")
|
||||||
|
|
||||||
# update the begin_mins and end_mins after swap
|
# update the begin_mins and end_mins after swap
|
||||||
begin_time_str, end_time_str = end_time_str, begin_time_str
|
begin_time_str, end_time_str = end_time_str, begin_time_str
|
||||||
@@ -246,7 +248,7 @@ class LibReserve(LibOperator):
|
|||||||
reserve_info["end_time"]["time"] = self.__minsToTime(new_end_mins)
|
reserve_info["end_time"]["time"] = self.__minsToTime(new_end_mins)
|
||||||
self._showTrace("预约持续时间超过8小时, 自动设置为 8 小时")
|
self._showTrace("预约持续时间超过8小时, 自动设置为 8 小时")
|
||||||
self._showTrace(
|
self._showTrace(
|
||||||
f"预约信息检查完成,准备预约 "
|
f"预约信息检查完成, 准备预约 "
|
||||||
f"{reserve_info['date']} "
|
f"{reserve_info['date']} "
|
||||||
f"{reserve_info['begin_time']["time"]} - "
|
f"{reserve_info['begin_time']["time"]} - "
|
||||||
f"{reserve_info['end_time']["time"]} "
|
f"{reserve_info['end_time']["time"]} "
|
||||||
@@ -263,7 +265,7 @@ class LibReserve(LibOperator):
|
|||||||
trigger_locator: tuple,
|
trigger_locator: tuple,
|
||||||
fail_msg: str,
|
fail_msg: str,
|
||||||
success_msg: str,
|
success_msg: str,
|
||||||
option_locator: tuple = None,
|
option_locator: tuple = None
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -489,97 +491,6 @@ class LibReserve(LibOperator):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def canReserve(
|
|
||||||
self,
|
|
||||||
date: str
|
|
||||||
) -> bool:
|
|
||||||
|
|
||||||
if date is None:
|
|
||||||
self._showTrace("日期未指定, 无法检查预约状态")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
self._showTrace(f"正在检查用户在日期 {date} 是否可预约......")
|
|
||||||
date_obj = datetime.strptime(date, "%Y-%m-%d").date()
|
|
||||||
try:
|
|
||||||
# we need to navigate to the history page to check if we can reserve
|
|
||||||
WebDriverWait(self.__driver, 5).until(
|
|
||||||
EC.element_to_be_clickable((By.XPATH, "//a[@href='/history?type=SEAT']"))
|
|
||||||
).click()
|
|
||||||
WebDriverWait(self.__driver, 2).until(
|
|
||||||
EC.presence_of_element_located((By.CLASS_NAME, "myReserveList"))
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
self._showTrace("加载预约记录页面失败 !")
|
|
||||||
return False
|
|
||||||
checked_count = 0
|
|
||||||
max_attemots = 3 # we only check (3*4=)12 reservations
|
|
||||||
|
|
||||||
for _ in range(max_attemots):
|
|
||||||
try:
|
|
||||||
# check if there's any reservation on the date
|
|
||||||
reservations = self.__driver.find_elements(
|
|
||||||
By.CSS_SELECTOR, ".myReserveList dl"
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
self._showTrace("加载预约记录失败 !")
|
|
||||||
return False
|
|
||||||
for i in range(checked_count, len(reservations) - 1): # the last one is load button
|
|
||||||
reservation = reservations[i]
|
|
||||||
try:
|
|
||||||
time_element = reservation.find_element(
|
|
||||||
By.CSS_SELECTOR, "dt"
|
|
||||||
)
|
|
||||||
status_elements = reservation.find_elements(
|
|
||||||
By.CSS_SELECTOR, "a"
|
|
||||||
)
|
|
||||||
is_reserved = any("已预约" in status.text for status in status_elements)
|
|
||||||
# process time element to get the date string
|
|
||||||
time_str = time_element.text.strip()
|
|
||||||
today = datetime.now().date()
|
|
||||||
if "明天" in time_str:
|
|
||||||
target_date = today + timedelta(days=1)
|
|
||||||
date_str = target_date.strftime("%Y-%m-%d")
|
|
||||||
elif "今天" in time_str:
|
|
||||||
target_date = today
|
|
||||||
date_str = target_date.strftime("%Y-%m-%d")
|
|
||||||
elif "昨天" in time_str:
|
|
||||||
target_date = today - timedelta(days=1)
|
|
||||||
date_str = target_date.strftime("%Y-%m-%d")
|
|
||||||
else:
|
|
||||||
date_match = re.search(r'(\d{4}-\d{1,2}-\d{1,2})', time_str)
|
|
||||||
if date_match:
|
|
||||||
date_str = date_match.group(1)
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
# reservation is earlier than the given date, can reserve
|
|
||||||
if datetime.strptime(date_str, "%Y-%m-%d").date() < date_obj:
|
|
||||||
self._showTrace(f"用户在 {date} 可预约")
|
|
||||||
return True
|
|
||||||
# reservation is later than the given date, check the next one
|
|
||||||
elif datetime.strptime(date_str, "%Y-%m-%d").date() > date_obj:
|
|
||||||
continue
|
|
||||||
# compare with the given date
|
|
||||||
if date_str == date and is_reserved:
|
|
||||||
self._showTrace(f"用户在 {date} 已存在有效预约, 无法预约")
|
|
||||||
return False
|
|
||||||
except:
|
|
||||||
self._showTrace(f"解析第 {i + 1} 条预约记录时发生未知错误 !")
|
|
||||||
continue
|
|
||||||
checked_count = len(reservations) - 1
|
|
||||||
# load new reservations if still not sure
|
|
||||||
try:
|
|
||||||
more_btn = self.__driver.find_element(By.ID, "moreBtn")
|
|
||||||
if more_btn.is_displayed() and more_btn.is_enabled():
|
|
||||||
self.__driver.execute_script("arguments[0].scrollIntoView(true);", more_btn)
|
|
||||||
self.__driver.execute_script("arguments[0].click();", more_btn)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
break
|
|
||||||
self._showTrace(f"用户在 {date} 可预约")
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def reserve(
|
def reserve(
|
||||||
self,
|
self,
|
||||||
reserve_info: dict
|
reserve_info: dict
|
||||||
|
|||||||
+3
-3
@@ -16,7 +16,7 @@ class MsgBase:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
input_queue: queue.Queue,
|
input_queue: queue.Queue,
|
||||||
output_queue: queue.Queue,
|
output_queue: queue.Queue
|
||||||
):
|
):
|
||||||
|
|
||||||
self._class_name = self.__class__.__name__
|
self._class_name = self.__class__.__name__
|
||||||
@@ -43,7 +43,7 @@ class MsgBase:
|
|||||||
|
|
||||||
def _waitMsg(
|
def _waitMsg(
|
||||||
self,
|
self,
|
||||||
timeout: float = 1.0,
|
timeout: float = 1.0
|
||||||
) -> str:
|
) -> str:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -55,7 +55,7 @@ class MsgBase:
|
|||||||
|
|
||||||
def _inputMsg(
|
def _inputMsg(
|
||||||
self,
|
self,
|
||||||
timeout: float = 1.0,
|
timeout: float = 1.0
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -569,7 +569,7 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
|
|||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def onFloorComboBoxCurrentIndexChanged(
|
def onFloorComboBoxCurrentIndexChanged(
|
||||||
self,
|
self
|
||||||
):
|
):
|
||||||
|
|
||||||
floor = self.FloorComboBox.currentText()
|
floor = self.FloorComboBox.currentText()
|
||||||
|
|||||||
@@ -1127,13 +1127,13 @@
|
|||||||
<widget class="QLineEdit" name="BrowseBrowserDriverEdit">
|
<widget class="QLineEdit" name="BrowseBrowserDriverEdit">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>265</width>
|
<width>250</width>
|
||||||
<height>25</height>
|
<height>25</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>260</width>
|
<width>300</width>
|
||||||
<height>25</height>
|
<height>25</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
|||||||
+11
-17
@@ -70,7 +70,7 @@ class AutoLibWorker(QThread):
|
|||||||
os.path.exists(path) for path in self.__config_paths.values()
|
os.path.exists(path) for path in self.__config_paths.values()
|
||||||
):
|
):
|
||||||
self.showTraceSignal.emit(
|
self.showTraceSignal.emit(
|
||||||
"配置文件路径不存在,请检查配置文件路径是否正确。"
|
"配置文件路径不存在, 请检查配置文件路径是否正确。"
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
@@ -102,7 +102,7 @@ class AutoLibWorker(QThread):
|
|||||||
self.showTraceSignal.emit("AutoLibrary 运行结束")
|
self.showTraceSignal.emit("AutoLibrary 运行结束")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.showTraceSignal.emit(
|
self.showTraceSignal.emit(
|
||||||
f"AutoLibrary 运行时发生异常:{e}"
|
f"AutoLibrary 运行时发生异常 : {e}"
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
self.finishedSignal.emit()
|
self.finishedSignal.emit()
|
||||||
@@ -127,10 +127,6 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.__input_queue = queue.Queue()
|
self.__input_queue = queue.Queue()
|
||||||
self.__output_queue = queue.Queue()
|
self.__output_queue = queue.Queue()
|
||||||
self.__auto_lib = AutoLib(
|
|
||||||
self.__input_queue,
|
|
||||||
self.__output_queue,
|
|
||||||
)
|
|
||||||
self.__config_paths = {
|
self.__config_paths = {
|
||||||
"system":
|
"system":
|
||||||
f"{QDir.toNativeSeparators(QFileInfo(sys.executable).absoluteDir().absoluteFilePath("system.json"))}",
|
f"{QDir.toNativeSeparators(QFileInfo(sys.executable).absoluteDir().absoluteFilePath("system.json"))}",
|
||||||
@@ -167,13 +163,11 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
|
|
||||||
def closeEvent(
|
def closeEvent(
|
||||||
self,
|
self,
|
||||||
event: QCloseEvent,
|
event: QCloseEvent
|
||||||
):
|
):
|
||||||
|
|
||||||
if self.__timer and self.__timer.isActive():
|
if self.__timer and self.__timer.isActive():
|
||||||
self.__timer.stop()
|
self.__timer.stop()
|
||||||
if self.__auto_lib:
|
|
||||||
self.__auto_lib.close()
|
|
||||||
if self.__alConfigWidget:
|
if self.__alConfigWidget:
|
||||||
self.__alConfigWidget.close()
|
self.__alConfigWidget.close()
|
||||||
super().closeEvent(event)
|
super().closeEvent(event)
|
||||||
@@ -181,7 +175,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
|
|
||||||
def appendToTextEdit(
|
def appendToTextEdit(
|
||||||
self,
|
self,
|
||||||
text: str,
|
text: str
|
||||||
):
|
):
|
||||||
|
|
||||||
cursor = self.MessageIOTextEdit.textCursor()
|
cursor = self.MessageIOTextEdit.textCursor()
|
||||||
@@ -206,7 +200,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
self,
|
self,
|
||||||
config_button_enabled: bool,
|
config_button_enabled: bool,
|
||||||
start_button_enabled: bool,
|
start_button_enabled: bool,
|
||||||
stop_button_enabled: bool,
|
stop_button_enabled: bool
|
||||||
):
|
):
|
||||||
|
|
||||||
self.ConfigButton.setEnabled(config_button_enabled)
|
self.ConfigButton.setEnabled(config_button_enabled)
|
||||||
@@ -216,7 +210,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
@Slot()
|
@Slot()
|
||||||
def showMsg(
|
def showMsg(
|
||||||
self,
|
self,
|
||||||
msg: str,
|
msg: str
|
||||||
):
|
):
|
||||||
|
|
||||||
self.appendToTextEdit(f"[{self.__class_name:<12}] >>> : {msg}")
|
self.appendToTextEdit(f"[{self.__class_name:<12}] >>> : {msg}")
|
||||||
@@ -224,7 +218,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
@Slot()
|
@Slot()
|
||||||
def showTrace(
|
def showTrace(
|
||||||
self,
|
self,
|
||||||
msg: str,
|
msg: str
|
||||||
):
|
):
|
||||||
|
|
||||||
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
||||||
@@ -232,7 +226,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def pollMsgQueue(
|
def pollMsgQueue(
|
||||||
self,
|
self
|
||||||
):
|
):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -245,7 +239,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
@Slot(dict)
|
@Slot(dict)
|
||||||
def onConfigWidgetClosed(
|
def onConfigWidgetClosed(
|
||||||
self,
|
self,
|
||||||
config_paths: dict,
|
config_paths: dict
|
||||||
):
|
):
|
||||||
|
|
||||||
self.__alConfigWidget = None
|
self.__alConfigWidget = None
|
||||||
@@ -256,7 +250,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def onConfigButtonClicked(
|
def onConfigButtonClicked(
|
||||||
self,
|
self
|
||||||
):
|
):
|
||||||
|
|
||||||
if self.__alConfigWidget is None:
|
if self.__alConfigWidget is None:
|
||||||
@@ -274,7 +268,7 @@ class ALMainWindow(QMainWindow, Ui_ALMainWindow):
|
|||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def onStartButtonClicked(
|
def onStartButtonClicked(
|
||||||
self,
|
self
|
||||||
):
|
):
|
||||||
|
|
||||||
self.setControlButtons(False, False, True)
|
self.setControlButtons(False, False, True)
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
Copyright 2025 KenanZhu
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
Reference in New Issue
Block a user