119 lines
4.6 KiB
Python
119 lines
4.6 KiB
Python
import time
|
|
import os
|
|
from framework.core.base_page import BasePage
|
|
from framework.core.logger import get_logger
|
|
|
|
logger = get_logger("FileManagerPage")
|
|
|
|
class FileManagerPage(BasePage):
|
|
"""文件管理页面 POM - 纯原子操作层"""
|
|
|
|
MENU_TEXT = "数据管理"
|
|
|
|
def __init__(self, page):
|
|
self.page = page
|
|
|
|
def navigate_to(self):
|
|
"""进入页面"""
|
|
logger.info("正在切换到数据管理页面...")
|
|
self.smart_click(self.MENU_TEXT)
|
|
# 等待页面核心元素出现,确保切换完成
|
|
try:
|
|
self.page.wait_for_selector(".p-datatable, button:has-text('新建文件夹')", timeout=5000)
|
|
except:
|
|
pass
|
|
time.sleep(2)
|
|
|
|
def create_folder(self, name):
|
|
"""原子:创建文件夹"""
|
|
logger.info(f"📁 新建文件夹: {name}")
|
|
self.smart_click("新建文件夹")
|
|
self.page.fill("#folderName", name)
|
|
self.smart_click("确定", role="button")
|
|
time.sleep(1)
|
|
|
|
def enter_folder(self, name):
|
|
"""原子:双击进入文件夹"""
|
|
logger.info(f"📂 进入文件夹: {name}")
|
|
self.page.click(f"text='{name}'")
|
|
time.sleep(1)
|
|
|
|
def upload_files(self, file_paths):
|
|
"""原子:触发上传并选择文件"""
|
|
if isinstance(file_paths, str): file_paths = [file_paths]
|
|
logger.info(f"📤 准备上传文件: {file_paths}")
|
|
self.smart_click("上传")
|
|
time.sleep(0.5)
|
|
self.page.set_input_files("input[type='file']", file_paths)
|
|
|
|
def cancel_upload(self, slow_mode=True):
|
|
"""原子:在上传中途取消"""
|
|
logger.info("⏹️ 尝试取消上传任务")
|
|
if slow_mode: time.sleep(1)
|
|
try:
|
|
# 缩短超时时间,取消操作不应阻塞太久
|
|
self.smart_click("取消上传", timeout=1500)
|
|
except:
|
|
# 兜底:尝试点关闭图标或按 ESC
|
|
try:
|
|
self.page.evaluate("document.querySelector('button.p-dialog-header-close')?.click()")
|
|
self.page.keyboard.press("Escape")
|
|
except:
|
|
pass
|
|
time.sleep(1)
|
|
|
|
def wait_for_success(self, count=1):
|
|
"""原子:等待上传进度条跑完"""
|
|
logger.info(f"⏳ 等待进度达成 ({count})...")
|
|
start = time.time()
|
|
while time.time() - start < 300:
|
|
content = self.page.evaluate("() => document.querySelector('.p-dialog')?.innerText || ''")
|
|
if ("成功" in content and str(count) in content) or f"{count}/{count}" in content:
|
|
break
|
|
time.sleep(2)
|
|
time.sleep(2)
|
|
self.page.evaluate("document.querySelector('button.p-dialog-header-close')?.click()")
|
|
time.sleep(1)
|
|
|
|
def rename_item(self, old_name, new_name):
|
|
"""原子:执行行内重命名"""
|
|
logger.info(f"✏️ 重命名: {old_name} -> {new_name}")
|
|
self.page.evaluate(f"""() => {{
|
|
const row = Array.from(document.querySelectorAll('tr')).find(r => r.innerText.includes('{old_name}'));
|
|
row?.querySelector('button[aria-label="重命名"], .p-button-text')?.click();
|
|
}}""")
|
|
time.sleep(0.5)
|
|
self.page.fill("input[placeholder*='名称']", new_name)
|
|
# 强力点击确定 (支持文本、类名、角色)
|
|
self.smart_click("确定", role="button")
|
|
time.sleep(1)
|
|
|
|
def delete_item(self, name):
|
|
"""原子:执行行内删除"""
|
|
logger.info(f"🗑️ 删除: {name}")
|
|
self.page.evaluate(f"""() => {{
|
|
const row = Array.from(document.querySelectorAll('tr')).find(r => r.innerText.includes('{name}'));
|
|
if (!row) return;
|
|
const delBtn = row.querySelector('button[aria-label="删除"]') ||
|
|
Array.from(row.querySelectorAll('button')).find(b => b.innerText.includes('删除'));
|
|
delBtn?.click();
|
|
}}""")
|
|
time.sleep(1) # 等待弹窗动画完成
|
|
|
|
# 针对确认框的多种可能属性进行强力点击
|
|
try:
|
|
self.smart_click("确定", role="button", timeout=3000)
|
|
except:
|
|
# 兜底:直接寻找 PrimeVue 或 通用确认框的“接受”按钮类
|
|
self.page.evaluate("""() => {
|
|
const ok = document.querySelector('.p-confirm-dialog-accept, .p-dialog-footer button:last-child, .btn-primary');
|
|
if (ok) ok.click();
|
|
}""")
|
|
time.sleep(1)
|
|
|
|
def back_to_root(self):
|
|
"""原子:通过面包屑返回"""
|
|
logger.info("🔙 返回根目录")
|
|
self.smart_click("数据管理", timeout=2000)
|
|
time.sleep(1)
|