串起截图和上传

This commit is contained in:
2026-02-10 09:20:12 +08:00
parent ac4d41c70b
commit 2441031bb6
26 changed files with 18384 additions and 18432 deletions

View File

@@ -73,22 +73,32 @@ class LoginPage:
pass
# 点击登录按钮
login_btn = self.wait.until(
EC.element_to_be_clickable((AppiumBy.ID, ids.LOGIN_BTN))
)
login_btn.click()
self.logger.info("已点击登录按钮")
max_retries = 3
retry_count = 0
# 等待登录完成
time.sleep(3)
while retry_count < max_retries:
login_btn = self.wait.until(
EC.element_to_be_clickable((AppiumBy.ID, ids.LOGIN_BTN))
)
login_btn.click()
self.logger.info(f"已点击登录按钮 (尝试 {retry_count + 1}/{max_retries})")
# 等待登录完成
time.sleep(3)
# 检查是否登录成功
if self.is_login_successful():
self.logger.info("登录成功")
return True
else:
self.logger.warning("登录后未检测到主页面元素,准备重试")
retry_count += 1
if retry_count < max_retries:
self.logger.info(f"等待2秒后重新尝试登录...")
time.sleep(2)
# 检查是否登录成功
if self.is_login_successful():
self.logger.info("登录成功")
return True
else:
self.logger.warning("登录后未检测到主页面元素")
return False
self.logger.error(f"登录失败,已尝试 {max_retries}")
return False
except Exception as e:
self.logger.error(f"登录过程中出错: {str(e)}")

View File

@@ -178,7 +178,7 @@ class MoreDownloadPage:
"""滑动年份选择器的滚轮"""
try:
# 获取年份选择器滚轮元素
year_wheel = self.driver.find_element(AppiumBy.ID, "com.bjjw.cjgc:id/wheelView2")
year_wheel = self.driver.find_element(AppiumBy.ID, "com.bjjw.cjgc:id/wheelView1")
# 获取滚轮的位置和尺寸
location = year_wheel.location
@@ -191,7 +191,7 @@ class MoreDownloadPage:
# 计算滑动距离 - 滚轮高度的1/5
swipe_distance = size['height'] // 5
for i in range(3):
for i in range(1):
# 执行滑动操作 - 从中心向上滑动1/5高度
self.driver.swipe(center_x, center_y - swipe_distance, center_x, center_y, 500)
@@ -369,7 +369,7 @@ class MoreDownloadPage:
continue
return False
def wait_for_loading_dialog(self, timeout=900, download_type="unknown", retry_count=0):
def wait_for_loading_dialog(self, timeout=1200, download_type="unknown", retry_count=0):
"""
检查加载弹窗的出现和消失支持最多1次重试总共执行2次
"""

View File

