first commit
This commit is contained in:
BIN
page_objects/__pycache__/download_tabbar_page.cpython-312.pyc
Normal file
BIN
page_objects/__pycache__/download_tabbar_page.cpython-312.pyc
Normal file
Binary file not shown.
BIN
page_objects/__pycache__/login_page.cpython-312.pyc
Normal file
BIN
page_objects/__pycache__/login_page.cpython-312.pyc
Normal file
Binary file not shown.
BIN
page_objects/__pycache__/measure_tabbar_page.cpython-312.pyc
Normal file
BIN
page_objects/__pycache__/measure_tabbar_page.cpython-312.pyc
Normal file
Binary file not shown.
BIN
page_objects/__pycache__/more_download_page.cpython-312.pyc
Normal file
BIN
page_objects/__pycache__/more_download_page.cpython-312.pyc
Normal file
Binary file not shown.
BIN
page_objects/__pycache__/screenshot_page.cpython-312.pyc
Normal file
BIN
page_objects/__pycache__/screenshot_page.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
page_objects/__pycache__/upload_config_page.cpython-312.pyc
Normal file
BIN
page_objects/__pycache__/upload_config_page.cpython-312.pyc
Normal file
Binary file not shown.
46
page_objects/call_xie.py
Normal file
46
page_objects/call_xie.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import socket
|
||||
|
||||
def send_tcp_command(command: str, host: str = '127.0.0.1', port: int = 8888, encoding: str = 'utf-8') -> bool:
|
||||
"""
|
||||
向指定TCP端口发送指令
|
||||
|
||||
参数:
|
||||
command: 要发送的指令字符串
|
||||
host: 目标主机地址(默认127.0.0.1)
|
||||
port: 目标端口(默认8888)
|
||||
encoding: 字符串编码格式(默认utf-8)
|
||||
|
||||
返回:
|
||||
发送成功返回True,失败返回False
|
||||
"""
|
||||
# 创建TCP socket并自动关闭(with语句确保资源释放)
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
try:
|
||||
# 连接服务器(超时时间5秒,避免无限阻塞)
|
||||
sock.settimeout(5.0)
|
||||
sock.connect((host, port))
|
||||
|
||||
# 发送指令(转换为字节流)
|
||||
sock.sendall(command.encode(encoding))
|
||||
print(f"指令 '{command}' 发送成功")
|
||||
return True
|
||||
|
||||
except ConnectionRefusedError:
|
||||
print(f"连接失败:{host}:{port} 未监听或不可达")
|
||||
except socket.timeout:
|
||||
print(f"连接超时:超过5秒未连接到 {host}:{port}")
|
||||
except UnicodeEncodeError:
|
||||
print(f"编码失败:指令包含{encoding}无法编码的字符")
|
||||
except Exception as e:
|
||||
print(f"发送失败:{str(e)}")
|
||||
|
||||
return False
|
||||
|
||||
|
||||
# 使用示例
|
||||
if __name__ == "__main__":
|
||||
# 发送StartConnect指令
|
||||
send_tcp_command("StartConnect")
|
||||
|
||||
# 也可以发送其他指令,例如:
|
||||
# send_tcp_command("StopConnect")
|
||||
405
page_objects/download_tabbar_page.py
Normal file
405
page_objects/download_tabbar_page.py
Normal file
@@ -0,0 +1,405 @@
|
||||
# 更新基站页面操作
|
||||
# page_objects/download_tabbar_page.py
|
||||
from appium.webdriver.common.appiumby import AppiumBy
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.common.exceptions import TimeoutException, NoSuchElementException, StaleElementReferenceException
|
||||
import logging
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import globals.ids as ids # 导入元素ID
|
||||
import globals.global_variable as global_variable # 导入全局变量
|
||||
from globals.driver_utils import check_session_valid, reconnect_driver
|
||||
|
||||
class DownloadTabbarPage:
|
||||
def __init__(self, driver, wait, device_id):
|
||||
self.driver = driver
|
||||
self.wait = wait
|
||||
self.device_id = device_id
|
||||
self.logger = logging.getLogger(__name__)
|
||||
# 添加默认的目标日期值
|
||||
self.target_year = 2022
|
||||
self.target_month = 9
|
||||
self.target_day = 22
|
||||
|
||||
def is_download_tabbar_visible(self):
|
||||
"""检查下载标签栏是否可见"""
|
||||
try:
|
||||
return self.driver.find_element(AppiumBy.ID, ids.DOWNLOAD_TABBAR_ID).is_displayed()
|
||||
except NoSuchElementException:
|
||||
self.logger.warning("下载标签栏元素未找到")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"检查下载标签栏可见性时发生意外错误: {str(e)}")
|
||||
return False
|
||||
|
||||
def click_download_tabbar(self):
|
||||
"""点击下载标签栏"""
|
||||
try:
|
||||
download_tab = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.DOWNLOAD_TABBAR_ID))
|
||||
)
|
||||
download_tab.click()
|
||||
self.logger.info("已点击下载标签栏")
|
||||
|
||||
# 使用显式等待替代固定等待
|
||||
self.wait.until(
|
||||
lambda driver: self.is_download_tabbar_visible()
|
||||
)
|
||||
return True
|
||||
except TimeoutException:
|
||||
self.logger.error("等待下载标签栏可点击超时")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"点击下载标签栏时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def update_work_base(self):
|
||||
"""更新工作基点"""
|
||||
try:
|
||||
# 点击更新工作基点
|
||||
update_work_base = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.UPDATE_WORK_BASE))
|
||||
)
|
||||
update_work_base.click()
|
||||
self.logger.info("已点击更新工作基点")
|
||||
|
||||
# 等待更新完成 - 可以添加更具体的等待条件
|
||||
# 例如等待某个进度条消失或成功提示出现
|
||||
time.sleep(2) # 暂时保留,但建议替换为显式等待
|
||||
return True
|
||||
except TimeoutException:
|
||||
self.logger.error("等待更新工作基点按钮可点击超时")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"更新工作基点时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def _get_current_date(self):
|
||||
"""获取当前开始日期控件的日期值,支持多种格式解析"""
|
||||
try:
|
||||
date_element = self.wait.until(
|
||||
EC.visibility_of_element_located((AppiumBy.ID, ids.DATE_START))
|
||||
)
|
||||
date_text = date_element.text.strip()
|
||||
self.logger.info(f"获取到当前开始日期: {date_text}")
|
||||
|
||||
# 尝试多种日期格式解析
|
||||
date_formats = [
|
||||
"%Y-%m-%d", # 匹配 '2025-08-12' 格式
|
||||
"%Y年%m月%d日", # 匹配 '2025年08月12日' 格式
|
||||
"%Y/%m/%d" # 可选:添加其他可能的格式
|
||||
]
|
||||
|
||||
for fmt in date_formats:
|
||||
try:
|
||||
return datetime.strptime(date_text, fmt)
|
||||
except ValueError:
|
||||
continue # 尝试下一种格式
|
||||
|
||||
# 如果所有格式都匹配失败
|
||||
self.logger.error(f"日期格式解析错误: 无法识别的格式,日期文本: {date_text}")
|
||||
return None
|
||||
|
||||
except TimeoutException:
|
||||
self.logger.error("获取当前日期超时")
|
||||
return None
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取当前日期失败: {str(e)}")
|
||||
return None
|
||||
|
||||
def update_level_line(self):
|
||||
"""更新水准线路,修改为设置2022年9月22日"""
|
||||
try:
|
||||
# 点击更新水准线路
|
||||
update_level_line = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.UPDATE_LEVEL_LINE))
|
||||
)
|
||||
update_level_line.click()
|
||||
self.logger.info("已点击更新水准线路")
|
||||
|
||||
# 获取原始开始日期
|
||||
original_date = self._get_current_date()
|
||||
if not original_date:
|
||||
self.logger.error("无法获取原始开始日期,更新水准线路失败")
|
||||
return False
|
||||
|
||||
# 点击开始日期
|
||||
date_start = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.DATE_START))
|
||||
)
|
||||
date_start.click()
|
||||
self.logger.info("已点击开始日期控件")
|
||||
|
||||
# # 处理时间选择器,设置为2022年9月22日
|
||||
# if not self.handle_time_selector(2022, 9, 22, original_date):
|
||||
# self.logger.error("处理时间选择失败")
|
||||
# return False
|
||||
# 处理时间选择器,滚动选择年份
|
||||
if not self.handle_year_selector():
|
||||
self.logger.error("时间选择器滑动年份,处理时间失败")
|
||||
return False
|
||||
|
||||
return True
|
||||
except TimeoutException:
|
||||
self.logger.error("等待更新水准线路按钮可点击超时")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"更新水准线路时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def _swipe_year_wheel(self):
|
||||
"""滑动年份选择器的滚轮"""
|
||||
try:
|
||||
# 获取年份选择器滚轮元素
|
||||
year_wheel = self.driver.find_element(AppiumBy.ID, "com.bjjw.cjgc:id/wheelView1")
|
||||
|
||||
# 获取滚轮的位置和尺寸
|
||||
location = year_wheel.location
|
||||
size = year_wheel.size
|
||||
|
||||
# 计算滚轮中心点坐标
|
||||
center_x = location['x'] + size['width'] // 2
|
||||
center_y = location['y'] + size['height'] // 2
|
||||
|
||||
# 计算滑动距离 - 滚轮高度的1/5
|
||||
swipe_distance = size['height'] // 5
|
||||
|
||||
# 执行滑动操作 - 从中心向上滑动1/5高度
|
||||
self.driver.swipe(center_x, center_y - swipe_distance, center_x, center_y, 500)
|
||||
|
||||
self.logger.info("已滑动年份选择器")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"滑动年份选择器时出错: {str(e)}")
|
||||
return False
|
||||
def _scroll_to_value(self, picker_id, target_value, original_value, max_attempts=20):
|
||||
"""滚动选择器到目标值,基于原始值计算滚动次数"""
|
||||
try:
|
||||
# 计算需要滚动的次数(绝对值)
|
||||
scroll_count = abs(int(target_value) - int(original_value))
|
||||
self.logger.info(f"需要滚动{scroll_count}次将{picker_id}从{original_value}调整到{target_value}")
|
||||
|
||||
# 确定滚动方向
|
||||
direction = "down" if int(target_value) > int(original_value) else "up"
|
||||
|
||||
# 获取选择器元素
|
||||
picker = self.wait.until(
|
||||
EC.visibility_of_element_located((AppiumBy.ID, picker_id))
|
||||
)
|
||||
|
||||
# 计算滚动坐标
|
||||
x = picker.location['x'] + picker.size['width'] // 2
|
||||
self.logger.info(f"水平位置x为{x}")
|
||||
y_center = picker.location['y'] + picker.size['height'] // 2
|
||||
self.logger.info(f"垂直位置中点y_center为{y_center}")
|
||||
# start_y = y_center if direction == "down" else picker.location['y']
|
||||
# end_y = picker.location['y'] if direction == "down" else y_center
|
||||
# 关键修改:计算选择器高度的五分之一(滑动距离)
|
||||
height_fifth = picker.size['height'] // 5 # 1/5高度
|
||||
|
||||
# 根据方向计算起点和终点,确保滑动距离为 height_fifth
|
||||
if direction == "down":
|
||||
# 向下滚动:从中心点向上滑动1/5高度
|
||||
start_y = y_center
|
||||
end_y = y_center - height_fifth # 终点 = 中心点 - 1/5高度
|
||||
self.logger.info(f"down垂直开始位置start_y为{y_center},垂直结束位置end_y为{end_y}")
|
||||
|
||||
else:
|
||||
# 向上滚动:从中心点向下滑动1/5高度
|
||||
start_y = y_center
|
||||
end_y = y_center + height_fifth # 终点 = 中心点 + 1/5高度
|
||||
self.logger.info(f"up垂直开始位置start_y为{y_center},垂直结束位置end_y为{end_y}")
|
||||
# 执行滚动操作
|
||||
for _ in range(scroll_count):
|
||||
self.driver.swipe(x, start_y, x, end_y, 500)
|
||||
time.sleep(0.5) # 等待滚动稳定
|
||||
return True # 循环scroll_count次后直接返回
|
||||
# # 验证当前值
|
||||
# current_value = picker.text
|
||||
# if current_value == str(target_value):
|
||||
# self.logger.info(f"{picker_id}已达到目标值: {target_value}")
|
||||
# return True
|
||||
|
||||
# 最终验证
|
||||
# final_value = picker.text
|
||||
# if final_value == str(target_value):
|
||||
# self.logger.info(f"{picker_id}已达到目标值: {target_value}")
|
||||
# return True
|
||||
# else:
|
||||
# self.logger.error(f"{picker_id}滚动{scroll_count}次后未达到目标值,当前值: {final_value}")
|
||||
# return False
|
||||
|
||||
except StaleElementReferenceException:
|
||||
self.logger.warning("元素状态已过期,重新获取")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"滚动选择器出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def handle_year_selector(self):
|
||||
"""处理时间选择器,滚动选择年份"""
|
||||
try:
|
||||
# 等待时间选择器出现
|
||||
self.wait.until(
|
||||
EC.visibility_of_element_located((AppiumBy.ID, ids.ALERT_DIALOG))
|
||||
)
|
||||
self.logger.info("时间选择对话框已出现")
|
||||
|
||||
# 滚动选择年份
|
||||
if not self._swipe_year_wheel():
|
||||
self.logger.error("滚动选择年份失败")
|
||||
return False
|
||||
|
||||
# 点击确认按钮
|
||||
confirm_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.SCRCOLL_CONFIRM)) # 日期选择器确认按钮
|
||||
)
|
||||
confirm_btn.click()
|
||||
self.logger.info("已确认时间选择")
|
||||
|
||||
# 点击对话框确认按钮(UPDATE_LEVEL_LINE_CONFIRM)
|
||||
confirm_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.UPDATE_LEVEL_LINE_CONFIRM)) # 选择日期对话框确认按钮
|
||||
)
|
||||
confirm_btn.click()
|
||||
self.logger.info("已点击对话框确认按钮commit")
|
||||
|
||||
# 等待加载对话框出现
|
||||
custom_dialog = self.wait.until(
|
||||
EC.visibility_of_element_located((AppiumBy.ID, ids.LOADING_DIALOG))
|
||||
)
|
||||
self.logger.info("检测到loading对话框出现")
|
||||
|
||||
if not check_session_valid(self.driver, self.device_id):
|
||||
self.logger.warning(f"设备 {self.device_id} 会话无效,尝试重新连接驱动...")
|
||||
if not reconnect_driver(self.device_id, self.driver):
|
||||
self.logger.error(f"设备 {self.device_id} 驱动重连失败")
|
||||
|
||||
# 新增:等待加载对话框消失(表示更新完成)
|
||||
WebDriverWait(self.driver, 300).until(
|
||||
EC.invisibility_of_element_located((AppiumBy.ID, ids.LOADING_DIALOG))
|
||||
)
|
||||
self.logger.info("loading对话框已消失,更新完成")
|
||||
|
||||
return True
|
||||
|
||||
except TimeoutException as e:
|
||||
# 明确超时发生在哪个环节
|
||||
self.logger.error("处理时间选择时超时:可能是等待对话框出现、日期选择器元素或确认按钮超时", exc_info=True)
|
||||
return False
|
||||
except Exception as e:
|
||||
# 细分不同环节的异常
|
||||
self.logger.error(f"处理时间选择对话框时出错:可能是日期滚动、选择器确认或对话框确认环节失败 - {str(e)}", exc_info=True)
|
||||
return False
|
||||
|
||||
def handle_time_selector(self, target_year, target_month, target_day, original_date=None):
|
||||
"""处理时间选择器,选择起始时间并确认"""
|
||||
self.logger.info(f"传入handle_time_selector的初始日期: {original_date}")
|
||||
try:
|
||||
# 等待时间选择器出现
|
||||
self.wait.until(
|
||||
EC.visibility_of_element_located((AppiumBy.ID, ids.ALERT_DIALOG))
|
||||
)
|
||||
self.logger.info("时间选择对话框已出现")
|
||||
|
||||
# 如果没有提供原始日期,使用当前日期控件的值
|
||||
if not original_date:
|
||||
original_date = self._get_current_date()
|
||||
if not original_date:
|
||||
self.logger.error("无法获取原始日期,处理时间选择失败")
|
||||
return False
|
||||
|
||||
# 滚动选择年份
|
||||
if not self._scroll_to_value(ids.SCRCOLL_YEAR, target_year, original_date.year):
|
||||
self.logger.error("滚动选择年份失败")
|
||||
return False
|
||||
|
||||
# 滚动选择月份
|
||||
if not self._scroll_to_value(ids.SCRCOLL_MONTH, target_month, original_date.month):
|
||||
self.logger.error("滚动选择月份失败")
|
||||
return False
|
||||
|
||||
# 滚动选择日期
|
||||
if not self._scroll_to_value(ids.SCRCOLL_DAY, target_day, original_date.day):
|
||||
self.logger.error("滚动选择日期失败")
|
||||
return False
|
||||
|
||||
# 点击确认按钮
|
||||
confirm_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.SCRCOLL_CONFIRM)) # 日期选择器确认按钮
|
||||
)
|
||||
confirm_btn.click()
|
||||
self.logger.info("已确认时间选择")
|
||||
|
||||
# 点击对话框确认按钮(UPDATE_LEVEL_LINE_CONFIRM)
|
||||
confirm_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.UPDATE_LEVEL_LINE_CONFIRM)) # 选择日期对话框确认按钮
|
||||
)
|
||||
confirm_btn.click()
|
||||
self.logger.info("已点击对话框确认按钮commit")
|
||||
|
||||
# 新增:等待加载对话框出现
|
||||
custom_dialog = self.wait.until(
|
||||
EC.visibility_of_element_located((AppiumBy.ID, ids.LOADING_DIALOG))
|
||||
)
|
||||
self.logger.info("检测到loading对话框出现")
|
||||
|
||||
if not check_session_valid(self.driver, self.device_id):
|
||||
self.logger.warning(f"设备 {self.device_id} 会话无效,尝试重新连接驱动...")
|
||||
if not reconnect_driver(self.device_id, self.driver):
|
||||
self.logger.error(f"设备 {self.device_id} 驱动重连失败")
|
||||
|
||||
# 新增:等待加载对话框消失(表示更新完成)
|
||||
WebDriverWait(self.driver, 300).until(
|
||||
EC.invisibility_of_element_located((AppiumBy.ID, ids.LOADING_DIALOG))
|
||||
)
|
||||
self.logger.info("loading对话框已消失,更新完成")
|
||||
|
||||
'''点击commit确认按钮后,loading弹窗会出现,等待其加载完成后关闭
|
||||
检测导航栏中的测量tabbar是否出现来确定是否返回True
|
||||
'''
|
||||
# measure_tabbar_btn = self.wait.until(
|
||||
# EC.visibility_of_element_located((AppiumBy.ID, ids.MEASURE_TABBAR_ID))
|
||||
# )
|
||||
# self.logger.info("检测测量tabbar按钮出现")
|
||||
|
||||
return True
|
||||
|
||||
except TimeoutException as e:
|
||||
# 明确超时发生在哪个环节
|
||||
self.logger.error("处理时间选择时超时:可能是等待对话框出现、日期选择器元素或确认按钮超时", exc_info=True)
|
||||
return False
|
||||
except Exception as e:
|
||||
# 细分不同环节的异常
|
||||
self.logger.error(f"处理时间选择对话框时出错:可能是日期滚动、选择器确认或对话框确认环节失败 - {str(e)}", exc_info=True)
|
||||
return False
|
||||
|
||||
def download_tabbar_page_manager(self):
|
||||
"""执行基础更新操作"""
|
||||
try:
|
||||
# 执行基础更新流程
|
||||
self.logger.info(f"设备 {global_variable.GLOBAL_DEVICE_ID} 开始执行更新流程")
|
||||
|
||||
# 点击下载标签栏
|
||||
if not self.click_download_tabbar():
|
||||
self.logger.error(f"设备 {global_variable.GLOBAL_DEVICE_ID} 点击下载标签栏失败")
|
||||
return False
|
||||
|
||||
# 更新工作基点
|
||||
if not self.update_work_base():
|
||||
self.logger.error(f"设备 {global_variable.GLOBAL_DEVICE_ID} 更新工作基点失败")
|
||||
return False
|
||||
|
||||
# 更新水准线路
|
||||
if not self.update_level_line():
|
||||
self.logger.error(f"设备 {global_variable.GLOBAL_DEVICE_ID} 更新水准线路失败")
|
||||
return False
|
||||
|
||||
self.logger.info(f"设备 {global_variable.GLOBAL_DEVICE_ID} 更新操作执行成功")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"设备 {global_variable.GLOBAL_DEVICE_ID} 执行更新操作时出错: {str(e)}")
|
||||
return False
|
||||
179
page_objects/login_page.py
Normal file
179
page_objects/login_page.py
Normal file
@@ -0,0 +1,179 @@
|
||||
# 登录页面操作
|
||||
# page_objects/login_page.py
|
||||
from appium.webdriver.common.appiumby import AppiumBy
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.common.exceptions import TimeoutException, NoSuchElementException
|
||||
import logging
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
import globals.ids as ids
|
||||
import globals.global_variable as global_variable # 导入全局变量模块
|
||||
import globals.apis as apis
|
||||
|
||||
|
||||
|
||||
class LoginPage:
|
||||
def __init__(self, driver, wait):
|
||||
self.driver = driver
|
||||
self.wait = wait
|
||||
|
||||
def navigate_to_login_page(self, driver, device_id):
|
||||
"""
|
||||
补充的跳转页面函数:当设备处于未知状态时,尝试跳转到登录页面
|
||||
|
||||
参数:
|
||||
driver: 已初始化的Appium WebDriver对象
|
||||
device_id: 设备ID,用于日志记录
|
||||
"""
|
||||
try:
|
||||
target_package = 'com.bjjw.cjgc'
|
||||
target_activity = '.activity.LoginActivity'
|
||||
# 使用ADB命令启动Activity
|
||||
try:
|
||||
logging.info(f"尝试使用ADB命令启动LoginActivity: {target_package}/{target_activity}")
|
||||
adb_command = f"adb -s {device_id} shell am start -n {target_package}/{target_activity}"
|
||||
result = subprocess.run(adb_command, shell=True, capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
logging.info(f"使用ADB命令启动LoginActivity成功")
|
||||
time.sleep(2) # 等待Activity启动
|
||||
return True
|
||||
else:
|
||||
logging.warning(f"ADB命令执行失败: {result.stderr}")
|
||||
except Exception as adb_error:
|
||||
logging.warning(f"执行ADB命令时出错: {adb_error}")
|
||||
except Exception as e:
|
||||
logging.error(f"跳转到登录页面过程中发生未预期错误: {e}")
|
||||
|
||||
# 所有尝试都失败
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def is_login_page(self):
|
||||
"""检查当前是否为登录页面"""
|
||||
try:
|
||||
return self.driver.find_element(AppiumBy.ID, ids.LOGIN_BTN).is_displayed()
|
||||
except NoSuchElementException:
|
||||
return False
|
||||
|
||||
def login(self, username=None):
|
||||
"""执行登录操作"""
|
||||
try:
|
||||
logging.info("正在执行登录操作...")
|
||||
|
||||
# # 获取文本框中已有的用户名
|
||||
# username_field = self.wait.until(
|
||||
# EC.element_to_be_clickable((AppiumBy.ID, ids.LOGIN_USERNAME))
|
||||
# )
|
||||
# 获取用户名输入框
|
||||
username_field = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.LOGIN_USERNAME))
|
||||
)
|
||||
# 填写用户名
|
||||
if username:
|
||||
# 清空用户名输入框
|
||||
try:
|
||||
username_field.clear()
|
||||
except:
|
||||
pass
|
||||
# 填写传入的用户名
|
||||
username_field.send_keys(username)
|
||||
existing_username = username
|
||||
logging.info(f"已填写用户名: {username}")
|
||||
else:
|
||||
# 获取文本框中已有的用户名
|
||||
existing_username = username_field.text
|
||||
# 日志记录获取到的已有用户名(若为空,也需明确记录,避免后续误解)
|
||||
if existing_username.strip(): # 去除空格后判断是否有有效内容
|
||||
logging.info(f"已获取文本框中的已有用户名: {existing_username}")
|
||||
else:
|
||||
logging.info("文本框中未检测到已有用户名(内容为空)")
|
||||
|
||||
# 将用户名写入全局变量中
|
||||
global_variable.GLOBAL_USERNAME = existing_username # 关键:给全局变量赋值
|
||||
# global_variable.set_username(existing_username)
|
||||
|
||||
|
||||
# # 读取文本框内已有的用户名(.text属性获取元素显示的文本内容)
|
||||
# existing_username = username_field.text
|
||||
# # 3. 将获取到的用户名写入全局变量中
|
||||
# # global_variable.GLOBAL_USERNAME = existing_username # 关键:给全局变量赋值
|
||||
# global_variable.set_username(existing_username)
|
||||
|
||||
# # 日志记录获取到的已有用户名(若为空,也需明确记录,避免后续误解)
|
||||
# if existing_username.strip(): # 去除空格后判断是否有有效内容
|
||||
# logging.info(f"已获取文本框中的已有用户名: {existing_username}")
|
||||
# else:
|
||||
# logging.info("文本框中未检测到已有用户名(内容为空)")
|
||||
|
||||
# 1. 定位密码输入框
|
||||
password_field = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.LOGIN_PASSWORD))
|
||||
)
|
||||
|
||||
# 2. 清空密码框(如果需要)
|
||||
try:
|
||||
password_field.clear()
|
||||
# time.sleep(0.5) # 等待清除完成
|
||||
except:
|
||||
# 如果clear方法不可用,尝试其他方式
|
||||
pass
|
||||
|
||||
accounts = apis.get_accounts_from_server("68ef0e02b0138d25e2ac9918")
|
||||
matches = [acc for acc in accounts if acc.get("username") == existing_username]
|
||||
if matches:
|
||||
password = matches[0].get("password")
|
||||
|
||||
password_field.send_keys(password)
|
||||
|
||||
# 4. 可选:隐藏键盘
|
||||
try:
|
||||
self.driver.hide_keyboard()
|
||||
except:
|
||||
pass
|
||||
|
||||
# 点击登录按钮
|
||||
max_retries = 3
|
||||
retry_count = 0
|
||||
|
||||
while retry_count < max_retries:
|
||||
login_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.LOGIN_BTN))
|
||||
)
|
||||
login_btn.click()
|
||||
logging.info(f"已点击登录按钮 (尝试 {retry_count + 1}/{max_retries})")
|
||||
|
||||
# 等待登录完成
|
||||
time.sleep(3)
|
||||
|
||||
# 检查是否登录成功
|
||||
if self.is_login_successful():
|
||||
logging.info("登录成功")
|
||||
return True
|
||||
else:
|
||||
logging.warning("登录后未检测到主页面元素,准备重试")
|
||||
retry_count += 1
|
||||
if retry_count < max_retries:
|
||||
logging.info(f"等待2秒后重新尝试登录...")
|
||||
time.sleep(2)
|
||||
|
||||
logging.error(f"登录失败,已尝试 {max_retries} 次")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"登录过程中出错: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def is_login_successful(self):
|
||||
"""检查登录是否成功"""
|
||||
try:
|
||||
# 等待主页面元素出现
|
||||
self.wait.until(
|
||||
EC.presence_of_element_located((AppiumBy.ID, ids.DOWNLOAD_TABBAR_ID))
|
||||
)
|
||||
return True
|
||||
except TimeoutException:
|
||||
return False
|
||||
403
page_objects/measure_tabbar_page.py
Normal file
403
page_objects/measure_tabbar_page.py
Normal file
@@ -0,0 +1,403 @@
|
||||
# 测量标签栏页面操作
|
||||
# page_objects/measure_tabbar_page.py
|
||||
from appium.webdriver.common.appiumby import AppiumBy
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.common.exceptions import TimeoutException, NoSuchElementException, StaleElementReferenceException
|
||||
import logging
|
||||
import time
|
||||
|
||||
import globals.ids as ids
|
||||
import globals.global_variable as global_variable # 导入全局变量模块
|
||||
from globals.driver_utils import check_session_valid, reconnect_driver, go_main_click_tabber_button # 导入会话检查和重连函数
|
||||
# import globals.driver_utils as driver_utils # 导入全局变量模块
|
||||
class MeasureTabbarPage:
|
||||
def __init__(self, driver, wait,device_id):
|
||||
self.driver = driver
|
||||
self.wait = wait
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.seen_items = set() # 记录已经看到的项目,用于检测是否滚动到底部
|
||||
self.all_items = set() # 记录所有看到的项目,用于检测是否已经查看过所有项目
|
||||
# 获取设备ID用于重连操作
|
||||
self.device_id = device_id
|
||||
|
||||
def is_measure_tabbar_visible(self):
|
||||
"""文件列表是否可见"""
|
||||
try:
|
||||
return self.driver.find_element(AppiumBy.ID, ids.MEASURE_LIST_ID).is_displayed()
|
||||
except NoSuchElementException:
|
||||
self.logger.warning("文件列表未找到")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"文件列表可见性时发生意外错误: {str(e)}")
|
||||
return False
|
||||
|
||||
def click_measure_tabbar(self):
|
||||
"""点击测量标签栏"""
|
||||
try:
|
||||
measure_tab = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, ids.MEASURE_TABBAR_ID))
|
||||
)
|
||||
measure_tab.click()
|
||||
self.logger.info("已点击测量标签栏")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# 等待测量页面加载完成
|
||||
self.wait.until(
|
||||
lambda driver: self.is_measure_tabbar_visible()
|
||||
)
|
||||
return True
|
||||
except TimeoutException:
|
||||
self.logger.error("等待测量标签栏可点击超时")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"点击测量标签栏时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
# def scroll_list(self):
|
||||
# """滑动列表以加载更多项目"""
|
||||
# try:
|
||||
# # 获取列表容器
|
||||
# list_container = self.driver.find_element(AppiumBy.ID, ids.MEASURE_LIST_ID)
|
||||
|
||||
# # 计算滑动坐标
|
||||
# start_x = list_container.location['x'] + list_container.size['width'] // 2
|
||||
# start_y = list_container.location['y'] + list_container.size['height'] * 0.8
|
||||
# end_y = list_container.location['y'] + list_container.size['height'] * 0.2
|
||||
|
||||
# # 执行滑动
|
||||
# self.driver.swipe(start_x, start_y, start_x, end_y, 1000)
|
||||
# self.logger.info("已滑动列表")
|
||||
|
||||
# # 等待新内容加载
|
||||
# time.sleep(2)
|
||||
# return True
|
||||
# except Exception as e:
|
||||
# self.logger.error(f"滑动列表失败: {str(e)}")
|
||||
# return False
|
||||
def scroll_list(self, direction="down"):
|
||||
"""滑动列表以加载更多项目
|
||||
|
||||
Args:
|
||||
direction: 滑动方向,"down"表示向下滑动,"up"表示向上滑动
|
||||
|
||||
Returns:
|
||||
bool: 滑动是否成功执行,对于向上滑动,如果滑动到顶则返回False
|
||||
"""
|
||||
max_retry = 2
|
||||
retry_count = 0
|
||||
|
||||
while retry_count <= max_retry:
|
||||
# 检查会话是否有效
|
||||
if not check_session_valid(self.driver, self.device_id):
|
||||
self.logger.warning(f"会话无效,尝试重新连接... (尝试 {retry_count + 1}/{max_retry})")
|
||||
try:
|
||||
# 尝试重新连接驱动
|
||||
self.driver, self.wait = reconnect_driver(self.device_id, self.driver)
|
||||
self.logger.info("驱动重新连接成功")
|
||||
except Exception as reconnect_error:
|
||||
self.logger.error(f"驱动重新连接失败: {str(reconnect_error)}")
|
||||
retry_count += 1
|
||||
if retry_count > max_retry:
|
||||
self.logger.error("达到最大重试次数,滑动列表失败")
|
||||
return False
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
try:
|
||||
# 获取列表容器
|
||||
list_container = self.driver.find_element(AppiumBy.ID, ids.MEASURE_LIST_ID)
|
||||
|
||||
# 计算滑动坐标
|
||||
start_x = list_container.location['x'] + list_container.size['width'] // 2
|
||||
|
||||
if direction == "down":
|
||||
# 向下滑动
|
||||
start_y = list_container.location['y'] + list_container.size['height'] * 0.95
|
||||
end_y = list_container.location['y'] + list_container.size['height'] * 0.05
|
||||
else:
|
||||
# 向上滑动
|
||||
# 记录滑动前的项目,用于判断是否滑动到顶
|
||||
before_scroll_items = self.get_current_items()
|
||||
start_y = list_container.location['y'] + list_container.size['height'] * 0.05
|
||||
end_y = list_container.location['y'] + list_container.size['height'] * 0.95
|
||||
|
||||
# 执行滑动
|
||||
self.driver.swipe(start_x, start_y, start_x, end_y, 1000)
|
||||
|
||||
# 等待新内容加载
|
||||
time.sleep(1)
|
||||
|
||||
# 向上滑动时,检查是否滑动到顶
|
||||
if direction == "up":
|
||||
after_scroll_items = self.get_current_items()
|
||||
# 如果滑动后的项目与滑动前的项目相同,说明已经滑动到顶
|
||||
if after_scroll_items == before_scroll_items:
|
||||
self.logger.info("已滑动到列表顶部,列表内容不变")
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
self.logger.error(f"滑动列表失败: {error_msg}")
|
||||
|
||||
# 如果是连接相关的错误,尝试重连
|
||||
if any(keyword in error_msg.lower() for keyword in ['socket hang up', 'could not proxy command', 'session']):
|
||||
retry_count += 1
|
||||
if retry_count > max_retry:
|
||||
self.logger.error("达到最大重试次数,滑动列表失败")
|
||||
return False
|
||||
self.logger.warning(f"尝试重新连接后重试... (尝试 {retry_count}/{max_retry})")
|
||||
time.sleep(1)
|
||||
else:
|
||||
# 非连接错误,直接返回False
|
||||
return False
|
||||
|
||||
|
||||
def get_current_items(self):
|
||||
"""获取当前页面中的所有项目文本"""
|
||||
max_retry = 2
|
||||
retry_count = 0
|
||||
|
||||
while retry_count <= max_retry:
|
||||
# 检查会话是否有效
|
||||
if not check_session_valid(self.driver, self.device_id):
|
||||
self.logger.warning(f"会话无效,尝试重新连接... (尝试 {retry_count + 1}/{max_retry})")
|
||||
try:
|
||||
# 尝试重新连接驱动
|
||||
self.driver, self.wait = reconnect_driver(self.device_id, self.driver)
|
||||
self.logger.info("驱动重新连接成功")
|
||||
except Exception as reconnect_error:
|
||||
self.logger.error(f"驱动重新连接失败: {str(reconnect_error)}")
|
||||
retry_count += 1
|
||||
if retry_count > max_retry:
|
||||
self.logger.error("达到最大重试次数,获取当前项目失败")
|
||||
return []
|
||||
time.sleep(0.1) # 等待1秒后重试
|
||||
continue
|
||||
|
||||
try:
|
||||
items = self.driver.find_elements(AppiumBy.ID, ids.MEASURE_LISTVIEW_ID)
|
||||
item_texts = []
|
||||
|
||||
for item in items:
|
||||
try:
|
||||
title_element = item.find_element(AppiumBy.ID, ids.MEASURE_NAME_TEXT_ID)
|
||||
if title_element and title_element.text:
|
||||
item_texts.append(title_element.text)
|
||||
except NoSuchElementException:
|
||||
continue
|
||||
except Exception as item_error:
|
||||
self.logger.warning(f"处理项目时出错: {str(item_error)}")
|
||||
continue
|
||||
|
||||
return item_texts
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
self.logger.error(f"获取当前项目失败: {error_msg}")
|
||||
|
||||
# 如果是连接相关的错误,尝试重连
|
||||
if any(keyword in error_msg.lower() for keyword in ['socket hang up', 'could not proxy command', 'session']):
|
||||
retry_count += 1
|
||||
if retry_count > max_retry:
|
||||
self.logger.error("达到最大重试次数,获取当前项目失败")
|
||||
return []
|
||||
self.logger.warning(f"尝试重新连接后重试... (尝试 {retry_count}/{max_retry})")
|
||||
time.sleep(1)
|
||||
else:
|
||||
# 非连接错误,直接返回空列表
|
||||
return []
|
||||
|
||||
def click_item_by_text(self, text):
|
||||
"""点击指定文本的项目"""
|
||||
max_retry = 2
|
||||
retry_count = 0
|
||||
|
||||
while retry_count <= max_retry:
|
||||
# 检查会话是否有效
|
||||
if not check_session_valid(self.driver, self.device_id):
|
||||
self.logger.warning(f"会话无效,尝试重新连接... (尝试 {retry_count + 1}/{max_retry})")
|
||||
try:
|
||||
# 尝试重新连接驱动
|
||||
self.driver, self.wait = reconnect_driver(self.device_id, self.driver)
|
||||
self.logger.info("驱动重新连接成功")
|
||||
except Exception as reconnect_error:
|
||||
self.logger.error(f"驱动重新连接失败: {str(reconnect_error)}")
|
||||
retry_count += 1
|
||||
if retry_count > max_retry:
|
||||
self.logger.error("达到最大重试次数,点击项目失败")
|
||||
return False
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
try:
|
||||
# 查找包含指定文本的项目
|
||||
items = self.driver.find_elements(AppiumBy.ID, ids.MEASURE_LISTVIEW_ID)
|
||||
|
||||
for item in items:
|
||||
try:
|
||||
title_element = item.find_element(AppiumBy.ID, ids.MEASURE_NAME_TEXT_ID)
|
||||
if title_element and title_element.text == text:
|
||||
title_element.click()
|
||||
self.logger.info(f"已点击项目: {text}")
|
||||
return True
|
||||
except NoSuchElementException:
|
||||
continue
|
||||
except Exception as item_error:
|
||||
self.logger.warning(f"处理项目时出错: {str(item_error)}")
|
||||
continue
|
||||
|
||||
self.logger.warning(f"未找到可点击的项目: {text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
self.logger.error(f"点击项目失败: {error_msg}")
|
||||
|
||||
# 如果是连接相关的错误,尝试重连
|
||||
if any(keyword in error_msg.lower() for keyword in ['socket hang up', 'could not proxy command', 'session']):
|
||||
retry_count += 1
|
||||
if retry_count > max_retry:
|
||||
self.logger.error("达到最大重试次数,点击项目失败")
|
||||
return False
|
||||
self.logger.warning(f"尝试重新连接后重试... (尝试 {retry_count}/{max_retry})")
|
||||
time.sleep(1)
|
||||
else:
|
||||
# 非连接错误,直接返回False
|
||||
return False
|
||||
|
||||
def find_keyword(self, fixed_filename):
|
||||
"""查找指定关键词并点击,支持向下和向上滑动查找"""
|
||||
try:
|
||||
# 等待线路列表容器出现
|
||||
self.wait.until(
|
||||
EC.presence_of_element_located((AppiumBy.ID, ids.MEASURE_LIST_ID))
|
||||
)
|
||||
# self.logger.info("线路列表容器已找到")
|
||||
|
||||
max_scroll_attempts = 50 # 最大滚动尝试次数
|
||||
scroll_count = 0
|
||||
found_items_count = 0 # 记录已找到的项目数量
|
||||
last_items_count = 0 # 记录上一次找到的项目数量
|
||||
previous_items = set() # 记录前一次获取的项目集合,用于检测是否到达边界
|
||||
|
||||
# 首先尝试向下滑动查找
|
||||
while scroll_count < max_scroll_attempts:
|
||||
# 获取当前页面中的所有项目
|
||||
current_items = self.get_current_items()
|
||||
# self.logger.info(f"当前页面找到 {len(current_items)} 个项目: {current_items}")
|
||||
|
||||
# 检查目标文件是否在当前页面中
|
||||
if fixed_filename in current_items:
|
||||
# self.logger.info(f"找到目标文件: {fixed_filename}")
|
||||
# 点击目标文件
|
||||
if self.click_item_by_text(fixed_filename):
|
||||
return True
|
||||
else:
|
||||
self.logger.error(f"点击目标文件失败: {fixed_filename}")
|
||||
return False
|
||||
|
||||
# 检查是否到达底部:连续两次获取的项目相同
|
||||
if current_items == previous_items and len(current_items) > 0:
|
||||
self.logger.info("连续两次获取的项目相同,已到达列表底部")
|
||||
break
|
||||
|
||||
# 更新前一次项目集合
|
||||
previous_items = current_items.copy()
|
||||
|
||||
# # 记录所有看到的项目
|
||||
# self.all_items.update(current_items)
|
||||
|
||||
# # 检查是否已经查看过所有项目
|
||||
# if len(current_items) > 0 and found_items_count == len(self.all_items):
|
||||
# self.logger.info("已向下查看所有项目,未找到目标文件")
|
||||
# break
|
||||
# # return False
|
||||
|
||||
# found_items_count = len(self.all_items)
|
||||
|
||||
# 向下滑动列表以加载更多项目
|
||||
if not self.scroll_list(direction="down"):
|
||||
self.logger.error("向下滑动列表失败")
|
||||
return False
|
||||
|
||||
scroll_count += 1
|
||||
self.logger.info(f"第 {scroll_count} 次向下滑动,继续查找...")
|
||||
|
||||
# 如果向下滑动未找到,尝试向上滑动查找
|
||||
self.logger.info("向下滑动未找到目标,开始向上滑动查找")
|
||||
|
||||
# 重置滚动计数
|
||||
scroll_count = 0
|
||||
|
||||
while scroll_count < max_scroll_attempts:
|
||||
# 向上滑动列表
|
||||
# 如果返回False,说明已经滑动到顶
|
||||
if not self.scroll_list(direction="up"):
|
||||
# 检查是否是因为滑动到顶而返回False
|
||||
if "已滑动到列表顶部" in self.logger.handlers[0].buffer[-1].message:
|
||||
self.logger.info("已滑动到列表顶部,停止向上滑动")
|
||||
break
|
||||
else:
|
||||
self.logger.error("向上滑动列表失败")
|
||||
return False
|
||||
|
||||
# 获取当前页面中的所有项目
|
||||
current_items = self.get_current_items()
|
||||
# self.logger.info(f"向上滑动后找到 {len(current_items)} 个项目: {current_items}")
|
||||
|
||||
# 检查目标文件是否在当前页面中
|
||||
if fixed_filename in current_items:
|
||||
self.logger.info(f"找到目标文件: {fixed_filename}")
|
||||
# 点击目标文件
|
||||
if self.click_item_by_text(fixed_filename):
|
||||
return True
|
||||
else:
|
||||
self.logger.error(f"点击目标文件失败: {fixed_filename}")
|
||||
return False
|
||||
|
||||
scroll_count += 1
|
||||
self.logger.info(f"第 {scroll_count} 次向上滑动,继续查找...")
|
||||
|
||||
self.logger.warning(f"经过 {max_scroll_attempts * 2} 次滑动仍未找到目标文件")
|
||||
return False
|
||||
|
||||
except TimeoutException:
|
||||
self.logger.error("等待线路列表元素超时")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"查找关键词时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def measure_tabbar_page_manager(self):
|
||||
"""执行测量操作"""
|
||||
try:
|
||||
# 跳转到测量页面
|
||||
if not go_main_click_tabber_button(self.driver, self.device_id, "com.bjjw.cjgc:id/img_3_layout"):
|
||||
logging.error(f"设备 {self.device_id} 跳转到测量页面失败")
|
||||
return False
|
||||
|
||||
# # 点击测量标签栏
|
||||
# if not self.click_measure_tabbar():
|
||||
# self.logger.error("点击测量标签栏失败")
|
||||
# return False
|
||||
|
||||
# 固定文件名
|
||||
fixed_filename = global_variable.GLOBAL_CURRENT_PROJECT_NAME
|
||||
self.logger.info(f"开始查找测量数据: {fixed_filename}")
|
||||
|
||||
# 重置已看到的项目集合
|
||||
self.seen_items = set()
|
||||
self.all_items = set()
|
||||
|
||||
# 查找并点击测量数据
|
||||
if self.find_keyword(fixed_filename):
|
||||
self.logger.info("成功找到并点击测量数据")
|
||||
return True
|
||||
else:
|
||||
self.logger.warning("未找到测量数据")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"执行测量操作时出错: {str(e)}")
|
||||
return False
|
||||
343
page_objects/more_download_page.py
Normal file
343
page_objects/more_download_page.py
Normal file
@@ -0,0 +1,343 @@
|
||||
# test_more_download_page.py
|
||||
from appium.webdriver.common.appiumby import AppiumBy
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.common.exceptions import TimeoutException, NoSuchElementException
|
||||
import logging
|
||||
import time
|
||||
|
||||
class MoreDownloadPage:
|
||||
def __init__(self, driver, wait,device_id):
|
||||
self.driver = driver
|
||||
self.wait = wait
|
||||
self.device_id = device_id
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def is_on_more_download_page(self):
|
||||
"""通过下载历史数据按钮来判断是否在更多下载页面"""
|
||||
try:
|
||||
# 使用下载历史数据按钮的resource-id来检查
|
||||
download_history_locator = (AppiumBy.ID, "com.bjjw.cjgc:id/download_history")
|
||||
self.wait.until(EC.presence_of_element_located(download_history_locator))
|
||||
self.logger.info("已确认在更多下载页面")
|
||||
return True
|
||||
except TimeoutException:
|
||||
self.logger.warning("未找到下载历史数据按钮,不在更多下载页面")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"检查更多下载页面时发生意外错误: {str(e)}")
|
||||
return False
|
||||
|
||||
def click_download_button(self):
|
||||
"""点击下载按钮"""
|
||||
try:
|
||||
# 点击下载历史数据按钮
|
||||
download_button = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, "com.bjjw.cjgc:id/download_history"))
|
||||
)
|
||||
download_button.click()
|
||||
self.logger.info("已点击下载历史数据按钮")
|
||||
|
||||
# 等待下载操作开始
|
||||
# time.sleep(3)
|
||||
|
||||
return True
|
||||
|
||||
except TimeoutException:
|
||||
self.logger.error("等待下载按钮可点击超时")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"点击下载按钮时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def click_download_original_data(self):
|
||||
"""点击下载原始数据按钮并处理日期选择"""
|
||||
try:
|
||||
# 点击下载原始数据按钮
|
||||
download_original_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, "com.bjjw.cjgc:id/download_org"))
|
||||
)
|
||||
download_original_btn.click()
|
||||
self.logger.info("已点击下载原始数据按钮")
|
||||
|
||||
# 等待日期选择弹窗出现
|
||||
# time.sleep(2)
|
||||
|
||||
# 点击选择开始日期
|
||||
start_date_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, "com.bjjw.cjgc:id/date"))
|
||||
)
|
||||
start_date_btn.click()
|
||||
self.logger.info("已点击选择开始日期")
|
||||
|
||||
# 等待日期选择器出现
|
||||
# time.sleep(2)
|
||||
|
||||
# 滑动年份选择器 - 向上滑动1/5的距离
|
||||
if not self._swipe_year_wheel():
|
||||
self.logger.error("滑动年份选择器失败")
|
||||
return False
|
||||
|
||||
# 点击日期选择器的确定按钮
|
||||
confirm_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, "com.bjjw.cjgc:id/okBtn"))
|
||||
)
|
||||
confirm_btn.click()
|
||||
self.logger.info("已确认日期选择")
|
||||
|
||||
# 等待日期选择器关闭
|
||||
# time.sleep(2)
|
||||
|
||||
# 假设弹窗有确定按钮,点击它开始下载
|
||||
try:
|
||||
# 尝试查找并点击下载弹窗的确定按钮
|
||||
download_confirm_btn = WebDriverWait(self.driver, 5).until(
|
||||
EC.element_to_be_clickable((AppiumBy.XPATH, "//android.widget.Button[contains(@text, '确定') or contains(@text, '下载')]"))
|
||||
)
|
||||
download_confirm_btn.click()
|
||||
self.logger.info("已点击下载确认按钮")
|
||||
except TimeoutException:
|
||||
self.logger.warning("未找到下载确认按钮,可能不需要确认")
|
||||
|
||||
# 等待下载开始
|
||||
# time.sleep(3)
|
||||
|
||||
return True
|
||||
|
||||
except TimeoutException:
|
||||
self.logger.error("等待下载原始数据按钮可点击超时")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"点击下载原始数据时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def click_download_result_data(self):
|
||||
"""点击下载成果数据按钮并处理日期选择"""
|
||||
try:
|
||||
# 点击下载成果数据按钮
|
||||
download_result_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, "com.bjjw.cjgc:id/download_result"))
|
||||
)
|
||||
download_result_btn.click()
|
||||
self.logger.info("已点击下载成果数据按钮")
|
||||
|
||||
# 等待日期选择弹窗出现
|
||||
# time.sleep(2)
|
||||
|
||||
# 点击选择开始日期
|
||||
start_date_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, "com.bjjw.cjgc:id/date"))
|
||||
)
|
||||
start_date_btn.click()
|
||||
self.logger.info("已点击选择开始日期")
|
||||
|
||||
# 等待日期选择器出现
|
||||
# time.sleep(2)
|
||||
|
||||
# 滑动年份选择器 - 向上滑动1/5的距离
|
||||
if not self._swipe_year_wheel():
|
||||
self.logger.error("滑动年份选择器失败")
|
||||
return False
|
||||
|
||||
# 点击日期选择器的确定按钮
|
||||
confirm_btn = self.wait.until(
|
||||
EC.element_to_be_clickable((AppiumBy.ID, "com.bjjw.cjgc:id/okBtn"))
|
||||
)
|
||||
confirm_btn.click()
|
||||
self.logger.info("已确认日期选择")
|
||||
|
||||
# 等待日期选择器关闭
|
||||
# time.sleep(2)
|
||||
|
||||
# 假设弹窗有确定按钮,点击它开始下载
|
||||
try:
|
||||
# 尝试查找并点击下载弹窗的确定按钮
|
||||
download_confirm_btn = WebDriverWait(self.driver, 5).until(
|
||||
EC.element_to_be_clickable((AppiumBy.XPATH, "//android.widget.Button[contains(@text, '确定') or contains(@text, '下载')]"))
|
||||
)
|
||||
download_confirm_btn.click()
|
||||
self.logger.info("已点击下载确认按钮")
|
||||
except TimeoutException:
|
||||
self.logger.warning("未找到下载确认按钮,可能不需要确认")
|
||||
|
||||
# 等待下载开始
|
||||
# time.sleep(3)
|
||||
|
||||
return True
|
||||
|
||||
except TimeoutException:
|
||||
self.logger.error("等待下载成果数据按钮可点击超时")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"点击下载成果数据时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def _swipe_year_wheel(self):
|
||||
"""滑动年份选择器的滚轮"""
|
||||
try:
|
||||
# 获取年份选择器滚轮元素
|
||||
year_wheel = self.driver.find_element(AppiumBy.ID, "com.bjjw.cjgc:id/wheelView1")
|
||||
|
||||
# 获取滚轮的位置和尺寸
|
||||
location = year_wheel.location
|
||||
size = year_wheel.size
|
||||
|
||||
# 计算滚轮中心点坐标
|
||||
center_x = location['x'] + size['width'] // 2
|
||||
center_y = location['y'] + size['height'] // 2
|
||||
|
||||
# 计算滑动距离 - 滚轮高度的1/5
|
||||
swipe_distance = size['height'] // 5
|
||||
|
||||
# 执行滑动操作 - 从中心向上滑动1/5高度
|
||||
self.driver.swipe(center_x, center_y - swipe_distance, center_x, center_y, 500)
|
||||
|
||||
self.logger.info("已滑动年份选择器")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"滑动年份选择器时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def wait_for_loading_dialog(self, timeout=900):
|
||||
"""
|
||||
检查特定结构的加载弹窗的出现和消失
|
||||
|
||||
参数:
|
||||
timeout: 最大等待时间,默认10分钟(600秒)
|
||||
|
||||
返回:
|
||||
bool: 如果加载弹窗出现并消失返回True,否则返回False
|
||||
"""
|
||||
try:
|
||||
self.logger.info("开始检查加载弹窗...")
|
||||
|
||||
# 首先检查加载弹窗是否出现
|
||||
start_time = time.time()
|
||||
loading_appeared = False
|
||||
|
||||
# 等待加载弹窗出现(最多等待30秒)
|
||||
while time.time() - start_time < 30:
|
||||
try:
|
||||
# 根据提供的结构查找加载弹窗
|
||||
# 查找包含ProgressBar和"loading..."文本的弹窗
|
||||
loading_indicators = [
|
||||
(AppiumBy.XPATH, "//android.widget.FrameLayout[@resource-id='android:id/content']/android.widget.LinearLayout[@resource-id='android:id/parentPanel']//android.widget.ProgressBar"),
|
||||
(AppiumBy.XPATH, "//android.widget.TextView[@resource-id='android:id/message' and @text='loading...']"),
|
||||
(AppiumBy.XPATH, "//android.widget.FrameLayout[@resource-id='android:id/content']//android.widget.ProgressBar"),
|
||||
(AppiumBy.XPATH, "//*[contains(@text, 'loading...')]")
|
||||
]
|
||||
|
||||
for by, value in loading_indicators:
|
||||
try:
|
||||
element = self.driver.find_element(by, value)
|
||||
if element.is_displayed():
|
||||
loading_appeared = True
|
||||
self.logger.info("数据下载已开始")
|
||||
self.logger.info("检测到加载弹窗出现")
|
||||
break
|
||||
except:
|
||||
continue
|
||||
|
||||
if loading_appeared:
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# 如果加载弹窗没有出现,直接返回True
|
||||
if not loading_appeared:
|
||||
self.logger.info("未检测到加载弹窗,继续执行")
|
||||
return True
|
||||
|
||||
# 等待加载弹窗消失
|
||||
self.logger.info("等待加载弹窗消失...")
|
||||
disappearance_start_time = time.time()
|
||||
|
||||
while time.time() - disappearance_start_time < timeout:
|
||||
try:
|
||||
# 检查加载弹窗是否还存在
|
||||
loading_still_exists = False
|
||||
|
||||
for by, value in loading_indicators:
|
||||
try:
|
||||
element = self.driver.find_element(by, value)
|
||||
if element.is_displayed():
|
||||
loading_still_exists = True
|
||||
break
|
||||
except:
|
||||
continue
|
||||
|
||||
if not loading_still_exists:
|
||||
self.logger.info("加载弹窗已消失")
|
||||
return True
|
||||
|
||||
# 每1分钟记录一次状态
|
||||
if int(time.time() - disappearance_start_time) % 60 == 0:
|
||||
elapsed_time = int(time.time() - disappearance_start_time)
|
||||
self.logger.info(f"加载弹窗仍在显示,已等待{elapsed_time//60}分钟")
|
||||
|
||||
except Exception as e:
|
||||
# 如果出现异常,可能弹窗已经消失
|
||||
self.logger.info("加载弹窗可能已消失")
|
||||
return True
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# 如果超时,记录错误并返回False
|
||||
self.logger.error(f"加载弹窗在{timeout}秒后仍未消失")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"检查加载弹窗时出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def more_download_page_manager(self):
|
||||
"""执行更多下载页面管理操作"""
|
||||
try:
|
||||
self.logger.info("开始执行更多下载页面操作")
|
||||
|
||||
# 检查是否在更多下载页面
|
||||
if not self.is_on_more_download_page():
|
||||
self.logger.error("不在更多下载页面")
|
||||
return False
|
||||
|
||||
# 点击下载历史数据按钮
|
||||
if not self.click_download_button():
|
||||
self.logger.error("点击下载历史数据按钮失败")
|
||||
return False
|
||||
|
||||
# 等待下载历史数据页面加载完成
|
||||
# time.sleep(3)
|
||||
|
||||
# 点击下载原始数据按钮
|
||||
if not self.click_download_original_data():
|
||||
self.logger.error("点击下载原始数据按钮失败")
|
||||
return False
|
||||
|
||||
# 等待下载操作完成
|
||||
time.sleep(1)
|
||||
|
||||
# 使用wait_for_loading_dialog函数等待下载过程中的加载弹窗消失
|
||||
if not self.wait_for_loading_dialog():
|
||||
self.logger.warning("下载过程中的加载弹窗未在预期时间内消失,但操作已完成")
|
||||
|
||||
# 等待一段时间,确保原始数据下载完成
|
||||
time.sleep(1)
|
||||
|
||||
# 点击下载成果数据按钮
|
||||
if not self.click_download_result_data():
|
||||
self.logger.error("点击下载成果数据按钮失败")
|
||||
return False
|
||||
|
||||
# 使用wait_for_loading_dialog函数等待下载过程中的加载弹窗消失
|
||||
if not self.wait_for_loading_dialog():
|
||||
self.logger.warning("成果数据下载过程中的加载弹窗未在预期时间内消失,但操作已完成")
|
||||
|
||||
self.logger.info("更多下载页面操作执行完成")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"执行更多下载页面操作时出错: {str(e)}")
|
||||
return False
|
||||
1907
page_objects/screenshot_page.py
Normal file
1907
page_objects/screenshot_page.py
Normal file
File diff suppressed because it is too large
Load Diff
1112
page_objects/section_mileage_config_page.py
Normal file
1112
page_objects/section_mileage_config_page.py
Normal file
File diff suppressed because it is too large
Load Diff
2227
page_objects/upload_config_page.py
Normal file
2227
page_objects/upload_config_page.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user