From e2ae3acd68929eba434ba09fb2f7cc06c3091c3b Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Wed, 29 Jul 2026 12:49:44 +0800 Subject: [PATCH] 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 --- inbound_verify/sites/zto.py | 56 ++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/inbound_verify/sites/zto.py b/inbound_verify/sites/zto.py index 3d89b0f..42d3922 100644 --- a/inbound_verify/sites/zto.py +++ b/inbound_verify/sites/zto.py @@ -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): """中通菜单导航""" print(f">> 正在导航: {' -> '.join(menu_path)}") @@ -158,15 +174,19 @@ def zto_expected_download_impl(page, force=False): target_time = today_time - offset * 86400000 target_cell = ewb_frame.locator(f"td div.day[time='{target_time}']").first - if target_cell.is_visible(): - target_cell.click() - page.wait_for_timeout(300) - target_cell.click() - else: - print(" ⚠️ 偏移日期不在当前日历视窗内,自动降级为查询当天。") - today_cell.click() - page.wait_for_timeout(300) - today_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) + _dom_click(target_cell) else: today_cell.click() page.wait_for_timeout(300) @@ -404,14 +424,16 @@ def zto_actual_download_impl(page): # 日期格子用 _dom_click 直接派发事件:Playwright 的 .click() 会先 hover 格子, # 触发“范围长度”提示气泡(.date-range-length-tip)盖住格子,导致点击被判遮挡而超时。 - if target_cell.is_visible(): - _dom_click(target_cell) - page.wait_for_timeout(300) - _dom_click(target_cell) - else: - _dom_click(today_cell) - page.wait_for_timeout(300) - _dom_click(today_cell) + # 偏移日期跨月时目标格子不在当前双月视窗 → 向前翻月把它带进视窗,不再降级为当天。 + 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) + page.wait_for_timeout(300) + _dom_click(target_cell) else: _dom_click(today_cell) page.wait_for_timeout(300)