diff --git a/globals/__pycache__/driver_utils.cpython-312.pyc b/globals/__pycache__/driver_utils.cpython-312.pyc index 6409e71..9efb5f0 100644 Binary files a/globals/__pycache__/driver_utils.cpython-312.pyc and b/globals/__pycache__/driver_utils.cpython-312.pyc differ diff --git a/page_objects/__pycache__/more_download_page.cpython-312.pyc b/page_objects/__pycache__/more_download_page.cpython-312.pyc index b23006a..bb23112 100644 Binary files a/page_objects/__pycache__/more_download_page.cpython-312.pyc and b/page_objects/__pycache__/more_download_page.cpython-312.pyc differ diff --git a/page_objects/__pycache__/screenshot_page.cpython-312.pyc b/page_objects/__pycache__/screenshot_page.cpython-312.pyc index 254efe3..858362c 100644 Binary files a/page_objects/__pycache__/screenshot_page.cpython-312.pyc and b/page_objects/__pycache__/screenshot_page.cpython-312.pyc differ diff --git a/page_objects/__pycache__/upload_config_page.cpython-312.pyc b/page_objects/__pycache__/upload_config_page.cpython-312.pyc index 1ab2c63..e75af5f 100644 Binary files a/page_objects/__pycache__/upload_config_page.cpython-312.pyc and b/page_objects/__pycache__/upload_config_page.cpython-312.pyc differ diff --git a/page_objects/more_download_page.py b/page_objects/more_download_page.py index c105577..ab8eca7 100644 --- a/page_objects/more_download_page.py +++ b/page_objects/more_download_page.py @@ -5,6 +5,7 @@ from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException, NoSuchElementException import logging import time +from datetime import datetime from globals.driver_utils import launch_app_manually from page_objects.login_page import LoginPage @@ -179,12 +180,41 @@ class MoreDownloadPage: try: # # 获取年份选择器滚轮元素 # year_wheel = self.driver.find_element(AppiumBy.ID, "com.bjjw.cjgc:id/wheelView1") + # 获取当前日期 + current_date = datetime.now() + current_month = current_date.month + + # 检查月份是否小于等于3 + if current_month <= 3: + self.logger.info(f"当前月份为{current_month}月,需要滑动年份选择器") + + # 获取年份选择器滚轮元素 + 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("已滑动一次年份选择器") + else: + self.logger.info(f"当前月份为{current_month}月,不需要滑动年份选择器") # 获取月份选择器滚轮元素 - year_wheel = self.driver.find_element(AppiumBy.ID, "com.bjjw.cjgc:id/wheelView2") + month_wheel = self.driver.find_element(AppiumBy.ID, "com.bjjw.cjgc:id/wheelView2") # 获取滚轮的位置和尺寸 - location = year_wheel.location - size = year_wheel.size + location = month_wheel.location + size = month_wheel.size # 计算滚轮中心点坐标 center_x = location['x'] + size['width'] // 2 diff --git a/page_objects/screenshot_page.py b/page_objects/screenshot_page.py index dd2a0b9..d0b0035 100644 --- a/page_objects/screenshot_page.py +++ b/page_objects/screenshot_page.py @@ -5,6 +5,7 @@ import time import re import os from datetime import datetime +from turtle import back from appium.webdriver.common.appiumby import AppiumBy from selenium.common.exceptions import NoSuchElementException, TimeoutException from selenium.webdriver.support.ui import WebDriverWait @@ -866,7 +867,7 @@ class ScreenshotPage: self.logger.info(f"已点击返回按钮,等待处理返回确认弹窗") if not self.handle_confirmation_dialog(device_id): self.logger.error(f"设备 {device_id} 处理返回确认弹窗失败") - return False + # return False # 3. 验证是否成功返回到上一页面 @@ -1277,80 +1278,118 @@ class ScreenshotPage: # 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 = [] + processed_breakpoints = [] # 创建一个列表,用于记录已处理的断点 # 开始循环处理断点 - for breakpoint_name in breakpoint_names: - if breakpoint_name in processed_breakpoints: - continue - line_code = global_variable.get_upload_breakpoint_dict()[breakpoint_name] - - self.logger.info(f"开始处理要平差的断点 {breakpoint_name}") + # 检测当前页面获取到的标段是否在breakpoint_names中 + max_scroll_attempts = 100 # 最大滚动尝试次数 + scroll_count = 0 + previous_items = set() # 记录前一次获取的项目集合,用于检测是否到达边界 + found_any = False # 标记是否找到并处理了任何断点 + max_retry_attempts = 3 # 每个断点的最大重试次数 + + while scroll_count < max_scroll_attempts: + # 获取当前页面中的所有项目 + current_items = self.get_current_items() + self.logger.info(f"当前页面找到 {len(current_items)} 个项目") - # 把断点名称给find_keyword - if not self.find_keyword(breakpoint_name): - self.logger.error(f"设备 {device_id} 未找到包含 {breakpoint_name} 的文件名") - continue # 继续处理下一个断点 + # 检查当前页面的项目是否在breakpoint_names中 + for item in current_items: + # 检查项目是否在breakpoint_names中且未处理 + if item in breakpoint_names and item not in processed_breakpoints: + self.logger.info(f"找到目标断点: {item}") + found_any = True + + # 获取线路编码 + try: + line_code = global_variable.get_upload_breakpoint_dict()[item] + except KeyError: + self.logger.error(f"未找到断点 {item} 的线路编码") + continue + + # 重试处理断点 + retry_count = 0 + while retry_count < max_retry_attempts: + self.logger.info(f"开始处理断点 {item} (第 {retry_count + 1} 次尝试)") + + # 点击目标项目 + if not self.click_item_by_text(item): + self.logger.error(f"点击目标断点失败: {item}") + retry_count += 1 + continue + + if not self.handle_measurement_dialog(): + self.logger.error(f"设备 {device_id} 处理测量弹窗失败") + retry_count += 1 + continue - if not self.handle_measurement_dialog(): - self.logger.error(f"设备 {device_id} 处理测量弹窗失败") - continue + if not self.check_apply_btn(): + retry_count += 1 + self.driver.back() + self.logger.info(f"设备 {device_id} 检查平差处理按钮失败,已点击手机系统返回按钮") + break + + # 点击平差处理按钮 + if not self.click_adjustment_button(device_id): + self.logger.error(f"设备 {device_id} 点击平差处理按钮失败") + retry_count += 1 + continue - if not self.check_apply_btn(): - self.logger.error(f"设备 {device_id} 检查平差处理按钮失败") - self.execute_back_navigation_steps(device_id) - continue + # 检查是否在测量页面,在就重新执行选择断点,滑动列表到底部,点击最后一个spinner, 再下滑一次,点击平差处理按钮平差 + if not self.handle_back_navigation(item, device_id): + self.logger.error(f"{item}平差失败,未截图") + retry_count += 1 + continue + + # 检测并处理"是 保留成果"弹窗 + if not self.handle_adjustment_result_dialog(): + self.logger.error("处理平差结果弹窗失败") + retry_count += 1 + continue + + # 点击返回按钮并处理弹窗 + if not self.execute_back_navigation_steps(device_id): + self.logger.error(f"设备 {device_id} 处理返回按钮确认失败") + retry_count += 1 + continue + + # 成功处理完一个断点,添加到已处理列表 + processed_breakpoints.append(item) + self.logger.info(f"成功处理断点: {item}") + break # 跳出重试循环 + + # 检查是否重试次数用完仍未成功 + if retry_count >= max_retry_attempts: + self.logger.error(f"断点 {item} 经过 {max_retry_attempts} 次重试后仍然失败") + + # 重新获取当前页面项目,因为可能有新的项目加载 + break + # 向下滑动列表以加载更多项目 + if not self.scroll_list(direction="down"): + self.logger.error("向下滑动列表失败") + break + + # 检查是否到达底部:连续两次获取的项目相同 + if current_items == previous_items and len(current_items) > 0: + self.logger.info("连续两次获取的项目相同,已到达列表底部") + break - # 4. 点击平差处理按钮 - if not self.click_adjustment_button(device_id): - self.logger.error(f"设备 {device_id} 点击平差处理按钮失败") - continue + # 更新前一次项目集合 + previous_items = current_items.copy() - # 检查是否在测量页面,在就重新执行选择断点,滑动列表到底部,点击最后一个spinner, 再下滑一次,点击平差处理按钮平差 - if not self.handle_back_navigation(breakpoint_name, device_id): - self.logger.error(f"{breakpoint_name}平差失败,未截图") - continue - - - # 检测并处理"是 保留成果"弹窗 - if not self.handle_adjustment_result_dialog(): - self.logger.error("处理平差结果弹窗失败") - continue - - # # 平差完成,将断点数据保存到上传列表中 - # if not self.add_breakpoint_to_upload_list(breakpoint_name, line_code): - # self.logger.error(f"设备 {device_id} 保存断点 {breakpoint_name} 到上传列表失败") - # continue - - # # 检查是否在测量页面,在就重新执行选择断点,滑动列表到底部,点击最后一个spinner, 再下滑一次,点击平差处理按钮平差 - # if not self.handle_back_navigation(breakpoint_name, device_id): - # self.logger.error(f"{breakpoint_name}平差失败,未截图") - # continue - - # # 检测并处理"是 保留成果"弹窗 - # if not self.handle_adjustment_result_dialog(): - # self.logger.error("处理平差结果弹窗失败") - # continue - - - # 点击返回按钮并处理弹窗 - if not self.execute_back_navigation_steps(device_id): - self.logger.error(f"设备 {device_id} 处理返回按钮确认失败") - continue - - # # 成功处理完一个断点,添加到已处理列表 - # processed_breakpoints.append(breakpoint_name) - # self.logger.info(f"成功处理断点: {breakpoint_name}") - - # # 检查是否所有断点都处理完成 - # if len(processed_breakpoints) == len(breakpoint_names): - # self.logger.info(f"设备 {device_id} 平差页面操作执行完成") - # return True - # else: - # self.logger.warning(f"设备 {device_id} 部分断点处理失败,已成功处理 {len(processed_breakpoints)}/{len(breakpoint_names)} 个断点") - # return True - self.logger.warning(f"设备 {device_id} 平差线路到上传页面流程执行完成") - return True + scroll_count += 1 + self.logger.info(f"第 {scroll_count} 次向下滑动,继续查找...") + + # 检查是否所有断点都处理完成 + if len(processed_breakpoints) == len(breakpoint_names): + self.logger.info(f"设备 {device_id} 平差页面操作执行完成") + return True + elif found_any: + self.logger.warning(f"设备 {device_id} 部分断点处理完成,已成功处理 {len(processed_breakpoints)}/{len(breakpoint_names)} 个断点") + return True + else: + self.logger.warning(f"设备 {device_id} 未找到任何目标断点") + return True except Exception as e: retry_count += 1 diff --git a/scheduler.py b/scheduler.py index 243acd5..05bc038 100644 --- a/scheduler.py +++ b/scheduler.py @@ -152,23 +152,28 @@ def get_combined_tasks(): def run_task(address, target_time, username): """ - 单个执行线程:锁定状态 -> 等待 -> 执行 -> 完成 + 单个执行线程:检查时间 -> 锁定状态 -> 执行 -> 完成 """ - # 1. 尝试将状态从 ok 改为 running (锁定任务) - # 如果此时文件状态已被其他逻辑修改,则放弃执行,防止重复 - if not update_file_status(username, "ok", "running"): - return f"⏭️ {username} 状态已变更,跳过执行。" - - print(f"🚀 [任务锁定] 设备: {address} | 用户: {username} | 计划时间: {target_time}") + print(f"📅 [任务检查] 设备: {address} | 用户: {username} | 计划时间: {target_time}") try: - # 2. 计算并执行等待逻辑 + # 1. 检查当前时间是否到达计划时间 target_dt = datetime.strptime(target_time, "%Y-%m-%d %H:%M:%S") - wait_secs = (target_dt - datetime.now()).total_seconds() + current_dt = datetime.now() - if wait_secs > 0: - print(f"⏳ {username} 距离执行还有 {int(wait_secs)} 秒...") - time.sleep(wait_secs) + # 如果当前时间还未到达计划时间,直接返回,等待下次轮询 + if current_dt < target_dt: + time_diff = int((target_dt - current_dt).total_seconds()) + print(f"⏰ {username} 计划时间未到,距离执行还有 {time_diff} 秒,等待下次轮询") + return f"⏰ {username} 计划时间未到,等待下次轮询" + + # 2. 开始执行前,尝试将状态从 ok 改为 running (锁定任务) + # 如果此时文件状态已被其他逻辑修改,则放弃执行,防止重复 + print(f"🔒 [准备锁定] 尝试锁定任务状态: {username}") + if not update_file_status(username, "ok", "running"): + return f"⏭️ {username} 状态已变更,跳过执行。" + + print(f"🚀 [任务锁定] 设备: {address} | 用户: {username} | 计划时间: {target_time}") # 3. 调用 main.py 中的自动化逻辑 print(f"▶️ [正在执行] {username} 开始自动化操作...") @@ -181,7 +186,11 @@ def run_task(address, target_time, username): except Exception as e: # 如果中间报错,将状态改为 error 方便排查 - update_file_status(username, "running", "error") + # 只有在状态已经改为 running 的情况下才需要改为 error + try: + update_file_status(username, "running", "error") + except: + pass return f"❌ {username} 执行异常: {str(e)}" def monitor_center(): diff --git a/test_results/上传失败的断点.txt b/test_results/上传失败的断点.txt index f31bda5..470c0f4 100644 --- a/test_results/上传失败的断点.txt +++ b/test_results/上传失败的断点.txt @@ -1,4 +1 @@ -CZSCZQ-13A-二工区-沙马大桥-1#墩身-山区 -CZSCZQ-13A-二工区-沙马大桥-2#墩身-山区 -CZSCZQ-13A-二工区-沙马大桥-6#墩-山区 -CZSCZQ-13A-二工区-沙马大桥-7#墩-山区 +SJSG-7标-跨沿江高速特大桥-85#-89#-墩身-平原