mirror of
https://github.com/KenanZhu/AutoLibrary.git
synced 2026-06-17 23:13:03 +08:00
refactor(LibReserve, LibRenew): 提取时间选择公共逻辑到 LibTimeSelector 基类
将 LibReserve 和 LibRenew 中重复的时间转换和选择逻辑提取到 LibTimeSelector 基类,消除代码重复,提升可维护性。 主要变更: - 新增 LibTimeSelector 基类,提供时间转换和最佳时间选择算法 - LibReserve 和 LibRenew 继承 LibTimeSelector,移除重复代码 - 拆分过长方法,提升代码可读性 - 修正方法命名 __selectNearstTime -> __selectNearestTime 同时修复续约功能业务逻辑漏洞: - 新增续约时间上限校验,防止续约时间超过图书馆闭馆时间(23:30)
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2025 - 2026 KenanZhu.
|
||||
All rights reserved.
|
||||
|
||||
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.
|
||||
"""
|
||||
import queue
|
||||
|
||||
from base.LibOperator import LibOperator
|
||||
|
||||
|
||||
class LibTimeSelector(LibOperator):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
input_queue: queue.Queue,
|
||||
output_queue: queue.Queue
|
||||
):
|
||||
|
||||
super().__init__(input_queue, output_queue)
|
||||
|
||||
@staticmethod
|
||||
def _timeToMins(
|
||||
time_str: str
|
||||
) -> int:
|
||||
|
||||
"""
|
||||
Convert time string "HH:MM" to minutes since midnight.
|
||||
"""
|
||||
hour, minute = map(int, time_str.split(":"))
|
||||
return hour*60 + minute
|
||||
|
||||
@staticmethod
|
||||
def _minsToTime(
|
||||
mins: int
|
||||
) -> str:
|
||||
|
||||
"""
|
||||
Convert minutes since midnight to time string "HH:MM".
|
||||
"""
|
||||
hour, minute = divmod(mins, 60)
|
||||
return f"{hour:02d}:{minute:02d}"
|
||||
|
||||
|
||||
def _formatTimeRelation(
|
||||
self,
|
||||
abs_diff: int,
|
||||
actual_diff: int,
|
||||
time_type: str
|
||||
) -> str:
|
||||
|
||||
"""
|
||||
Format time difference relation string.
|
||||
"""
|
||||
if actual_diff < 0:
|
||||
return f"早了 {abs_diff} 分钟"
|
||||
elif actual_diff > 0:
|
||||
return f"晚了 {abs_diff} 分钟"
|
||||
else:
|
||||
return f"正好等于 {time_type}"
|
||||
|
||||
|
||||
def _findBestTimeOption(
|
||||
self,
|
||||
time_options: list,
|
||||
target_time: int,
|
||||
max_time_diff: int,
|
||||
prefer_earlier: bool,
|
||||
is_reserve: bool = True
|
||||
) -> tuple:
|
||||
"""
|
||||
Find the best time option from available times.
|
||||
|
||||
Args:
|
||||
time_options: List of WebElement time options
|
||||
target_time: Target time in minutes
|
||||
max_time_diff: Maximum acceptable time difference in minutes
|
||||
prefer_earlier: If True, prefer earlier times when diffs are equal
|
||||
is_reserve: If True, parse 'time' attribute; if False, parse 'id' attribute
|
||||
|
||||
Returns:
|
||||
Tuple of (best_time_element, best_time_text, actual_diff, free_times_list)
|
||||
or (None, None, None, []) if no suitable option found
|
||||
"""
|
||||
free_times = []
|
||||
best_time_diff = max_time_diff
|
||||
best_actual_diff = None
|
||||
best_time_opt = None
|
||||
|
||||
for time_opt in time_options:
|
||||
# Parse time value based on context
|
||||
if is_reserve:
|
||||
time_attr = time_opt.get_attribute("time")
|
||||
if time_attr == "now":
|
||||
from datetime import datetime
|
||||
now = datetime.now()
|
||||
time_val = now.hour * 60 + now.minute
|
||||
elif time_attr and time_attr.isdigit():
|
||||
time_val = int(time_attr)
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
# Renewal context: parse 'id' attribute
|
||||
time_attr = time_opt.get_attribute("id")
|
||||
if not (time_attr and time_attr.isdigit()):
|
||||
continue
|
||||
time_val = int(time_attr)
|
||||
|
||||
free_times.append(time_opt.text.strip() if not is_reserve else self._minsToTime(time_val))
|
||||
|
||||
actual_diff = time_val - target_time
|
||||
abs_diff = abs(actual_diff)
|
||||
|
||||
# Update best option if current is better
|
||||
if (abs_diff < best_time_diff or
|
||||
(abs_diff == best_time_diff and
|
||||
((prefer_earlier and actual_diff <= 0) or
|
||||
(not prefer_earlier and actual_diff >= 0)))):
|
||||
|
||||
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)
|
||||
+75
-84
@@ -14,10 +14,10 @@ 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.LibOperator import LibOperator
|
||||
from base.LibTimeSelector import LibTimeSelector
|
||||
|
||||
|
||||
class LibRenew(LibOperator):
|
||||
class LibRenew(LibTimeSelector):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -38,22 +38,6 @@ class LibRenew(LibOperator):
|
||||
self.__driver.refresh()
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def __timeToMins(
|
||||
time_str: str
|
||||
) -> int:
|
||||
|
||||
hour, minute = map(int, time_str.split(":"))
|
||||
return hour*60 + minute
|
||||
|
||||
@staticmethod
|
||||
def __minsToTime(
|
||||
mins: int
|
||||
) -> str:
|
||||
|
||||
hour, minute = divmod(mins, 60)
|
||||
return f"{hour:02d}:{minute:02d}"
|
||||
|
||||
|
||||
def __waitRenewDialog(
|
||||
self
|
||||
@@ -94,85 +78,92 @@ class LibRenew(LibOperator):
|
||||
return True
|
||||
|
||||
|
||||
def __selectNearstTime(
|
||||
def __selectNearestTime(
|
||||
self,
|
||||
record: dict,
|
||||
reserve_info: dict
|
||||
) -> bool:
|
||||
|
||||
"""
|
||||
TODO : this function is too long and too ugly
|
||||
|
||||
we need to refactor it to make it more readable.
|
||||
but may be it is not a good idea to refactor it. :) who knows...
|
||||
Select the nearest available renewal time.
|
||||
"""
|
||||
|
||||
end_time = record["time"]["end"]
|
||||
renew_info = reserve_info["renew_time"]
|
||||
max_diff = renew_info["max_diff"]
|
||||
prefer_earlier = renew_info["prefer_early"]
|
||||
target_renew_mins = self.__timeToMins(end_time) + renew_info["expect_duration"]*60
|
||||
renew_ok_btn = self.__driver.find_element(
|
||||
By.CSS_SELECTOR, "#extendDiv .btnOK"
|
||||
)
|
||||
try:
|
||||
renew_time_opts = self.__driver.find_elements(
|
||||
By.CSS_SELECTOR, "#extendDiv .renewal_List li"
|
||||
)
|
||||
free_times = []
|
||||
best_time_diff = max_diff
|
||||
best_actual_diff = None
|
||||
best_time_opt = None
|
||||
target_renew_mins = self._timeToMins(end_time) + renew_info["expect_duration"]*60
|
||||
|
||||
if not renew_time_opts:
|
||||
self._showTrace("当前未查询到可用续约时间 !")
|
||||
return False
|
||||
for time_opt in renew_time_opts:
|
||||
time_attr = time_opt.get_attribute("id")
|
||||
if time_attr and time_attr.isdigit():
|
||||
time_val = int(time_attr)
|
||||
free_times.append(time_opt.text.strip())
|
||||
else:
|
||||
continue
|
||||
actual_diff = time_val - target_renew_mins
|
||||
abs_diff = abs(actual_diff)
|
||||
if abs_diff < best_time_diff or (
|
||||
abs_diff == best_time_diff and (
|
||||
(prefer_earlier and actual_diff <= 0) or
|
||||
(not prefer_earlier and actual_diff >= 0)
|
||||
)
|
||||
):
|
||||
best_time_diff = abs_diff
|
||||
best_actual_diff = actual_diff
|
||||
best_time_opt = time_opt
|
||||
|
||||
if best_time_opt is not None:
|
||||
best_time_opt.click()
|
||||
abs_time_diff = abs(best_actual_diff)
|
||||
if best_actual_diff < 0:
|
||||
time_relation = f"早了 {abs_time_diff} 分钟"
|
||||
elif best_actual_diff > 0:
|
||||
time_relation = f"晚了 {abs_time_diff} 分钟"
|
||||
else:
|
||||
time_relation = f"正好等于续约时间"
|
||||
self._showTrace(
|
||||
f"选择距离期望续约时间最近的 {best_time_opt.text}, "\
|
||||
f"与期望续约时间相比 {time_relation}"
|
||||
)
|
||||
# update the actual renew end time
|
||||
record["time"]["end"] = best_time_opt.text.strip()
|
||||
renew_ok_btn.click()
|
||||
return True
|
||||
self._showTrace(
|
||||
"无法选择最近的可用续约时间 !" \
|
||||
f"所有可选时间与目标时间相差都超过了 {max_diff} 分钟 !"
|
||||
)
|
||||
self._showTrace(
|
||||
f"当前可供续约的时间有: {free_times}"
|
||||
)
|
||||
# Validate and adjust target renew time to library closing time
|
||||
if not self.__validateAndAdjustRenewTime(end_time, target_renew_mins):
|
||||
return False
|
||||
renew_ok_btn = self.__driver.find_element(By.CSS_SELECTOR, "#extendDiv .btnOK")
|
||||
renew_time_opts = self.__driver.find_elements(By.CSS_SELECTOR, "#extendDiv .renewal_List li")
|
||||
if not renew_time_opts:
|
||||
self._showTrace("当前未查询到可用续约时间 !")
|
||||
return False
|
||||
|
||||
# Find best renewal time option
|
||||
best_opt, best_text, actual_diff, free_times = self._findBestTimeOption(
|
||||
renew_time_opts, target_renew_mins, max_diff, prefer_earlier, is_reserve=False
|
||||
)
|
||||
if best_opt is not None:
|
||||
return self.__confirmRenewal(best_opt, best_text, actual_diff, record, renew_ok_btn)
|
||||
self._showTrace(
|
||||
"无法选择最近的可用续约时间 ! "
|
||||
f"所有可选时间与目标时间相差都超过了 {max_diff} 分钟 !"
|
||||
)
|
||||
self._showTrace(f"当前可供续约的时间有: {free_times}")
|
||||
return False
|
||||
|
||||
|
||||
def __validateAndAdjustRenewTime(
|
||||
self,
|
||||
end_time: str,
|
||||
target_renew_mins: int
|
||||
) -> bool:
|
||||
|
||||
"""
|
||||
Validate and adjust renewal time to library closing time if needed.
|
||||
"""
|
||||
LIBRARY_CLOSE_TIME = 1410 # 23:30 in minutes
|
||||
if target_renew_mins > LIBRARY_CLOSE_TIME:
|
||||
actual_renew_duration = LIBRARY_CLOSE_TIME - self._timeToMins(end_time)
|
||||
if actual_renew_duration <= 0:
|
||||
self._showTrace(f"当前结束时间 {end_time} 已接近闭馆时间,无法续约 !")
|
||||
return False
|
||||
self._showTrace(
|
||||
f"续约时间已调整至闭馆时间 {self._minsToTime(LIBRARY_CLOSE_TIME)},"
|
||||
f"实际续约时长为 {actual_renew_duration//60} 小时 {actual_renew_duration%60} 分钟"
|
||||
)
|
||||
return True
|
||||
return True
|
||||
|
||||
|
||||
def __confirmRenewal(
|
||||
self,
|
||||
best_opt,
|
||||
best_text: str,
|
||||
actual_diff: int,
|
||||
record: dict,
|
||||
ok_btn
|
||||
) -> bool:
|
||||
|
||||
"""
|
||||
Confirm the selected renewal time.
|
||||
"""
|
||||
try:
|
||||
best_opt.click()
|
||||
abs_diff = abs(actual_diff)
|
||||
time_relation = self._formatTimeRelation(abs_diff, actual_diff, "续约时间")
|
||||
self._showTrace(
|
||||
f"选择距离期望续约时间最近的 {best_text}, "
|
||||
f"与期望续约时间相比 {time_relation}"
|
||||
)
|
||||
record["time"]["end"] = best_text.strip()
|
||||
ok_btn.click()
|
||||
return True
|
||||
except:
|
||||
self._showTrace("查询可用续约时间时发生未知错误 !")
|
||||
self._showTrace("确认续约时发生错误 !")
|
||||
return False
|
||||
|
||||
|
||||
@@ -204,7 +195,7 @@ class LibRenew(LibOperator):
|
||||
# so we need to refresh the page for subsequent operations.
|
||||
self.__driver.refresh()
|
||||
return False
|
||||
if not self.__selectNearstTime(record, reserve_info):
|
||||
if not self.__selectNearestTime(record, reserve_info):
|
||||
self._showTrace(f"用户 {username} 续约失败 !")
|
||||
self.__driver.refresh()
|
||||
return False
|
||||
|
||||
+75
-108
@@ -10,16 +10,15 @@ See the LICENSE file for details.
|
||||
import time
|
||||
import queue
|
||||
|
||||
from datetime import datetime
|
||||
from selenium.webdriver.common.by import By
|
||||
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.LibOperator import LibOperator
|
||||
from base.LibTimeSelector import LibTimeSelector
|
||||
|
||||
|
||||
class LibReserve(LibOperator):
|
||||
class LibReserve(LibTimeSelector):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -100,22 +99,6 @@ class LibReserve(LibOperator):
|
||||
self._showTrace(f"预约结果加载失败 !")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def __timeToMins(
|
||||
time_str: str
|
||||
) -> int:
|
||||
|
||||
hour, minute = map(int, time_str.split(":"))
|
||||
return hour*60 + minute
|
||||
|
||||
@staticmethod
|
||||
def __minsToTime(
|
||||
mins: int
|
||||
) -> str:
|
||||
|
||||
hour, minute = divmod(mins, 60)
|
||||
return f"{hour:02d}:{minute:02d}"
|
||||
|
||||
|
||||
def __containRequiredInfo(
|
||||
self,
|
||||
@@ -207,10 +190,10 @@ class LibReserve(LibOperator):
|
||||
if reserve_info.get("end_time") is None:
|
||||
reserve_info["end_time"] = {}
|
||||
if "time" not in reserve_info["end_time"]:
|
||||
end_mins = self.__timeToMins(reserve_info["begin_time"]["time"])
|
||||
end_mins = self._timeToMins(reserve_info["begin_time"]["time"])
|
||||
end_mins = end_mins + int(reserve_info["expect_duration"]*60)
|
||||
reserve_info["end_time"] = {
|
||||
"time": self.__minsToTime(end_mins),
|
||||
"time": self._minsToTime(end_mins),
|
||||
"max_diff": 30,
|
||||
"prefer_early": False
|
||||
}
|
||||
@@ -232,8 +215,8 @@ class LibReserve(LibOperator):
|
||||
):
|
||||
|
||||
begin_time, end_time = reserve_info["begin_time"], reserve_info["end_time"]
|
||||
begin_mins = self.__timeToMins(begin_time["time"])
|
||||
end_mins = self.__timeToMins(end_time["time"])
|
||||
begin_mins = self._timeToMins(begin_time["time"])
|
||||
end_mins = self._timeToMins(end_time["time"])
|
||||
# if end time is earlier than begin_time, exchange them
|
||||
if end_mins < begin_mins:
|
||||
self._showTrace(
|
||||
@@ -242,15 +225,15 @@ class LibReserve(LibOperator):
|
||||
reserve_info["end_time"] = begin_time
|
||||
reserve_info["begin_time"] = end_time
|
||||
begin_time, end_time = reserve_info["begin_time"], reserve_info["end_time"]
|
||||
begin_mins = self.__timeToMins(begin_time["time"])
|
||||
end_mins = self.__timeToMins(end_time["time"])
|
||||
begin_mins = self._timeToMins(begin_time["time"])
|
||||
end_mins = self._timeToMins(end_time["time"])
|
||||
# ensure the end time is not later than 23:30
|
||||
if end_mins > self.__timeToMins("23:30"):
|
||||
if end_mins > self._timeToMins("23:30"):
|
||||
self._showTrace(
|
||||
f"结束时间 {end_time['time']} 晚于 23:30, 自动设置为 23:30"
|
||||
)
|
||||
reserve_info["end_time"]["time"] = "23:30"
|
||||
end_mins = self.__timeToMins("23:30")
|
||||
end_mins = self._timeToMins("23:30")
|
||||
# ensure the duration is not longer than 8 hours
|
||||
if reserve_info["satisfy_duration"]:
|
||||
if reserve_info["expect_duration"] > 8:
|
||||
@@ -267,7 +250,7 @@ class LibReserve(LibOperator):
|
||||
f"{float((end_mins - begin_mins)/60)} 小时 "
|
||||
f"超出最大时长 8 小时, 自动设置为 8 小时"
|
||||
)
|
||||
reserve_info["end_time"]["time"] = self.__minsToTime(begin_mins + 8*60)
|
||||
reserve_info["end_time"]["time"] = self._minsToTime(begin_mins + 8*60)
|
||||
return True
|
||||
|
||||
|
||||
@@ -496,6 +479,10 @@ class LibReserve(LibOperator):
|
||||
prefer_earlier: bool = True
|
||||
) -> int:
|
||||
|
||||
"""
|
||||
Select the nearest available time option.
|
||||
"""
|
||||
# Wait for time options to load
|
||||
try:
|
||||
WebDriverWait(self.__driver, 2).until(
|
||||
EC.presence_of_all_elements_located(
|
||||
@@ -505,67 +492,34 @@ class LibReserve(LibOperator):
|
||||
except:
|
||||
self._showTrace(f"{time_type} 选择失败 ! : 当前未查询到可用时间")
|
||||
return -1
|
||||
try:
|
||||
all_time_opts = self.__driver.find_elements(
|
||||
By.CSS_SELECTOR,
|
||||
f"#{time_id} ul li a"
|
||||
)
|
||||
free_times = []
|
||||
best_time_diff = max_time_diff
|
||||
best_actual_diff = None
|
||||
best_time_opt = None
|
||||
|
||||
if not all_time_opts:
|
||||
self._showTrace(f"{time_type} 选择失败 ! : 当前未查询到可用时间")
|
||||
return -1
|
||||
for time_opt in all_time_opts:
|
||||
time_attr = time_opt.get_attribute("time")
|
||||
if time_attr == "now":
|
||||
now = datetime.now()
|
||||
time_val = int(now.hour*60 + now.minute)
|
||||
elif time_attr and time_attr.isdigit():
|
||||
time_val = int(time_attr)
|
||||
else:
|
||||
continue
|
||||
free_times.append(self.__minsToTime(time_val))
|
||||
actual_diff = time_val - target_time
|
||||
abs_diff = abs(actual_diff)
|
||||
if abs_diff < best_time_diff or (
|
||||
abs_diff == best_time_diff and (
|
||||
# prefer earlier time
|
||||
(prefer_earlier and actual_diff <= 0) or
|
||||
# prefer later time
|
||||
(not prefer_earlier and actual_diff >= 0)
|
||||
)
|
||||
):
|
||||
best_time_diff = abs_diff
|
||||
best_actual_diff = actual_diff
|
||||
best_time_opt = time_opt
|
||||
|
||||
if best_time_opt is not None:
|
||||
best_time_opt.click()
|
||||
abs_time_diff = abs(best_actual_diff)
|
||||
if best_actual_diff < 0:
|
||||
time_relation = f"早了 {abs_time_diff} 分钟"
|
||||
elif best_actual_diff > 0:
|
||||
time_relation = f"晚了 {abs_time_diff} 分钟"
|
||||
else:
|
||||
time_relation = f"正好等于 {time_type}"
|
||||
target_time += best_actual_diff
|
||||
self._showTrace(
|
||||
f"选择距离期望 {time_type} 最近的 {best_time_opt.text}, "\
|
||||
f"与期望 {time_type} 相比 {time_relation}"
|
||||
)
|
||||
return target_time
|
||||
# Find best time option
|
||||
all_time_opts = self.__driver.find_elements(
|
||||
By.CSS_SELECTOR,
|
||||
f"#{time_id} ul li a"
|
||||
)
|
||||
if not all_time_opts:
|
||||
self._showTrace(f"{time_type} 选择失败 ! : 当前未查询到可用时间")
|
||||
return -1
|
||||
best_opt, best_text, actual_diff, free_times = self._findBestTimeOption(
|
||||
all_time_opts, target_time, max_time_diff, prefer_earlier, is_reserve=True
|
||||
)
|
||||
if best_opt is not None:
|
||||
best_opt.click()
|
||||
abs_diff = abs(actual_diff)
|
||||
time_relation = self._formatTimeRelation(abs_diff, actual_diff, time_type)
|
||||
target_time += actual_diff
|
||||
self._showTrace(
|
||||
f"无法选择最近的 {time_type} {self.__minsToTime(target_time)}, "\
|
||||
f"所有可选时间与目标时间相差都超过 {max_time_diff} 分钟"
|
||||
f"选择距离期望 {time_type} 最近的 {best_text}, "
|
||||
f"与期望 {time_type} 相比 {time_relation}"
|
||||
)
|
||||
self._showTrace(f"当前可供预约的 {time_type} 有: {free_times}")
|
||||
return -1
|
||||
except:
|
||||
self._showTrace(f"{time_type} {self.__minsToTime(target_time)} 选择失败 !")
|
||||
return -1
|
||||
return target_time
|
||||
self._showTrace(
|
||||
f"无法选择最近的 {time_type} {self._minsToTime(target_time)}, "
|
||||
f"所有可选时间与目标时间相差都超过 {max_time_diff} 分钟"
|
||||
)
|
||||
self._showTrace(f"当前可供预约的 {time_type} 有: {free_times}")
|
||||
return -1
|
||||
|
||||
|
||||
def __selectSeatTime(
|
||||
@@ -576,40 +530,35 @@ class LibReserve(LibOperator):
|
||||
satisfy_duration: bool = True
|
||||
) -> bool:
|
||||
|
||||
"""Select seat begin and end time."""
|
||||
expect_begin_time = actual_begin_time = begin_time["time"]
|
||||
expect_end_time = actual_end_time = end_time["time"]
|
||||
expect_begin_mins = self.__timeToMins(expect_begin_time)
|
||||
expect_begin_mins = self._timeToMins(expect_begin_time)
|
||||
actual_begin_mins = expect_begin_mins
|
||||
expect_end_mins = self.__timeToMins(expect_end_time)
|
||||
expect_end_mins = self._timeToMins(expect_end_time)
|
||||
|
||||
# select the begin time
|
||||
# Select begin time
|
||||
if self.__selectNearestTime(
|
||||
time_id="startTime", # dont change into begin, this is the element in the page
|
||||
time_id="startTime",
|
||||
time_type="开始时间",
|
||||
target_time=expect_begin_mins,
|
||||
max_time_diff=begin_time["max_diff"],
|
||||
prefer_earlier=begin_time["prefer_early"]
|
||||
) == -1:
|
||||
return False
|
||||
else:
|
||||
actual_begin_time = self.__minsToTime(expect_begin_mins)
|
||||
actual_begin_mins = self.__timeToMins(actual_begin_time)
|
||||
# if 'satisfy_duration' is True.
|
||||
# select the end time based on the begin time
|
||||
# (because it may be changed under the 'max time diff' strategy) and expect duration.
|
||||
actual_begin_time = self._minsToTime(expect_begin_mins)
|
||||
actual_begin_mins = self._timeToMins(actual_begin_time)
|
||||
|
||||
# If 'satisfy_duration' is True, select end time based on actual begin time
|
||||
if satisfy_duration:
|
||||
expect_end_mins = int(actual_begin_mins + expct_duration*60)
|
||||
if expect_end_mins > self.__timeToMins("23:30"):
|
||||
expect_end_mins = self.__timeToMins("23:30")
|
||||
self._showTrace(
|
||||
f"预约持续时间 {expct_duration} 小时, 超过最大预约时间 23:30, 自动调整为 23:30"
|
||||
)
|
||||
expect_end_time = self.__minsToTime(expect_end_mins)
|
||||
expect_end_mins = self.validateAndAdjustEndTime(actual_begin_mins, expct_duration)
|
||||
expect_end_time = self._minsToTime(expect_end_mins)
|
||||
self._showTrace(
|
||||
f"需要满足期望预约持续时间: {expct_duration} 小时, "\
|
||||
f"根据开始时间 {actual_begin_time} 计算结束时间: {self.__minsToTime(expect_end_mins)}"
|
||||
f"需要满足期望预约持续时间: {expct_duration} 小时, "
|
||||
f"根据开始时间 {actual_begin_time} 计算结束时间: {expect_end_time}"
|
||||
)
|
||||
# select the end time
|
||||
|
||||
# Select end time
|
||||
if self.__selectNearestTime(
|
||||
time_id="endTime",
|
||||
time_type="结束时间",
|
||||
@@ -618,8 +567,7 @@ class LibReserve(LibOperator):
|
||||
prefer_earlier=end_time["prefer_early"]
|
||||
) == -1:
|
||||
return False
|
||||
else:
|
||||
actual_end_time = self.__minsToTime(expect_end_mins)
|
||||
actual_end_time = self._minsToTime(expect_end_mins)
|
||||
self._showTrace(
|
||||
f"期望预约时间段: {expect_begin_time} - {expect_end_time}, "
|
||||
f"实际预约时间段: {actual_begin_time} - {actual_end_time}"
|
||||
@@ -627,6 +575,25 @@ class LibReserve(LibOperator):
|
||||
return True
|
||||
|
||||
|
||||
def validateAndAdjustEndTime(
|
||||
self,
|
||||
begin_mins: int,
|
||||
duration: int
|
||||
) -> int:
|
||||
|
||||
"""
|
||||
Validate and adjust reserve end time to library closing time if needed.
|
||||
"""
|
||||
LIBRARY_CLOSE_TIME = self._timeToMins("23:30")
|
||||
expect_end_mins = begin_mins + duration * 60
|
||||
if expect_end_mins > LIBRARY_CLOSE_TIME:
|
||||
expect_end_mins = LIBRARY_CLOSE_TIME
|
||||
self._showTrace(
|
||||
f"预约持续时间 {duration} 小时, 超过最大预约时间 23:30, 自动调整为 23:30"
|
||||
)
|
||||
return expect_end_mins
|
||||
|
||||
|
||||
def reserve(
|
||||
self,
|
||||
username: str,
|
||||
|
||||
Reference in New Issue
Block a user