Compare commits
2 Commits
2cee7731b1
...
fbdbed37f4
| Author | SHA1 | Date | |
|---|---|---|---|
| fbdbed37f4 | |||
| 80fdc75c26 |
Binary file not shown.
@@ -604,7 +604,7 @@ def launch_app_manually(driver, device_id, package_name="com.bjjw.cjgc", activit
|
|||||||
# 使用ADB命令设置屏幕永不休眠
|
# 使用ADB命令设置屏幕永不休眠
|
||||||
screen_timeout_cmd = [
|
screen_timeout_cmd = [
|
||||||
"adb", "-s", device_id,
|
"adb", "-s", device_id,
|
||||||
"shell", "settings", "put", "system", "screen_off_timeout", "0"
|
"shell", "settings", "put", "system", "screen_off_timeout", "86400000"
|
||||||
]
|
]
|
||||||
timeout_result = subprocess.run(screen_timeout_cmd, capture_output=True, text=True, timeout=15)
|
timeout_result = subprocess.run(screen_timeout_cmd, capture_output=True, text=True, timeout=15)
|
||||||
if timeout_result.returncode == 0:
|
if timeout_result.returncode == 0:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -5,6 +5,7 @@ from selenium.webdriver.support import expected_conditions as EC
|
|||||||
from selenium.common.exceptions import TimeoutException, NoSuchElementException
|
from selenium.common.exceptions import TimeoutException, NoSuchElementException
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from datetime import datetime
|
||||||
from globals.driver_utils import launch_app_manually
|
from globals.driver_utils import launch_app_manually
|
||||||
from page_objects.login_page import LoginPage
|
from page_objects.login_page import LoginPage
|
||||||
|
|
||||||
@@ -177,12 +178,43 @@ class MoreDownloadPage:
|
|||||||
def _swipe_year_wheel(self):
|
def _swipe_year_wheel(self):
|
||||||
"""滑动年份选择器的滚轮"""
|
"""滑动年份选择器的滚轮"""
|
||||||
try:
|
try:
|
||||||
# 获取年份选择器滚轮元素
|
# # 获取年份选择器滚轮元素
|
||||||
year_wheel = self.driver.find_element(AppiumBy.ID, "com.bjjw.cjgc:id/wheelView1")
|
# 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}月,不需要滑动年份选择器")
|
||||||
|
# 获取月份选择器滚轮元素
|
||||||
|
month_wheel = self.driver.find_element(AppiumBy.ID, "com.bjjw.cjgc:id/wheelView2")
|
||||||
|
|
||||||
# 获取滚轮的位置和尺寸
|
# 获取滚轮的位置和尺寸
|
||||||
location = year_wheel.location
|
location = month_wheel.location
|
||||||
size = year_wheel.size
|
size = month_wheel.size
|
||||||
|
|
||||||
# 计算滚轮中心点坐标
|
# 计算滚轮中心点坐标
|
||||||
center_x = location['x'] + size['width'] // 2
|
center_x = location['x'] + size['width'] // 2
|
||||||
@@ -191,7 +223,7 @@ class MoreDownloadPage:
|
|||||||
# 计算滑动距离 - 滚轮高度的1/5
|
# 计算滑动距离 - 滚轮高度的1/5
|
||||||
swipe_distance = size['height'] // 5
|
swipe_distance = size['height'] // 5
|
||||||
|
|
||||||
for i in range(1):
|
for i in range(3):
|
||||||
# 执行滑动操作 - 从中心向上滑动1/5高度
|
# 执行滑动操作 - 从中心向上滑动1/5高度
|
||||||
self.driver.swipe(center_x, center_y - swipe_distance, center_x, center_y, 500)
|
self.driver.swipe(center_x, center_y - swipe_distance, center_x, center_y, 500)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import time
|
|||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from turtle import back
|
||||||
from appium.webdriver.common.appiumby import AppiumBy
|
from appium.webdriver.common.appiumby import AppiumBy
|
||||||
from selenium.common.exceptions import NoSuchElementException, TimeoutException
|
from selenium.common.exceptions import NoSuchElementException, TimeoutException
|
||||||
from selenium.webdriver.support.ui import WebDriverWait
|
from selenium.webdriver.support.ui import WebDriverWait
|
||||||
@@ -866,7 +867,7 @@ class ScreenshotPage:
|
|||||||
self.logger.info(f"已点击返回按钮,等待处理返回确认弹窗")
|
self.logger.info(f"已点击返回按钮,等待处理返回确认弹窗")
|
||||||
if not self.handle_confirmation_dialog(device_id):
|
if not self.handle_confirmation_dialog(device_id):
|
||||||
self.logger.error(f"设备 {device_id} 处理返回确认弹窗失败")
|
self.logger.error(f"设备 {device_id} 处理返回确认弹窗失败")
|
||||||
return False
|
# return False
|
||||||
|
|
||||||
|
|
||||||
# 3. 验证是否成功返回到上一页面
|
# 3. 验证是否成功返回到上一页面
|
||||||
@@ -1277,80 +1278,118 @@ class ScreenshotPage:
|
|||||||
# global_variable.set_upload_breakpoint_dict({'CDWZQ-2标-龙骨湾右线大桥-0-7号墩-平原': 'L156372', 'CDWZQ-2标-蓝家湾特大 桥-31-31-平原': 'L159206'})
|
# 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())
|
breakpoint_names = list(global_variable.get_upload_breakpoint_dict().keys())
|
||||||
processed_breakpoints = []
|
processed_breakpoints = [] # 创建一个列表,用于记录已处理的断点
|
||||||
|
|
||||||
# 开始循环处理断点
|
# 开始循环处理断点
|
||||||
for breakpoint_name in breakpoint_names:
|
# 检测当前页面获取到的标段是否在breakpoint_names中
|
||||||
if breakpoint_name in processed_breakpoints:
|
max_scroll_attempts = 100 # 最大滚动尝试次数
|
||||||
continue
|
scroll_count = 0
|
||||||
line_code = global_variable.get_upload_breakpoint_dict()[breakpoint_name]
|
previous_items = set() # 记录前一次获取的项目集合,用于检测是否到达边界
|
||||||
|
found_any = False # 标记是否找到并处理了任何断点
|
||||||
|
max_retry_attempts = 3 # 每个断点的最大重试次数
|
||||||
|
|
||||||
self.logger.info(f"开始处理要平差的断点 {breakpoint_name}")
|
while scroll_count < max_scroll_attempts:
|
||||||
|
# 获取当前页面中的所有项目
|
||||||
|
current_items = self.get_current_items()
|
||||||
|
self.logger.info(f"当前页面找到 {len(current_items)} 个项目")
|
||||||
|
|
||||||
# 把断点名称给find_keyword
|
# 检查当前页面的项目是否在breakpoint_names中
|
||||||
if not self.find_keyword(breakpoint_name):
|
for item in current_items:
|
||||||
self.logger.error(f"设备 {device_id} 未找到包含 {breakpoint_name} 的文件名")
|
# 检查项目是否在breakpoint_names中且未处理
|
||||||
continue # 继续处理下一个断点
|
if item in breakpoint_names and item not in processed_breakpoints:
|
||||||
|
self.logger.info(f"找到目标断点: {item}")
|
||||||
|
found_any = True
|
||||||
|
|
||||||
if not self.handle_measurement_dialog():
|
# 获取线路编码
|
||||||
self.logger.error(f"设备 {device_id} 处理测量弹窗失败")
|
try:
|
||||||
continue
|
line_code = global_variable.get_upload_breakpoint_dict()[item]
|
||||||
|
except KeyError:
|
||||||
|
self.logger.error(f"未找到断点 {item} 的线路编码")
|
||||||
|
continue
|
||||||
|
|
||||||
if not self.check_apply_btn():
|
# 重试处理断点
|
||||||
self.logger.error(f"设备 {device_id} 检查平差处理按钮失败")
|
retry_count = 0
|
||||||
self.execute_back_navigation_steps(device_id)
|
while retry_count < max_retry_attempts:
|
||||||
continue
|
self.logger.info(f"开始处理断点 {item} (第 {retry_count + 1} 次尝试)")
|
||||||
|
|
||||||
# 4. 点击平差处理按钮
|
# 点击目标项目
|
||||||
if not self.click_adjustment_button(device_id):
|
if not self.click_item_by_text(item):
|
||||||
self.logger.error(f"设备 {device_id} 点击平差处理按钮失败")
|
self.logger.error(f"点击目标断点失败: {item}")
|
||||||
continue
|
retry_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
# 检查是否在测量页面,在就重新执行选择断点,滑动列表到底部,点击最后一个spinner, 再下滑一次,点击平差处理按钮平差
|
if not self.handle_measurement_dialog():
|
||||||
if not self.handle_back_navigation(breakpoint_name, device_id):
|
self.logger.error(f"设备 {device_id} 处理测量弹窗失败")
|
||||||
self.logger.error(f"{breakpoint_name}平差失败,未截图")
|
retry_count += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if not self.check_apply_btn():
|
||||||
|
retry_count += 1
|
||||||
|
self.driver.back()
|
||||||
|
self.logger.info(f"设备 {device_id} 检查平差处理按钮失败,已点击手机系统返回按钮")
|
||||||
|
break
|
||||||
|
|
||||||
# 检测并处理"是 保留成果"弹窗
|
# 点击平差处理按钮
|
||||||
if not self.handle_adjustment_result_dialog():
|
if not self.click_adjustment_button(device_id):
|
||||||
self.logger.error("处理平差结果弹窗失败")
|
self.logger.error(f"设备 {device_id} 点击平差处理按钮失败")
|
||||||
continue
|
retry_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
# # 平差完成,将断点数据保存到上传列表中
|
# 检查是否在测量页面,在就重新执行选择断点,滑动列表到底部,点击最后一个spinner, 再下滑一次,点击平差处理按钮平差
|
||||||
# if not self.add_breakpoint_to_upload_list(breakpoint_name, line_code):
|
if not self.handle_back_navigation(item, device_id):
|
||||||
# self.logger.error(f"设备 {device_id} 保存断点 {breakpoint_name} 到上传列表失败")
|
self.logger.error(f"{item}平差失败,未截图")
|
||||||
# continue
|
retry_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
# # 检查是否在测量页面,在就重新执行选择断点,滑动列表到底部,点击最后一个spinner, 再下滑一次,点击平差处理按钮平差
|
# 检测并处理"是 保留成果"弹窗
|
||||||
# if not self.handle_back_navigation(breakpoint_name, device_id):
|
if not self.handle_adjustment_result_dialog():
|
||||||
# self.logger.error(f"{breakpoint_name}平差失败,未截图")
|
self.logger.error("处理平差结果弹窗失败")
|
||||||
# continue
|
retry_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
# # 检测并处理"是 保留成果"弹窗
|
# 点击返回按钮并处理弹窗
|
||||||
# if not self.handle_adjustment_result_dialog():
|
if not self.execute_back_navigation_steps(device_id):
|
||||||
# self.logger.error("处理平差结果弹窗失败")
|
self.logger.error(f"设备 {device_id} 处理返回按钮确认失败")
|
||||||
# continue
|
retry_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 成功处理完一个断点,添加到已处理列表
|
||||||
|
processed_breakpoints.append(item)
|
||||||
|
self.logger.info(f"成功处理断点: {item}")
|
||||||
|
break # 跳出重试循环
|
||||||
|
|
||||||
# 点击返回按钮并处理弹窗
|
# 检查是否重试次数用完仍未成功
|
||||||
if not self.execute_back_navigation_steps(device_id):
|
if retry_count >= max_retry_attempts:
|
||||||
self.logger.error(f"设备 {device_id} 处理返回按钮确认失败")
|
self.logger.error(f"断点 {item} 经过 {max_retry_attempts} 次重试后仍然失败")
|
||||||
continue
|
|
||||||
|
|
||||||
# # 成功处理完一个断点,添加到已处理列表
|
# 重新获取当前页面项目,因为可能有新的项目加载
|
||||||
# processed_breakpoints.append(breakpoint_name)
|
break
|
||||||
# self.logger.info(f"成功处理断点: {breakpoint_name}")
|
# 向下滑动列表以加载更多项目
|
||||||
|
if not self.scroll_list(direction="down"):
|
||||||
|
self.logger.error("向下滑动列表失败")
|
||||||
|
break
|
||||||
|
|
||||||
# # 检查是否所有断点都处理完成
|
# 检查是否到达底部:连续两次获取的项目相同
|
||||||
# if len(processed_breakpoints) == len(breakpoint_names):
|
if current_items == previous_items and len(current_items) > 0:
|
||||||
# self.logger.info(f"设备 {device_id} 平差页面操作执行完成")
|
self.logger.info("连续两次获取的项目相同,已到达列表底部")
|
||||||
# return True
|
break
|
||||||
# else:
|
|
||||||
# self.logger.warning(f"设备 {device_id} 部分断点处理失败,已成功处理 {len(processed_breakpoints)}/{len(breakpoint_names)} 个断点")
|
# 更新前一次项目集合
|
||||||
# return True
|
previous_items = current_items.copy()
|
||||||
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:
|
except Exception as e:
|
||||||
retry_count += 1
|
retry_count += 1
|
||||||
|
|||||||
35
scheduler.py
35
scheduler.py
@@ -152,23 +152,28 @@ def get_combined_tasks():
|
|||||||
|
|
||||||
def run_task(address, target_time, username):
|
def run_task(address, target_time, username):
|
||||||
"""
|
"""
|
||||||
单个执行线程:锁定状态 -> 等待 -> 执行 -> 完成
|
单个执行线程:检查时间 -> 锁定状态 -> 执行 -> 完成
|
||||||
"""
|
"""
|
||||||
# 1. 尝试将状态从 ok 改为 running (锁定任务)
|
print(f"📅 [任务检查] 设备: {address} | 用户: {username} | 计划时间: {target_time}")
|
||||||
# 如果此时文件状态已被其他逻辑修改,则放弃执行,防止重复
|
|
||||||
if not update_file_status(username, "ok", "running"):
|
|
||||||
return f"⏭️ {username} 状态已变更,跳过执行。"
|
|
||||||
|
|
||||||
print(f"🚀 [任务锁定] 设备: {address} | 用户: {username} | 计划时间: {target_time}")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 2. 计算并执行等待逻辑
|
# 1. 检查当前时间是否到达计划时间
|
||||||
target_dt = datetime.strptime(target_time, "%Y-%m-%d %H:%M:%S")
|
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)} 秒...")
|
if current_dt < target_dt:
|
||||||
time.sleep(wait_secs)
|
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 中的自动化逻辑
|
# 3. 调用 main.py 中的自动化逻辑
|
||||||
print(f"▶️ [正在执行] {username} 开始自动化操作...")
|
print(f"▶️ [正在执行] {username} 开始自动化操作...")
|
||||||
@@ -181,7 +186,11 @@ def run_task(address, target_time, username):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# 如果中间报错,将状态改为 error 方便排查
|
# 如果中间报错,将状态改为 error 方便排查
|
||||||
update_file_status(username, "running", "error")
|
# 只有在状态已经改为 running 的情况下才需要改为 error
|
||||||
|
try:
|
||||||
|
update_file_status(username, "running", "error")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
return f"❌ {username} 执行异常: {str(e)}"
|
return f"❌ {username} 执行异常: {str(e)}"
|
||||||
|
|
||||||
def monitor_center():
|
def monitor_center():
|
||||||
|
|||||||
@@ -1,4 +1 @@
|
|||||||
CZSCZQ-13A-二工区-沙马大桥-1#墩身-山区
|
SJSG-7标-跨沿江高速特大桥-85#-89#-墩身-平原
|
||||||
CZSCZQ-13A-二工区-沙马大桥-2#墩身-山区
|
|
||||||
CZSCZQ-13A-二工区-沙马大桥-6#墩-山区
|
|
||||||
CZSCZQ-13A-二工区-沙马大桥-7#墩-山区
|
|
||||||
|
|||||||
Reference in New Issue
Block a user