feat(yunda): cross-month calendar navigation for date-specific download

韵达两个流程的日期组件不同,分别适配跨月翻月:
- 应到(.layui-laydate 新版):读 .laydate-set-ym 当前年月,点 .laydate-prev-m/.laydate-next-m
  翻月,格子 td[lay-ymd='YYYY-M-D']。
- 实到(#laydate_box 旧版):读 #laydate_y/#laydate_m 输入框值,点 #laydate_MM 内
  .laydate_chprev/.laydate_chnext 翻月,格子 td[y][m][d]。
两处设日期改走 _yunda_pick_laydate_new / _yunda_pick_laydate_old,同月(offset 当月)
行为不变,仅跨月时翻月。年*12+月 比较天然支持跨年。

实到 #startDate/#endDate 保持普通 click(force=True 会在导航后 laydate 绑定完成前
抢先点击导致面板打不开);新增 #laydate_box:visible 就绪等待。

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Misaka
2026-07-29 20:26:45 +08:00
parent 21662d3944
commit 047036f46b

View File

@@ -77,6 +77,64 @@ def _remove_if_exists(path):
pass pass
def _yunda_pick_laydate_new(ws_frame, page, date_ymd):
"""应到(新版 laydate .layui-laydate在已打开的面板上选中指定日期含跨月翻月
目标格子 td[lay-ymd='YYYY-M-D'](非补零)不在当前月视窗时,读 .laydate-set-ym 的
当前年月形如「2026年7月」按差值点 .laydate-prev-m / .laydate-next-m 翻到目标月,
再点格子;同月则直接点。调用前提:#startTime/#endTime 已点开,.layui-laydate:visible 就绪。
"""
cal = ws_frame.locator(".layui-laydate:visible").first
cell = cal.locator(f"td[lay-ymd='{date_ymd}']").first
if not cell.is_visible():
ty, tm = (int(x) for x in date_ymd.split("-")[:2])
print(f" 目标日期 {date_ymd} 不在当前月视窗,正在翻月导航 ...")
for _ in range(24):
nums = re.findall(r"\d+", cal.locator(".laydate-set-ym").first.inner_text())
if len(nums) >= 2:
cur_y, cur_m = int(nums[0]), int(nums[1])
if cur_y == ty and cur_m == tm:
break
cur = cur_y * 12 + (cur_m - 1)
btn = (
".laydate-prev-m"
if (ty * 12 + (tm - 1)) < cur
else ".laydate-next-m"
)
cal.locator(btn).first.click()
page.wait_for_timeout(300)
cell = cal.locator(f"td[lay-ymd='{date_ymd}']").first
cell.click()
def _yunda_pick_laydate_old(ws_frame, page, date_ymd):
"""实到(旧版 laydate #laydate_box在已打开的面板上选中指定日期含跨月翻月
目标格子 td[y][m][d](非补零)不在当前月视窗时,读 #laydate_y/#laydate_m 输入框值
形如「2026年」「07月」得当前年月按差值点 #laydate_MM 内 .laydate_chprev /
.laydate_chnext 翻到目标月,再点格子;同月则直接点。调用前提:#startDate/#endDate
已点开force=True#laydate_box:visible 就绪。
"""
box = ws_frame.locator("#laydate_box:visible").first
ty, tm, td = (int(x) for x in date_ymd.split("-")[:3])
cell = box.locator(f"td[y='{ty}'][m='{tm}'][d='{td}']").first
if not cell.is_visible():
print(f" 目标日期 {date_ymd} 不在当前月视窗,正在翻月导航 ...")
for _ in range(24):
yv = box.locator("#laydate_y").first.evaluate("e=>e.value")
mv = box.locator("#laydate_m").first.evaluate("e=>e.value")
cur_y = int(re.search(r"\d+", yv).group())
cur_m = int(re.search(r"\d+", mv).group())
if cur_y == ty and cur_m == tm:
break
cur = cur_y * 12 + (cur_m - 1)
btn = ".laydate_chprev" if (ty * 12 + (tm - 1)) < cur else ".laydate_chnext"
box.locator(f"#laydate_MM {btn}").first.click()
page.wait_for_timeout(300)
cell = box.locator(f"td[y='{ty}'][m='{tm}'][d='{td}']").first
cell.click()
def _resolve_export_frame(ws_frame): def _resolve_export_frame(ws_frame):
"""定位韵达数据导出面板内嵌的 iframe。 """定位韵达数据导出面板内嵌的 iframe。
@@ -228,7 +286,7 @@ def yunda_expected_download_impl(page, force=False, date=None):
calendar1 = ws_frame.locator(".layui-laydate:visible").first calendar1 = ws_frame.locator(".layui-laydate:visible").first
calendar1.wait_for(state="visible", timeout=5000) calendar1.wait_for(state="visible", timeout=5000)
calendar1.locator(f"td[lay-ymd='{start_date_ymd}']").click() _yunda_pick_laydate_new(ws_frame, page, start_date_ymd)
calendar1.locator(".laydate-btns-confirm").click() calendar1.locator(".laydate-btns-confirm").click()
page.wait_for_timeout(400) page.wait_for_timeout(400)
@@ -238,7 +296,7 @@ def yunda_expected_download_impl(page, force=False, date=None):
calendar2 = ws_frame.locator(".layui-laydate:visible").first calendar2 = ws_frame.locator(".layui-laydate:visible").first
calendar2.wait_for(state="visible", timeout=5000) calendar2.wait_for(state="visible", timeout=5000)
calendar2.locator(f"td[lay-ymd='{today_ymd}']").click() _yunda_pick_laydate_new(ws_frame, page, today_ymd)
calendar2.locator(".laydate-btns-confirm").click() calendar2.locator(".laydate-btns-confirm").click()
page.wait_for_timeout(500) page.wait_for_timeout(500)
@@ -472,8 +530,8 @@ def yunda_actual_download_impl(page, date=None):
target = datetime.strptime(date, "%Y-%m-%d") target = datetime.strptime(date, "%Y-%m-%d")
else: else:
target = today - timedelta(days=offset) target = today - timedelta(days=offset)
start_date = target # 单日范围起止同日 # 旧版 laydate 的日期格子 td[y][m][d] 用非补零整数值;单日范围起止同日
today = target # 让下方"截止时间"选择器也指向 target target_ymd = f"{target.year}-{target.month}-{target.day}"
src = f"指定 {date}" if date else f"偏移 {offset}0=今天" src = f"指定 {date}" if date else f"偏移 {offset}0=今天"
print( print(
f">> 设置实到查询日期: [{target.year}-{target.month}-{target.day}]{src}" f">> 设置实到查询日期: [{target.year}-{target.month}-{target.day}]{src}"
@@ -482,19 +540,19 @@ def yunda_actual_download_impl(page, date=None):
print(" >> 正在设定起始时间...") print(" >> 正在设定起始时间...")
ws_frame.locator("#startDate").click() ws_frame.locator("#startDate").click()
page.wait_for_timeout(400) page.wait_for_timeout(400)
box1 = ws_frame.locator("#laydate_box:visible").first ws_frame.locator("#laydate_box:visible").first.wait_for(
box1.locator( state="visible", timeout=5000
f"td[y='{start_date.year}'][m='{start_date.month}'][d='{start_date.day}']" )
).click() _yunda_pick_laydate_old(ws_frame, page, target_ymd)
page.wait_for_timeout(400) page.wait_for_timeout(400)
print(" >> 正在设定截止时间...") print(" >> 正在设定截止时间...")
ws_frame.locator("#endDate").click() ws_frame.locator("#endDate").click()
page.wait_for_timeout(400) page.wait_for_timeout(400)
box2 = ws_frame.locator("#laydate_box:visible").first ws_frame.locator("#laydate_box:visible").first.wait_for(
box2.locator( state="visible", timeout=5000
f"td[y='{today.year}'][m='{today.month}'][d='{today.day}']" )
).click() _yunda_pick_laydate_old(ws_frame, page, target_ymd)
page.wait_for_timeout(500) page.wait_for_timeout(500)
print(" >> 正在变更扫描类型为【到件】...") print(" >> 正在变更扫描类型为【到件】...")