fix(yunda): 导出面板适配 Element UI 改版

韵达导出面板从 jQuery(.allRight/#submitbutton) 改版为 Element UI,应到/实到导出均卡在全选字段步骤。

- actual/expected 改 Element UI 交互:全选 → 向右转移(el-icon-d-arrow-right) → 导出(el-icon-download) → 等 el-loading-mask → el-message-box 成功提示 → 确定
- 新增 _resolve_export_frame() 探测导出 iframe(实到=myFrame、应到=target1),都未命中时 dump 面板内 iframe 名便于排查
- 外层 layui-layer 弹层、查询、切导出服务下载逻辑不变

验证:韵达应到 49 条 / 实到 141 条下载成功。

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Misaka
2026-07-27 22:50:47 +08:00
parent 5e4889e845
commit 29edcbfdbb

View File

@@ -77,6 +77,35 @@ def _remove_if_exists(path):
pass
def _resolve_export_frame(ws_frame):
"""定位韵达数据导出面板内嵌的 iframe。
韵达改版后导出面板换用 Element UI全选/向右转移/导出按钮)。实到流程的面板
iframe 名为 myFrame已验证应到流程历史上为 target1。这里短超时轮流探测
返回首个出现「全选」按钮的 frame都未命中则 dump 面板内所有 iframe 名便于排查。
"""
for name in ("myFrame", "target1"):
frame = ws_frame.frame_locator(f'iframe[name="{name}"]')
try:
frame.locator("button.el-button", has_text="全选").first.wait_for(
state="visible", timeout=5000
)
print(f" [导出iframe] 命中 iframe[name={name}]")
return frame
except Exception:
continue
try:
names = ws_frame.locator("iframe").evaluate_all(
"els => els.map(e => e.name || '(无name)')"
)
print(
f" [导出iframe] myFrame/target1 均未命中全选;面板 iframe 名: {names}"
)
except Exception as e:
print(f" [导出iframe] dump 失败: {e}")
return ws_frame.frame_locator('iframe[name="myFrame"]')
def yunda_login(page):
"""韵达自动登录:未登录则填充表单并提交,已登录则跳过。"""
print(">> 正在检查韵达登录状态...")
@@ -274,8 +303,11 @@ def yunda_expected_download_impl(page):
ws_frame.locator("#docSum").wait_for(state="visible", timeout=15000)
page.wait_for_timeout(500)
# 导出弹窗双层重试:外层重新打开面板,内层重新提交
# 区分字段漏选(补点全选)与字段列表消失(重新打开面板)。
# 导出弹窗重试:外层重新打开面板(最多 3 次)
# 韵达站点已将导出面板从 jQuery(.allRight/#submitbutton) 改版为 Element UI
# 与实到流程同一导出组件iframe=myFrame
# 全选(button“全选”) → 向右转移(i.el-icon-d-arrow-right) → 导出(i.el-icon-download)
# → 正在导出中(.el-loading-mask) → 成功提示(.el-message-box 导出任务建立成功) → 确定
task_success = False
for major_attempt in range(3):
print(f" >> 正在打开数据导出面板 (尝试 {major_attempt + 1}/3)...")
@@ -285,74 +317,61 @@ def yunda_expected_download_impl(page):
state="visible", timeout=15000
)
export_frame = ws_frame.frame_locator('iframe[name="target1"]')
export_frame = _resolve_export_frame(ws_frame)
try:
# 校验字段列表是否加载完成(以“交接单号”为标志)
export_frame.get_by_text("交接单号").first.wait_for(
state="visible", timeout=3000
)
# 校验 Element UI 字段选择区是否加载完成(以「全选」按钮就绪为标志)
export_frame.locator(
"button.el-button", has_text="全选"
).first.wait_for(state="visible", timeout=8000)
except Exception:
print(" ⚠️ 字段列表未加载,关闭面板后重试...")
print(" ⚠️ 导出面板字段区未加载,关闭面板后重试...")
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(1000)
continue
export_frame.locator(".allRight").click()
print(" -> 全选字段并向右转移...")
export_frame.locator("button.el-button", has_text="全选").first.click()
page.wait_for_timeout(400)
export_frame.locator(
"button.el-button:has(i.el-icon-d-arrow-right)"
).first.click()
page.wait_for_timeout(500)
inner_success = False
needs_reopen = False
print(" -> 正在提交导出任务...")
for attempt in range(4):
export_frame.locator("#submitbutton", has_text="导出数据").click()
confirm_link = export_frame.get_by_role("link", name="确定")
try:
confirm_link.wait_for(state="visible", timeout=6000)
if export_frame.get_by_text("导出任务建立成功").is_visible():
print(" ✅ 导出任务已建立成功。")
confirm_link.click()
inner_success = True
break
elif export_frame.get_by_text(
"请选择格式相应的导出字段"
).is_visible():
confirm_link.click()
page.wait_for_timeout(500)
export_frame.locator(
"button.el-button:has(i.el-icon-download)"
).first.click()
# 区分:字段漏选 还是 字段列表消失
if export_frame.get_by_text("交接单号").first.is_visible():
print(
" ⚠️ 检测到未选择字段(字段列表仍在),重新点击全选..."
)
export_frame.locator(".allRight").click()
page.wait_for_timeout(500)
else:
print(
" ⚠️ 字段列表异常消失,重新打开导出面板..."
)
needs_reopen = True
break # 跳出内层循环,重新打开面板
else:
confirm_link.click()
page.wait_for_timeout(1000)
except Exception:
page.wait_for_timeout(1000)
# 等待「正在导出中」遮罩出现并消失
loading = export_frame.locator(".el-loading-mask").first
try:
loading.wait_for(state="visible", timeout=5000)
loading.wait_for(state="hidden", timeout=60000)
except Exception:
pass
# 等待结果提示并判定
inner_success = False
try:
msg_box = export_frame.locator(".el-message-box.my-alert").first
msg_box.wait_for(state="visible", timeout=30000)
if msg_box.get_by_text("导出任务建立成功").is_visible():
print(" ✅ 导出任务已建立成功。")
inner_success = True
else:
print(" ⚠️ 导出结果提示非成功状态,将重试。")
msg_box.locator("button.el-button", has_text="确定").first.click()
page.wait_for_timeout(500)
except Exception:
print(" ⚠️ 未检测到导出结果提示,将重试。")
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(500)
if inner_success:
task_success = True
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(500)
break # 跳出外层循环,继续后续步骤
elif needs_reopen:
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(1000)
continue # 重新打开面板
else:
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(1000)
continue
break
if not task_success:
raise RuntimeError("多次重试后仍未能建立应到数据离线任务。")
@@ -497,8 +516,10 @@ def yunda_actual_download_impl(page):
).click()
return
# 导出弹窗双层重试:外层重新打开面板,内层重新提交
# 区分字段漏选(补点全选)与字段列表消失(重新打开面板)。
# 导出弹窗重试:外层重新打开面板(最多 3 次)
# 韵达站点已将导出面板从 jQuery(.allRight/#submitbutton) 改版为 Element UI
# 全选(button“全选”) → 向右转移(i.el-icon-d-arrow-right) → 导出(i.el-icon-download)
# → 正在导出中(.el-loading-mask) → 成功提示(.el-message-box 导出任务建立成功) → 确定
print(">> 正在发起导出...")
task_success = False
@@ -512,69 +533,58 @@ def yunda_actual_download_impl(page):
export_frame = ws_frame.frame_locator('iframe[name="myFrame"]')
try:
# 校验字段列表是否加载完成(以“扫描类型”为标志)
export_frame.get_by_text("扫描类型").first.wait_for(
state="visible", timeout=3000
)
# 校验 Element UI 字段选择区是否加载完成(以「全选」按钮就绪为标志)
export_frame.locator(
"button.el-button", has_text="全选"
).first.wait_for(state="visible", timeout=8000)
except Exception:
print(" ⚠️ 字段列表未加载,关闭面板后重试...")
print(" ⚠️ 导出面板字段区未加载,关闭面板后重试...")
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(1000)
continue
export_frame.locator(".allRight").click()
print(" -> 全选字段并向右转移...")
export_frame.locator("button.el-button", has_text="全选").first.click()
page.wait_for_timeout(400)
export_frame.locator(
"button.el-button:has(i.el-icon-d-arrow-right)"
).first.click()
page.wait_for_timeout(500)
inner_success = False
needs_reopen = False
print(" -> 正在提交导出任务...")
for attempt in range(4):
export_frame.locator("#submitbutton", has_text="导出数据").click()
confirm_link = export_frame.get_by_role("link", name="确定")
try:
confirm_link.wait_for(state="visible", timeout=6000)
if export_frame.get_by_text("导出任务建立成功").is_visible():
print(" ✅ 导出任务已建立成功。")
confirm_link.click()
inner_success = True
break
elif export_frame.get_by_text(
"请选择格式相应的导出字段"
).is_visible():
confirm_link.click()
page.wait_for_timeout(500)
export_frame.locator(
"button.el-button:has(i.el-icon-download)"
).first.click()
# 区分:字段漏选 还是 字段列表消失
if export_frame.get_by_text("扫描类型").first.is_visible():
print(
" ⚠️ 检测到未选择字段(字段列表仍在),重新点击全选..."
)
export_frame.locator(".allRight").click()
page.wait_for_timeout(500)
else:
print(" ⚠️ 字段列表异常消失,重新打开导出面板...")
needs_reopen = True
break
else:
confirm_link.click()
page.wait_for_timeout(1000)
except Exception:
page.wait_for_timeout(1000)
# 等待「正在导出中」遮罩出现并消失
loading = export_frame.locator(".el-loading-mask").first
try:
loading.wait_for(state="visible", timeout=5000)
loading.wait_for(state="hidden", timeout=60000)
except Exception:
pass
# 等待结果提示并判定
inner_success = False
try:
msg_box = export_frame.locator(".el-message-box.my-alert").first
msg_box.wait_for(state="visible", timeout=30000)
if msg_box.get_by_text("导出任务建立成功").is_visible():
print(" ✅ 导出任务已建立成功。")
inner_success = True
else:
print(" ⚠️ 导出结果提示非成功状态,将重试。")
msg_box.locator("button.el-button", has_text="确定").first.click()
page.wait_for_timeout(500)
except Exception:
print(" ⚠️ 未检测到导出结果提示,将重试。")
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(500)
if inner_success:
task_success = True
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(500)
break
elif needs_reopen:
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(1000)
continue
else:
ws_frame.locator(".layui-layer-close1").click()
page.wait_for_timeout(1000)
continue
if not task_success:
raise RuntimeError("多次重试后仍未能建立实到数据离线任务。")