@@ -19,7 +19,8 @@ import globals.global_variable as global_variable # 导入全局变量模块
class ScreenshotPage:
def __init__(self, driver, wait, device_id=None):
self.driver = driver
self.wait = wait
# self.wait = wait
self.wait = WebDriverWait(self.driver, 0.5)
self.device_id = device_id
self.logger = logging.getLogger(__name__)
self.all_items = set()
@@ -233,7 +234,7 @@ class ScreenshotPage:
def check_apply_btn(self):
"""检查是否有平差处理按钮"""
try:
apply_btn = WebDriverWait(self.driver, 5).until(
apply_btn = WebDriverWait(self.driver, 1).until(
EC.element_to_be_clickable((AppiumBy.ID, "com.bjjw.cjgc:id/point_measure_btn"))
)
if apply_btn.is_displayed():
@@ -548,117 +549,6 @@ class ScreenshotPage:
self.logger.error(f"截图时发生错误: {str(e)}")
return False
def wait_for_measurement_end(self, timeout=900):
"""
等待按钮变成"测量结束"最多15分钟包含驱动重新初始化机制
Args:
timeout: 超时时间默认900秒15分钟
Returns:
bool: 是否成功等到测量结束按钮
"""
try:
# 更新WebDriverWait等待时间为900秒
self.wait = WebDriverWait(self.driver, 900)
self.logger.info(f"设备等待测量结束按钮出现,最多等待 {timeout}")
start_time = time.time()
reinit_attempts = 0
max_reinit_attempts = 3 # 最大重新初始化次数
while time.time() - start_time < timeout:
try:
# 使用XPath查找文本为"测量结束"的按钮
measurement_end_button = self.driver.find_element(
AppiumBy.XPATH,
"//android.widget.Button[@text='测量结束']"
)
if measurement_end_button.is_displayed() and measurement_end_button.is_enabled():
self.logger.info(f"设备检测到测量结束按钮")
return True
except NoSuchElementException:
# 按钮未找到,继续等待
pass
except Exception as e:
error_msg = str(e)
self.logger.warning(f"设备查找测量结束按钮时出现异常: {error_msg}")
# 检测是否是UiAutomator2服务崩溃
if 'UiAutomator2 server' in error_msg and 'instrumentation process is not running' in error_msg and reinit_attempts < max_reinit_attempts:
reinit_attempts += 1
self.logger.info(f"设备检测到UiAutomator2服务崩溃尝试第 {reinit_attempts} 次重新初始化驱动")
# 尝试重新初始化驱动
if self._reinit_driver():
self.logger.info(f"设备驱动重新初始化成功")
else:
self.logger.error(f"设备驱动重新初始化失败")
# 继续尝试,而不是立即失败
# 等待一段时间后再次检查
time.sleep(3)
# 每30秒输出一次等待状态
if int(time.time() - start_time) % 30 == 0:
elapsed = int(time.time() - start_time)
self.logger.info(f"设备 {self.device_id} 已等待 {elapsed} 秒,仍在等待测量结束...")
self.logger.error(f"设备 {self.device_id} 等待测量结束按钮超时")
return False
except Exception as e:
self.logger.error(f"设备 {self.device_id} 等待测量结束时发生错误: {str(e)}")
return False
def _reinit_driver(self):
"""
重新初始化Appium驱动
Returns:
bool: 是否成功重新初始化
"""
try:
# 首先尝试关闭现有的驱动
if hasattr(self, 'driver') and self.driver:
try:
self.driver.quit()
except:
self.logger.warning("关闭现有驱动时出现异常")
# 导入必要的模块
from appium import webdriver
from appium.options.android import UiAutomator2Options
# 重新创建驱动配置
options = UiAutomator2Options()
options.platform_name = "Android"
options.device_name = self.device_id
options.app_package = "com.bjjw.cjgc"
options.app_activity = ".activity.LoginActivity"
options.automation_name = "UiAutomator2"
options.no_reset = True
options.auto_grant_permissions = True
options.new_command_timeout = 300
options.udid = self.device_id
# 重新连接驱动
self.logger.info(f"正在重新初始化设备 {self.device_id} 的驱动...")
self.driver = webdriver.Remote("http://localhost:4723", options=options)
# 重新初始化等待对象
from selenium.webdriver.support.ui import WebDriverWait
self.wait = WebDriverWait(self.driver, 1)
self.logger.info(f"设备 {self.device_id} 驱动重新初始化完成")
return True
except Exception as e:
self.logger.error(f"设备 {self.device_id} 驱动重新初始化失败: {str(e)}")
return False
def handle_confirmation_dialog(self, device_id, timeout=2):
"""
处理确认弹窗,点击""按钮
@@ -672,31 +562,68 @@ class ScreenshotPage:
"""
# 等待弹窗出现最多等待2秒
try:
dialog_message = WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located((AppiumBy.XPATH, "//android.widget.TextView[@text='是否退出测量界面?']"))
)
# dialog_message = WebDriverWait(self.driver, timeout).until(
# EC.presence_of_element_located((AppiumBy.XPATH, "//android.widget.TextView[@text='是否退出测量界面?']"))
# )
self.logger.info(f"设备 {device_id} 检测到确认弹窗")
# self.logger.info(f"设备 {device_id} 检测到确认弹窗")
# 查找并点击"是"按钮
confirm_button = self.driver.find_element(
AppiumBy.XPATH,
"//android.widget.Button[@text='' and @resource-id='android:id/button1']"
)
# # 查找并点击"是"按钮
# confirm_button = self.driver.find_element(
# AppiumBy.XPATH,
# "//android.widget.Button[@text='是' and @resource-id='android:id/button1']"
# )
if confirm_button.is_displayed() and confirm_button.is_enabled():
self.logger.info(f"设备 {device_id} 点击确认弹窗的''按钮")
confirm_button.click()
time.sleep(0.5)
return True
else:
self.logger.error(f"设备 {device_id} ''按钮不可点击")
return False
# if confirm_button.is_displayed() and confirm_button.is_enabled():
# self.logger.info(f"设备 {device_id} 点击确认弹窗的'是'按钮")
# confirm_button.click()
# time.sleep(0.5)
# return True
# else:
# self.logger.error(f"设备 {device_id} '是'按钮不可点击")
# return False
except TimeoutException:
# 超时未找到弹窗,认为没有弹窗,返回成功
self.logger.info(f"设备 {device_id} 等待 {timeout} 秒未发现确认弹窗,可能没有弹窗,返回成功")
return True
# except TimeoutException:
# # 超时未找到弹窗,认为没有弹窗,返回成功
# self.logger.info(f"设备 {device_id} 等待 {timeout} 秒未发现确认弹窗,可能没有弹窗,返回成功")
# return True
max_attempts = 2
for attempt in range(max_attempts):
try:
dialog_message = WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located((AppiumBy.XPATH, "//android.widget.TextView[@text='是否退出测量界面?']"))
)
self.logger.info(f"设备 {device_id} 检测到确认弹窗 (第 {attempt + 1} 次)")
# 查找并点击"是"按钮
confirm_button = self.driver.find_element(
AppiumBy.XPATH,
"//android.widget.Button[@text='' and @resource-id='android:id/button1']"
)
if confirm_button.is_displayed() and confirm_button.is_enabled():
self.logger.info(f"设备 {device_id} 点击确认弹窗的''按钮 (第 {attempt + 1} 次)")
confirm_button.click()
time.sleep(0.5)
# 如果是第一次尝试,继续检查是否还有弹窗
if attempt < max_attempts - 1:
self.logger.info(f"设备 {device_id} 等待 1 秒后检查是否还有弹窗")
time.sleep(0.5)
continue
return True
else:
self.logger.error(f"设备 {device_id} ''按钮不可点击")
return False
except TimeoutException:
# 超时未找到弹窗,认为没有弹窗,返回成功
self.logger.info(f"设备 {device_id} 等待 {timeout} 秒未发现确认弹窗,可能没有弹窗,返回成功")
return True
except Exception as e:
self.logger.error(f"设备 {device_id} 处理确认弹窗时出错: {str(e)}")
return False
def click_back_button(self, device_id):
"""点击手机系统返回按钮"""
@@ -765,7 +692,7 @@ class ScreenshotPage:
if confirm_button and confirm_button.is_displayed() and confirm_button.is_enabled():
self.logger.info(f"设备 {device_id} 点击确认弹窗的''按钮")
confirm_button.click()
time.sleep(1)
time.sleep(0.5)
# 验证弹窗是否消失
try:
@@ -785,7 +712,7 @@ class ScreenshotPage:
except Exception as e:
self.logger.warning(f"设备 {device_id} 查找确认弹窗时出现异常: {str(e)}")
time.sleep(1)
time.sleep(0.5)
self.logger.error(f"设备 {device_id} 等待返回确认弹窗超时")
return False
@@ -884,7 +811,7 @@ class ScreenshotPage:
# time.sleep(2)
self.logger.info(f"已点击平差处理按钮,检查是否在测量页面")
# 检测是否存在测量列表(修正逻辑)
# 检测是否存在测量列表
has_measurement_list = self.check_measurement_list(device_id)
if not has_measurement_list:
self.logger.info(f"设备 {device_id} 存在测量列表,重新执行平差流程")
@@ -943,7 +870,7 @@ class ScreenshotPage:
# 3. 验证是否成功返回到上一页面
time.sleep(1) # 等待页面跳转完成
time.sleep(0.5) # 等待页面跳转完成
# 可以添加页面验证逻辑,比如检查是否返回到预期的页面
# 这里可以根据实际应用添加特定的页面元素验证
@@ -967,7 +894,7 @@ class ScreenshotPage:
"""
try:
self.logger.info(f"设备 {device_id} 开始执行测量结束后的操作流程")
time.sleep(5)
time.sleep(0.5)
# 1. 下滑列表到最底端
if not self.scroll_list_to_bottom(device_id):
@@ -1071,7 +998,7 @@ class ScreenshotPage:
if self.click_last_spinner(device_id):
return True
self.logger.warning(f"设备 {device_id}{attempt + 1}次点击失败,准备重试")
time.sleep(1) # 重试前等待
time.sleep(0.5) # 重试前等待
except Exception as e:
self.logger.error(f"设备 {device_id}{attempt + 1}次尝试失败: {str(e)}")
@@ -1133,7 +1060,8 @@ class ScreenshotPage:
new_driver, new_wait = reconnect_driver(actual_device_id, self.driver)
if new_driver:
self.driver = new_driver
self.wait = new_wait
# self.wait = new_wait
self.wait = WebDriverWait(self.driver, 2)
self.logger.info(f"设备 {actual_device_id} 驱动重连成功")
else:
self.logger.error(f"设备 {actual_device_id} 驱动重连失败")
@@ -1189,8 +1117,8 @@ class ScreenshotPage:
retry_count += 1
if retry_count < max_retries:
self.logger.info(f"设备 {device_id} 将在1秒后进行第{retry_count+1}次重试")
time.sleep(1) # 等待1秒后重试
self.logger.info(f"设备 {device_id} 将在0.5秒后进行第{retry_count+1}次重试")
time.sleep(0.5) # 等待0.5秒后重试
self.logger.error(f"设备 {device_id} 经过{max_retries}次重试后仍无法展开下拉菜单")
return False
@@ -1222,7 +1150,7 @@ class ScreenshotPage:
'percent': 0.5
})
time.sleep(1)
time.sleep(0.5)
self.logger.info(f"设备 {device_id} 额外下滑完成")
return True
@@ -1343,8 +1271,10 @@ class ScreenshotPage:
# 检查GLOBAL_UPLOAD_BREAKPOINT_DICT是否为空如果为空则初始化一些测试数据
if not global_variable.get_upload_breakpoint_dict():
self.logger.warning("global_variable.GLOBAL_UPLOAD_BREAKPOINT_DICT为空正在初始化测试数据")
global_variable.set_upload_breakpoint_dict({'CDWZQ-2标-龙骨湾右线大桥-0-7号墩-平原': 'L156372', 'CDWZQ-2标-蓝家湾特大 桥-31-31-平原': 'L159206'})
self.logger.warning("上传列表为空,无法执行平差操作")
return False
# global_variable.set_upload_breakpoint_dict({'CDWZQ-2标-龙骨湾右线大桥-0-7号墩-平原': 'L156372', 'CDWZQ-2标-蓝家湾特大 桥-31-31-平原': 'L159206'})
breakpoint_names = list(global_variable.get_upload_breakpoint_dict().keys())
processed_breakpoints = []
@@ -1450,23 +1380,4 @@ class ScreenshotPage:
self.logger.info(f"等待10秒后重试...")
time.sleep(10)
return False
def run_automation_test(self):
# 滑动列表到底部
if not self.scroll_list_to_bottom(self.device_id):
self.logger.error(f"设备 {self.device_id} 下滑列表到底部失败")
return False
# 2. 点击最后一个spinner
if not self.click_last_spinner_with_retry(self.device_id):
self.logger.error(f"设备 {self.device_id} 点击最后一个spinner失败")
return False
# 3. 再下滑一次
if not self.scroll_down_once(self.device_id):
self.logger.warning(f"设备 {self.device_id} 再次下滑失败,但继续执行")
# 4. 点击平差处理按钮
if not self.click_adjustment_button(self.device_id):
self.logger.error(f"设备 {self.device_id} 点击平差处理按钮失败")
return False
return False

View File

@@ -40,7 +40,7 @@ class UploadConfigPage:
except Exception as e:
self.logger.error(f"获取当前activity时出错: {str(e)}")
# 尝试返回到主页面(如果不在主页面)
# 尝试返回到主页面(如果不在主页面)保存上传
self.logger.info("尝试返回到主页面...")
max_back_presses = 5 # 最多按返回键次数
back_press_count = 0
@@ -932,6 +932,19 @@ class UploadConfigPage:
condition_button.click()
self.logger.info(f"成功点击{work_type_name}工况选择按钮")
# 检查是否有ListView如果没有就再次点击
try:
# 尝试查找ListView
self.wait.until(
EC.presence_of_element_located((AppiumBy.CLASS_NAME, "android.widget.ListView"))
)
self.logger.info(f"找到{work_type_name}工况选择的ListView")
except TimeoutException:
# 没有找到ListView再次点击按钮
self.logger.warning(f"未找到{work_type_name}工况选择的ListView再次点击按钮")
condition_button.click()
self.logger.info(f"再次成功点击{work_type_name}工况选择按钮")
# 选择主要的工况选项
if self._select_condition_option(workinfo_name):
self.logger.info(f"成功为{work_type_name}选择主要工况: {workinfo_name}")
@@ -1120,10 +1133,24 @@ class UploadConfigPage:
"com.bjjw.cjgc:id/point_workinfo_sp"
)
# 验证按钮是否可见和可用
if workinfo_button.is_displayed() and workinfo_button.is_enabled():
workinfo_button.click()
self.logger.info(f"已点击测点 {point_id} 的工况选择按钮")
self.logger.info(f"已点击测点 {point_id}次要工况选择按钮")
# 检查是否有ListView如果没有就再次点击
try:
# 尝试查找ListView
self.wait.until(
EC.presence_of_element_located((AppiumBy.CLASS_NAME, "android.widget.ListView"))
)
self.logger.info(f"找到{point_id}次要工况选择的ListView")
except TimeoutException:
# 没有找到ListView再次点击按钮
self.logger.warning(f"未找到{point_id}次要工况选择的ListView再次点击按钮")
workinfo_button.click()
self.logger.info(f"再次成功点击{point_id}次要工况选择按钮")
# 选择对应的工况选项
if self._select_minor_conditions_option(workinfoname, work_type):
@@ -1370,33 +1397,6 @@ class UploadConfigPage:
return points
def _set_single_point_work_condition(self, point_data: Dict, workinfo_name: str, work_type: str) -> bool:
"""为单个测点设置工况信息"""
try:
point_name = point_data.get('point_name')
self.logger.info(f"开始为测点 {point_name} 设置工况: {workinfo_name}")
# 使用保存的元素引用点击工况选择按钮
workinfo_element = point_data.get('workinfo_element')
if workinfo_element:
workinfo_element.click()
time.sleep(1) # 等待选项弹出
# 选择指定的工况
if self._select_condition_option(workinfo_name):
self.logger.info(f"成功为测点 {point_name} 设置工况: {workinfo_name}")
return True
else:
self.logger.warning(f"为测点 {point_name} 选择工况选项失败")
return False
else:
self.logger.warning(f"未找到测点 {point_name} 的工况选择按钮")
return False
except Exception as e:
self.logger.error(f"为测点 {point_name} 设置工况时出错: {str(e)}")
return False
def _select_condition_option(self, condition_name: str) -> bool:
"""选择具体的工况选项
@@ -1434,18 +1434,18 @@ class UploadConfigPage:
self.logger.debug("未找到列表项形式的工况选项")
# 方法3: 尝试点击屏幕特定位置(备选方案)
try:
# 获取屏幕尺寸
window_size = self.driver.get_window_size()
x = window_size['width'] // 2
y = window_size['height'] // 2
# try:
# # 获取屏幕尺寸
# window_size = self.driver.get_window_size()
# x = window_size['width'] // 2
# y = window_size['height'] // 2
# 点击屏幕中央(假设选项在中间)
self.driver.tap([(x, y)])
self.logger.info("通过点击屏幕中央选择工况")
return True
except Exception as e:
self.logger.debug(f"点击屏幕中央失败: {str(e)}")
# # 点击屏幕中央(假设选项在中间)
# self.driver.tap([(x, y)])
# self.logger.info("通过点击屏幕中央选择工况")
# return True
# except Exception as e:
# self.logger.debug(f"点击屏幕中央失败: {str(e)}")
self.logger.error(f"所有方法都无法选择工况选项: {condition_name}")
return False
@@ -1606,7 +1606,7 @@ class UploadConfigPage:
self.logger.info("开始等待上传完成")
# 等待弹窗显示
upload_list = WebDriverWait(self.driver, 10).until(
upload_list = WebDriverWait(self.driver, 2).until(
EC.presence_of_element_located((AppiumBy.ID, "android:id/customPanel"))
)
#等待弹窗消失
@@ -1862,13 +1862,13 @@ class UploadConfigPage:
return False
# 表达填写完成,点击"保存上传"并处理弹窗
if not self.click_save_upload_and_handle_dialogs():
self.logger.error("点击保存上传并处理弹窗失败")
return False
# # 表达填写完成,点击"保存上传"并处理弹窗
# if not self.click_save_upload_and_handle_dialogs():
# self.logger.error("点击保存上传并处理弹窗失败")
# return False
# # 暂不上传,使用返回按钮替代。
# self.driver.back()
# 暂不上传,使用返回按钮替代。
self.driver.back()
# 等待上传查看loading弹窗。没有就下一个