feat(zto): cross-month calendar navigation instead of fallback to today

When the offset target date falls outside the current two-month view, flip .prev months (1 month/step) until the target day cell enters month1 view, instead of silently falling back to today. JS-dispatched clicks avoid the .date-range-length-tip hover interception.

Also switch the expected (#beginDate) day-cell click to _dom_click (matching actual #daterange): the range-length tooltip intercepts the second click on non-today cells during single-day range selection, causing timeouts.

Verified end-to-end: offset=45 (-> 2026-06-14, cross-month) expected task succeeded and downloaded 6-14 data without fallback.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-07-29 12:49:44 +08:00
parent f710622a3d
commit e2ae3acd68

View File

@@ -93,6 +93,22 @@ def _dom_click(locator):
) )
def _zto_flip_to_target_month(frame_locator, page, target_time, max_flips=12):
"""中通日历(jQuery-Date-Range-Picker 双月视图)跨月导航:目标日期不在当前视窗时,
循环点 .prev 把目标月翻进 month1 视窗。offset 恒指向过去,故只往前翻;步长 1 月/次。
用 JS 派发点击(.evaluate("el=>el.click()"))避开 .date-range-length-tip 等 hover 遮挡。
返回 True 若目标格子最终可见。"""
sel = f"td div.day[time='{target_time}']"
for _ in range(max_flips):
if frame_locator.locator(sel).first.is_visible():
return True
frame_locator.locator(".date-picker-wrapper .prev").first.evaluate(
"el => el.click()"
)
page.wait_for_timeout(450)
return frame_locator.locator(sel).first.is_visible()
def zto_smart_menu_click(page, menu_path): def zto_smart_menu_click(page, menu_path):
"""中通菜单导航""" """中通菜单导航"""
print(f">> 正在导航: {' -> '.join(menu_path)}") print(f">> 正在导航: {' -> '.join(menu_path)}")
@@ -158,15 +174,19 @@ def zto_expected_download_impl(page, force=False):
target_time = today_time - offset * 86400000 target_time = today_time - offset * 86400000
target_cell = ewb_frame.locator(f"td div.day[time='{target_time}']").first target_cell = ewb_frame.locator(f"td div.day[time='{target_time}']").first
if target_cell.is_visible(): # 偏移日期跨月时目标格子不在当前双月视窗 → 向前翻月把它带进视窗,不再降级为当天
target_cell.click() if not target_cell.is_visible():
print(" 偏移日期跨月,正在向前翻月导航到目标 ...")
if not _zto_flip_to_target_month(ewb_frame, page, target_time):
raise RuntimeError(
f"翻月后仍无法定位目标日期格子(time={target_time})"
)
# 日期格子用 _dom_click 直接派发事件(同实到):.click() 会先 hover 格子,触发
# “范围长度”提示气泡(.date-range-length-tip)盖住格子导致点击被遮挡超时,
# 跨月选中非今日格子时尤为明显。
_dom_click(target_cell)
page.wait_for_timeout(300) page.wait_for_timeout(300)
target_cell.click() _dom_click(target_cell)
else:
print(" ⚠️ 偏移日期不在当前日历视窗内,自动降级为查询当天。")
today_cell.click()
page.wait_for_timeout(300)
today_cell.click()
else: else:
today_cell.click() today_cell.click()
page.wait_for_timeout(300) page.wait_for_timeout(300)
@@ -404,7 +424,13 @@ def zto_actual_download_impl(page):
# 日期格子用 _dom_click 直接派发事件Playwright 的 .click() 会先 hover 格子, # 日期格子用 _dom_click 直接派发事件Playwright 的 .click() 会先 hover 格子,
# 触发“范围长度”提示气泡(.date-range-length-tip)盖住格子,导致点击被判遮挡而超时。 # 触发“范围长度”提示气泡(.date-range-length-tip)盖住格子,导致点击被判遮挡而超时。
if target_cell.is_visible(): # 偏移日期跨月时目标格子不在当前双月视窗 → 向前翻月把它带进视窗,不再降级为当天。
if not target_cell.is_visible():
print(" 偏移日期跨月,正在向前翻月导航到目标 ...")
if not _zto_flip_to_target_month(arr_frame, page, target_time):
raise RuntimeError(
f"翻月后仍无法定位目标日期格子(time={target_time})"
)
_dom_click(target_cell) _dom_click(target_cell)
page.wait_for_timeout(300) page.wait_for_timeout(300)
_dom_click(target_cell) _dom_click(target_cell)
@@ -412,10 +438,6 @@ def zto_actual_download_impl(page):
_dom_click(today_cell) _dom_click(today_cell)
page.wait_for_timeout(300) page.wait_for_timeout(300)
_dom_click(today_cell) _dom_click(today_cell)
else:
_dom_click(today_cell)
page.wait_for_timeout(300)
_dom_click(today_cell)
page.wait_for_timeout(500) page.wait_for_timeout(500)