playwright/tests/pages/LongiMainPage.js
2025-03-05 18:21:48 +08:00

840 lines
32 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 龙蛟IBP系统主页面对象模型
*/
const BasePage = require('../utils/BasePage');
const FileUtils = require('../utils/FileUtils');
class LongiMainPage extends BasePage {
/**
* 创建主页面对象
* @param {import('@playwright/test').Page} page Playwright页面对象
*/
constructor(page) {
super(page);
// 页面元素选择器
this.selectors = {
// 侧边导航菜单 - 使用更精确的选择器
sideNav: '.ly-side-nav, .el-menu', // 主菜单
menuToggle: '.hamburger-container, .fold-btn, button.hamburger, .vab-content .toggle-icon', // 菜单展开/收起按钮,提供多个可能的选择器
menuContainer: '.el-scrollbar__view > .el-menu', // 菜单容器
menuItems: '.el-sub-menu__title, .el-menu-item', // 菜单项
menuItemText: '.titleSpan', // 菜单项文本
firstLevelIndicator: '.menuIcon', // 一级菜单指示器
thirdLevelMenu: '.el-popper.is-light.el-popover .menuTitle.canClick', // 三级菜单项
thirdLevelIndicator: '.el-icon-arrow-right', // 三级菜单指示器(箭头图标)
subMenuIndicator: '.el-sub-menu__icon-arrow' // 子菜单指示器
};
// 设置超时时间
this.timeout = 10000;
}
/**
* 检查菜单是否已展开
* @returns {Promise<boolean>} 菜单是否已展开
*/
async isMenuExpanded() {
// 获取菜单元素
const sideNav = this.page.locator(this.selectors.sideNav).first();
// 检查菜单的位置
const leftValue = await sideNav.evaluate(el => {
const style = window.getComputedStyle(el);
console.log(`菜单现在的偏移量是:${style.left}`);
return style.left;
});
// 如果left是0px说明菜单已展开
return leftValue === '0px';
}
/**
* 点击展开菜单
* @returns {Promise<void>}
*/
async clickExpandMenu() {
try {
// 尝试查找菜单切换按钮
const toggleButton = this.page.locator(this.selectors.menuToggle).first();
// 检查按钮是否可见
const isVisible = await toggleButton.isVisible().catch(() => false);
if (!isVisible) {
console.log('菜单切换按钮不可见,尝试其他方法');
// 如果按钮不可见可以尝试其他方法比如键盘快捷键或直接修改DOM
return;
}
// 点击菜单切换按钮
await toggleButton.click();
console.log('已点击展开菜单');
} catch (error) {
console.error('点击展开菜单时出错:', error);
}
}
/**
* 检查并展开侧边菜单
* 如果菜单已收起,则点击展开
* @returns {Promise<boolean>} 是否执行了展开操作
*/
async expandSideMenu() {
try {
// 检查菜单是否已展开
const isExpanded = await this.isMenuExpanded();
if (!isExpanded) {
console.log('菜单未展开,点击展开');
await this.clickExpandMenu();
return true;
} else {
// console.log('菜单已经处于展开状态');
return false;
}
} catch (error) {
console.error('展开菜单时出错:', error);
return false;
}
}
/**
* 检查菜单数据文件是否存在并加载数据
*/
async checkAndLoadMenuItems() {
try {
// 加载JSON文件
const menuItems = FileUtils.loadFromJsonFile(process.env.MENU_DATA_FILE_PATH);
// 检查是否成功加载数据
if (menuItems && Array.isArray(menuItems) && menuItems.length > 0) {
console.log(`从文件 ${process.env.BASE_URL} 成功加载了 ${menuItems.length} 个菜单项`);
return menuItems;
} else {
await this.expandSideMenu();
return await this.findAndSaveMenuItems();
}
} catch (error) {
console.error(`检查并加载菜单项时出错: ${error}`);
return null;
}
}
/**
* 查找菜单项并保存到文件
*/
async findAndSaveMenuItems() {
try {
// 查找菜单项
const menuItems = await this.findMenuItems();
// 如果没有找到菜单项,则返回空数组
if (!menuItems || menuItems.length === 0) {
console.warn('未找到任何菜单项,无法保存到文件');
return [];
}
// 过滤掉不能序列化的element属性
const menuItemsForSave = menuItems.map(({element, ...rest}) => rest);
// 保存到文件
FileUtils.saveToJsonFile(menuItemsForSave, process.env.MENU_DATA_FILE_PATH);
console.log(`已找到并保存 ${menuItems.length} 个菜单项到文件: ${process.env.MENU_DATA_FILE_PATH}`);
return menuItems;
} catch (error) {
console.error('查找并保存菜单项时出错:', error);
return [];
}
}
/**
* 查找所有菜单项
* @returns {Promise<Array>} 菜单项数组
*/
async findMenuItems() {
try {
console.log('开始查找菜单项...');
// 等待菜单加载完成
await this.page.waitForSelector(this.selectors.sideNav, {
timeout: parseInt(process.env.MENU_TIME_OUT || '30000', 10)
});
// 获取所有菜单项
const items = await this.page.locator(this.selectors.menuItems).all();
console.log(`找到 ${items.length} 个菜单项元素`);
const menuItems = [];
// 处理每个菜单项
for (let i = 0; i < items.length; i++) {
const item = items[i];
//过滤一级菜单
let isTopMenu = (await item.locator(this.selectors.firstLevelIndicator).count()) > 0;
if (isTopMenu) {
continue;
}
// 获取菜单项文本
const text = await item.textContent();
// 检查是否是可见的菜单项
const isVisible = await item.isVisible();
if (isVisible && text.trim()) {
// 检查是否有子菜单指示器
const hasSubMenuIndicator = await item.evaluate(el => {
return el.querySelector('.el-submenu__icon-arrow') !== null ||
el.querySelector('.el-icon-arrow-down') !== null;
});
// 检查是否有三级菜单指示器
const hasThirdLevelIndicator = await item.evaluate(el => {
// 检查是否有特定的三级菜单指示器
return el.classList.contains('is-opened') ||
el.querySelector('.third-level-menu') !== null ||
el.querySelector('.el-menu--inline') !== null;
});
// 检查是否是子菜单标题
const isSubMenuTitle = await item.evaluate(el => el.classList.contains('el-sub-menu__title'));
// 综合判断是否有三级菜单
const hasThirdMenu = isSubMenuTitle || hasSubMenuIndicator || hasThirdLevelIndicator;
console.log(`菜单项 "${text.trim()}" ${hasThirdMenu ? '有' : '没有'}三级菜单 (通过DOM结构判断)`);
// 生成唯一标识符,结合索引和文本
const uniqueId = `menu_${i}_${text.trim().replace(/\s+/g, '_')}`;
// 获取菜单路径
const menuPath = await this.getMenuPath(item);
menuItems.push({
index: i,
text: text.trim(),
element: item,
hasThirdMenu: hasThirdMenu,
uniqueId: uniqueId,
// 添加路径信息,帮助识别菜单层级
path: menuPath
});
}
}
console.log(`🔍 找到 ${menuItems.length} 个可测试的菜单项`);
return menuItems;
} catch (error) {
console.error('查找菜单项时出错:', error);
return [];
}
}
/**
* 获取菜单项的路径信息
* @param {Object} menuItem 菜单项元素
* @returns {Promise<string>} 菜单路径
*/
async getMenuPath(menuItem) {
try {
// 尝试获取父级菜单的文本
const parentText = await menuItem.evaluate(el => {
// 查找最近的父级菜单项
const parent = el.closest('.el-submenu');
if (parent) {
const parentTitle = parent.querySelector('.el-submenu__title');
if (parentTitle) {
const titleSpan = parentTitle.querySelector('.titleSpan');
return titleSpan ? titleSpan.textContent.trim() : parentTitle.textContent.trim();
}
}
return '';
});
const itemText = await menuItem.textContent();
if (parentText) {
return `${parentText} > ${itemText}`;
}
return itemText;
} catch (error) {
console.error('获取菜单路径时出错:', error);
return '';
}
}
/**
* 通过索引查找菜单项
* @param {number} index 菜单项索引
* @param {Array} menuItems 菜单项数组如果未提供则会调用findMenuItems获取
* @returns {Promise<Object|null>} 找到的菜单项或null
*/
async findMenuItemByIndex(index, menuItems = null) {
try {
// 如果未提供菜单项数组,则获取
if (!menuItems) {
menuItems = await this.findMenuItems();
}
// 查找指定索引的菜单项
const menuItem = menuItems.find(item => item.index === index);
if (menuItem) {
console.log(`通过索引 ${index} 找到菜单项: "${menuItem.text}"`);
return menuItem;
} else {
console.log(`未找到索引为 ${index} 的菜单项`);
return null;
}
} catch (error) {
console.error(`通过索引查找菜单项时出错: ${error}`);
return null;
}
}
/**
* 通过文本和可选的索引查找菜单项
* 当有多个同名菜单项时可以通过指定occurrence来选择第几个匹配项
* @param {string} text 菜单项文本
* @param {number} occurrence 第几个匹配项从0开始计数默认为0第一个
* @param {Array} menuItems 菜单项数组如果未提供则会调用findMenuItems获取
* @returns {Promise<Object|null>} 找到的菜单项或null
*/
async findMenuItemByText(text, occurrence = 0, menuItems = null) {
try {
// 如果未提供菜单项数组,则获取
if (!menuItems) {
menuItems = await this.findMenuItems();
}
// 查找所有匹配文本的菜单项
const matchingItems = menuItems.filter(item => item.text === text);
if (matchingItems.length > 0) {
if (occurrence < matchingItems.length) {
const menuItem = matchingItems[occurrence];
console.log(`通过文本 "${text}" 找到第 ${occurrence + 1} 个菜单项,索引为 ${menuItem.index}`);
return menuItem;
} else {
console.log(`未找到第 ${occurrence + 1} 个文本为 "${text}" 的菜单项,只有 ${matchingItems.length} 个匹配项`);
return null;
}
} else {
console.log(`未找到文本为 "${text}" 的菜单项`);
return null;
}
} catch (error) {
console.error(`通过文本查找菜单项时出错: ${error}`);
return null;
}
}
/**
* 通过唯一ID查找菜单项
* @param {string} uniqueId 菜单项的唯一ID
* @param {Array} menuItems 菜单项数组如果未提供则会调用findMenuItems获取
* @returns {Promise<Object|null>} 找到的菜单项或null
*/
async findMenuItemByUniqueId(uniqueId, menuItems = null) {
try {
// 如果未提供菜单项数组,则获取
if (!menuItems) {
menuItems = await this.findMenuItems();
}
// 查找指定唯一ID的菜单项
const menuItem = menuItems.find(item => item.uniqueId === uniqueId);
if (menuItem) {
console.log(`通过唯一ID ${uniqueId} 找到菜单项: "${menuItem.text}"`);
return menuItem;
} else {
console.log(`未找到唯一ID为 ${uniqueId} 的菜单项`);
return null;
}
} catch (error) {
console.error(`通过唯一ID查找菜单项时出错: ${error}`);
return null;
}
}
/**
* 检查是否存在三级菜单并进行相应处理
* @param {Object} menuItem 菜单项对象,包含索引、文本和元素
* @param {number} timeout 超时时间毫秒默认30秒
* @returns {Promise<{hasThirdMenu: boolean, thirdMenuItems: Array}>} 是否有三级菜单及三级菜单项数组
*/
async checkForThirdLevelMenu(menuItem, timeout = 30000) {
try {
console.log(`点击菜单项 "${menuItem.text}" 检查三级菜单...`);
// 点击菜单项,触发三级菜单弹出
await menuItem.element.click();
// 等待弹出动画完成,增加等待时间
await this.page.waitForTimeout(2000);
// 检查三级菜单
const thirdMenuSelector = this.selectors.thirdLevelMenu;
// 尝试等待三级菜单出现,但不抛出错误
const hasThirdMenu = await this.page.locator(thirdMenuSelector).count().then(count => count > 0).catch(() => false);
// 如果没有立即找到,再等待一段时间再次检查
let thirdMenuCount = 0;
if (hasThirdMenu) {
thirdMenuCount = await this.page.locator(thirdMenuSelector).count();
} else {
// 再等待一段时间,有些菜单可能加载较慢
await this.page.waitForTimeout(1000);
thirdMenuCount = await this.page.locator(thirdMenuSelector).count();
}
console.log(`菜单项 "${menuItem.text}" ${thirdMenuCount > 0 ? '有' : '没有'}三级菜单,找到 ${thirdMenuCount} 个三级菜单项`);
// 如果没有三级菜单,直接返回
if (thirdMenuCount === 0) {
return {hasThirdMenu: false, thirdMenuItems: []};
}
// 收集三级菜单项
const thirdMenuItems = [];
for (let i = 0; i < thirdMenuCount; i++) {
const item = this.page.locator(thirdMenuSelector).nth(i);
const text = await item.textContent();
thirdMenuItems.push({
index: i,
text: text.trim(),
element: item
});
}
// 输出三级菜单项文本
const menuTexts = thirdMenuItems.map(item => item.text).join(', ');
console.log(`三级菜单项: ${menuTexts}`);
return {hasThirdMenu: true, thirdMenuItems};
} catch (error) {
console.error(`检查三级菜单时出错: ${error}`);
return {hasThirdMenu: false, thirdMenuItems: []};
}
}
/**
* 处理菜单项,包括检查和处理可能的三级菜单
* @param {Object} menuItem 菜单项对象包含索引、文本和元素以及hasThirdMenu标志
* @param {Function} processWithThirdMenu 处理有三级菜单情况的回调函数
* @param {Function} processWithoutThirdMenu 处理没有三级菜单情况的回调函数
* @returns {Promise<{hasThirdMenu: boolean, thirdMenuItems: Array}>} 处理结果
*/
async processMenuItem(menuItem, processWithThirdMenu = null, processWithoutThirdMenu = null) {
try {
console.log(`处理菜单项: "${menuItem.text}"`);
// 使用菜单项中的hasThirdMenu字段
const hasThirdMenu = menuItem.hasThirdMenu;
// 点击菜单项
await menuItem.element.click();
await this.page.waitForTimeout(1000); // 等待可能的动画完成
let thirdMenuItems = [];
// 如果有三级菜单,获取三级菜单项
if (hasThirdMenu) {
const thirdMenuSelector = this.selectors.thirdLevelMenu;
const thirdMenuCount = await this.page.locator(thirdMenuSelector).count();
console.log(`菜单项 "${menuItem.text}" 有三级菜单,找到 ${thirdMenuCount} 个三级菜单项`);
// 收集三级菜单项
for (let i = 0; i < thirdMenuCount; i++) {
const item = this.page.locator(thirdMenuSelector).nth(i);
const text = await item.textContent();
thirdMenuItems.push({
index: i,
text: text.trim(),
element: item
});
}
// 输出三级菜单项文本
const menuTexts = thirdMenuItems.map(item => item.text).join(', ');
console.log(`三级菜单项: ${menuTexts}`);
} else {
console.log(`菜单项 "${menuItem.text}" 没有三级菜单`);
}
// 根据是否有三级菜单调用相应的处理函数
if (hasThirdMenu && processWithThirdMenu) {
await processWithThirdMenu(menuItem, thirdMenuItems);
} else if (!hasThirdMenu && processWithoutThirdMenu) {
await processWithoutThirdMenu(menuItem);
}
return {hasThirdMenu, thirdMenuItems};
} catch (error) {
console.error(`处理菜单项时出错: ${error}`);
return {hasThirdMenu: false, thirdMenuItems: []};
}
}
async handleAllMenus(menuItems) {
for (let i = 0; i < menuItems.length; i++) {
await this.handleSingleMenu(menuItems[i]);
}
}
/**
* 恢复菜单项的element元素
* @param {Object} menuItem 需要恢复element的菜单项
* @returns {Promise<Object>} 返回更新后的菜单项
* @private
*/
async restoreMenuElement(menuItem) {
try {
// 获取当前页面上的所有菜单元素
const currentMenuElements = await this.page.locator(this.selectors.menuItems).all();
let foundElement = null;
let sameTextElements = [];
// 首先找到所有文本匹配的元素
for (const element of currentMenuElements) {
const elementText = await element.textContent();
if (elementText.trim() === menuItem.text) {
// 检查是否是一级菜单
const isTopMenu = await element.locator(this.selectors.firstLevelIndicator).count() > 0;
if (!isTopMenu) {
sameTextElements.push(element);
}
}
}
// 如果找到多个同名菜单,根据是否有三级菜单来区分
if (sameTextElements.length > 0) {
for (const element of sameTextElements) {
// 检查是否有三级菜单指示器
const hasThirdMenu = await element.evaluate(el => {
return el.classList.contains('el-sub-menu__title') ||
el.querySelector('.el-submenu__icon-arrow') !== null;
});
if (hasThirdMenu === menuItem.hasThirdMenu) {
foundElement = element;
break;
}
}
// 如果还没找到,就用第一个匹配的元素
if (!foundElement && sameTextElements.length > 0) {
foundElement = sameTextElements[0];
}
}
if (foundElement) {
menuItem.element = foundElement;
console.log(`✅ 成功恢复菜单项 "${menuItem.text}" (${menuItem.hasThirdMenu ? '有' : '无'}三级菜单) 的element元素`);
} else {
console.warn(`⚠️ 无法恢复菜单项 "${menuItem.text}" (${menuItem.hasThirdMenu ? '有' : '无'}三级菜单) 的element元素`);
}
return menuItem;
} catch (error) {
console.error(`恢复菜单项element时出错 [${menuItem.text}]:`, error.message);
return menuItem;
}
}
async handleSingleMenu(menu) {
await this.expandSideMenu();
// 在处理菜单前重新获取最新的element
menu = await this.restoreMenuElement(menu);
if (!menu.element) {
console.error(`无法找到菜单项 "${menu.text}" 的element跳过处理`);
return;
}
if (menu.hasThirdMenu) {
await this.handleThreeLevelMenu(menu);
} else {
// 处理二级菜单点击
await this.handleMenuClick(menu);
}
}
/**
* 等待页面加载完成,带重试机制
* @param {Object} menu 菜单对象
* @param {string} subMenuText 子菜单文本(可选)
* @returns {Promise<boolean>} 页面是否加载成功
*/
async waitForPageLoadWithRetry(menu, subMenuText = '') {
const pageName = subMenuText ? `${menu.text} > ${subMenuText}` : menu.text;
const pageStartTime = Date.now();
console.log(`等待页面 ${pageName} 数据加载...`);
const config = {
maxRetries: 30,
retryInterval: 500,
stabilityDelay: 1000
};
let retryCount = 0;
try {
while (retryCount < config.maxRetries) {
// 检查页面状态
const selectors = {
loadingMask: '.el-loading-mask',
errorBox: '.el-message-box__message',
errorMessage: '.el-message--error'
};
// 检查错误状态
for (const [key, selector] of Object.entries(selectors)) {
const elements = await this.page.locator(selector).all();
if (elements.length > 0 && key !== 'loadingMask') {
const errorText = await elements[0].textContent();
console.error(`页面加载出现错误: ${pageName}, 错误信息: ${errorText}`);
return false;
}
}
// 检查加载状态
const loadingMasks = await this.page.locator(selectors.loadingMask).all();
if (loadingMasks.length === 0) {
// 加载完成,等待页面稳定
await this.page.waitForTimeout(config.stabilityDelay);
console.log(`✅ 页面 ${pageName} 加载完成`);
return true;
}
// 继续等待
retryCount++;
await this.page.waitForTimeout(config.retryInterval);
}
// 超时处理
console.error(`页面加载超时: ${pageName}, 重试次数: ${config.maxRetries}`);
return false;
} catch (error) {
// 任何错误都记录并返回false
console.error(`页面加载出错: ${pageName}, 错误信息: ${error.message}`);
return false;
}
}
/**
* 关闭当前活动的标签页
* @param {string} pageName 页面名称,用于日志显示
* @returns {Promise<boolean>} 是否成功关闭标签页
*/
async closeActiveTab(pageName) {
try {
console.log(`🗑️ 正在关闭页面 "${pageName}" 的tab...`);
// 检查是否存在活动的tab和关闭按钮
const activeTab = this.page.locator('.vab-tabs .el-tabs--card .el-tabs__item.is-active');
const closeButton = activeTab.locator('.el-icon.is-icon-close');
const hasActiveTab = await activeTab.count() > 0;
const hasCloseButton = await closeButton.count() > 0;
if (hasActiveTab && hasCloseButton) {
// 确保关闭按钮可见并点击
await closeButton.waitFor({state: 'visible', timeout: 5000});
await closeButton.click();
// 等待关闭动画完成
await this.page.waitForTimeout(500);
return true;
} else {
console.log(`⚠️ [${pageName}] 没有找到可关闭的tab继续执行...`);
return false;
}
} catch (error) {
console.error(`关闭标签页时出错 [${pageName}]:`, error.message);
return false;
}
}
/**
* 获取三级菜单列表
* @param {Object} parentMenu 父级菜单对象
* @returns {Promise<Array>} 三级菜单项数组
* @private
*/
async getThirdLevelMenus(parentMenu) {
try {
// 检查三级菜单是否存在
const elements = await this.page.locator('.el-popper.is-light.el-popover .menuTitle.canClick').all();
if (elements.length === 0) {
return [];
}
// 收集所有三级菜单项
const thirdMenus = [];
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
const text = await element.textContent();
thirdMenus.push({
index: i,
text: text.trim(),
element: element,
hasThirdMenu: false, // 三级菜单项不会有下一级
uniqueId: `menu_${parentMenu.uniqueId}_${i}_${text.trim().replace(/\s+/g, '_')}`,
path: `${parentMenu.text} > ${text.trim()}`
});
}
return thirdMenus;
} catch (error) {
console.error(`获取三级菜单失败: ${error.message}`);
return [];
}
}
/**
* 处理三级菜单
* @param {Object} menu 菜单对象
*/
async handleThreeLevelMenu(menu) {
try {
console.log(`正在处理 ${menu.text} 菜单`);
await menu.element.click();
// 等待一个短暂的时间让弹出层出现
await this.page.waitForTimeout(500);
// 获取三级菜单列表
const thirdMenus = await this.getThirdLevelMenus(menu);
// 这里可以根据需要处理三级菜单项
for (const thirdMenu of thirdMenus) {
await this.handleMenuClick(thirdMenu, menu.text);
// 如果不是最后一个菜单项,需要重新点击父菜单展开三级菜单
if (thirdMenu !== thirdMenus[thirdMenus.length - 1]) {
await menu.element.click();
await this.page.waitForTimeout(500);
}
}
} catch (error) {
console.error(`处理三级菜单时出错 [${menu.text}]:`, error.message);
throw error;
}
}
/**
* 通用的菜单点击和页面加载处理方法
* @param {Object} menuInfo 菜单信息对象包含text属性
* @param {string} parentText 父级菜单文本(可选)
* @returns {Promise<boolean>} 处理是否成功
*/
async handleMenuClick(menuInfo, parentText = '') {
try {
const menuPath = parentText ? `${parentText} > ${menuInfo.text}` : menuInfo.text;
console.log(`🔸 点击菜单: ${menuPath}`);
await menuInfo.element.click();
// 等待页面加载
const loadResult = await this.waitForPageLoadWithRetry(menuInfo);
if (!loadResult) {
console.warn('页面加载失败');
return false;
}
// 处理所有TAB页
await this.handleAllTabs(menuInfo);
// 关闭标签页
await this.closeActiveTab(menuPath);
return true;
} catch (error) {
console.error(`处理菜单点击失败 [${menuInfo.text}]:`, error.message);
return false;
}
}
/**
* 处理单个TAB页
* @param {Object} tabInfo TAB页信息对象包含text、isActive和element属性
* @param {Object} parentMenu 父级菜单对象
* @returns {Promise<boolean>} 处理是否成功
* @private
*/
async handleSingleTab(tabInfo, parentMenu) {
try {
const menuPath = parentMenu.path || parentMenu.text;
console.log(`🔹 处理TAB页: ${menuPath} > ${tabInfo.text}`);
// 直接使用传入的element点击
await tabInfo.element.click();
// 等待页面加载
const loadResult = await this.waitForPageLoadWithRetry(parentMenu, tabInfo.text);
if (!loadResult) {
console.warn('页面加载失败');
return false;
}
return true;
} catch (error) {
console.error(`处理TAB页失败 [${parentMenu.text} > ${tabInfo.text}]:`, error.message);
return false;
}
}
/**
* 处理所有TAB页
* @param {Object} menu 菜单对象
* @returns {Promise<boolean>} 处理是否成功
* @private
*/
async handleAllTabs(menu) {
try {
// 等待TAB容器加载
await this.page.waitForTimeout(1000);
// 使用更精确的选择器获取工作区的TAB页
const tabs = await this.page.locator('.workSpaceBaseTab .el-tabs__item').all();
if (tabs.length === 0) {
console.log(`📝 ${menu.text} 没有TAB页`);
return true;
}
console.log(`📑 ${menu.text} 找到 ${tabs.length} 个TAB页`);
// 获取所有TAB页的完整信息文本、激活状态和元素引用
const tabInfos = await Promise.all(
tabs.map(async element => ({
text: (await element.textContent()).trim(),
isActive: await element.evaluate(el => el.classList.contains('is-active')),
element: element // 保存元素引用
}))
);
// 处理每个非激活的TAB页
for (const tabInfo of tabInfos) {
// 跳过当前激活的TAB页因为它已经是默认加载的
if (!tabInfo.isActive) {
await this.handleSingleTab(tabInfo, menu);
} else {
console.log(`⏭️ 跳过当前激活的TAB页: ${menu.text} > ${tabInfo.text}`);
}
}
return true;
} catch (error) {
console.error(`处理TAB页失败 [${menu.text}]:`, error.message);
return false;
}
}
}
module.exports = LongiMainPage;