第一次
This commit is contained in:
parent
08910deeed
commit
5e1d37134e
@ -80,22 +80,16 @@ class LongiMainPage extends BasePage {
|
|||||||
* @returns {Promise<boolean>} 是否执行了展开操作
|
* @returns {Promise<boolean>} 是否执行了展开操作
|
||||||
*/
|
*/
|
||||||
async expandSideMenu() {
|
async expandSideMenu() {
|
||||||
try {
|
// 检查菜单是否已展开
|
||||||
// 检查菜单是否已展开
|
const isExpanded = await this.isMenuExpanded();
|
||||||
const isExpanded = await this.isMenuExpanded();
|
|
||||||
|
|
||||||
if (!isExpanded) {
|
if (!isExpanded) {
|
||||||
console.log('菜单未展开,点击展开');
|
console.log('菜单未展开,点击展开');
|
||||||
await this.clickExpandMenu();
|
await this.clickExpandMenu();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
// console.log('菜单已经处于展开状态');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('展开菜单时出错:', error);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,6 +109,7 @@ class LongiMainPage extends BasePage {
|
|||||||
return await this.findAndSaveMenuItems();
|
return await this.findAndSaveMenuItems();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// 文件操作错误需要被捕获并处理
|
||||||
console.error(`检查并加载菜单项时出错: ${error}`);
|
console.error(`检查并加载菜单项时出错: ${error}`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -124,16 +119,16 @@ class LongiMainPage extends BasePage {
|
|||||||
* 查找菜单项并保存到文件
|
* 查找菜单项并保存到文件
|
||||||
*/
|
*/
|
||||||
async findAndSaveMenuItems() {
|
async findAndSaveMenuItems() {
|
||||||
|
// 查找菜单项
|
||||||
|
const menuItems = await this.findMenuItems();
|
||||||
|
|
||||||
|
// 如果没有找到菜单项,则返回空数组
|
||||||
|
if (!menuItems || menuItems.length === 0) {
|
||||||
|
console.warn('未找到任何菜单项,无法保存到文件');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 查找菜单项
|
|
||||||
const menuItems = await this.findMenuItems();
|
|
||||||
|
|
||||||
// 如果没有找到菜单项,则返回空数组
|
|
||||||
if (!menuItems || menuItems.length === 0) {
|
|
||||||
console.warn('未找到任何菜单项,无法保存到文件');
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过滤掉不能序列化的element属性
|
// 过滤掉不能序列化的element属性
|
||||||
const menuItemsForSave = menuItems.map(({element, ...rest}) => rest);
|
const menuItemsForSave = menuItems.map(({element, ...rest}) => rest);
|
||||||
|
|
||||||
@ -144,8 +139,9 @@ class LongiMainPage extends BasePage {
|
|||||||
|
|
||||||
return menuItems;
|
return menuItems;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('查找并保存菜单项时出错:', error);
|
// 文件操作错误需要被捕获
|
||||||
return [];
|
console.error('保存菜单项到文件时出错:', error);
|
||||||
|
return menuItems; // 即使保存失败也返回找到的菜单项
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,79 +150,74 @@ class LongiMainPage extends BasePage {
|
|||||||
* @returns {Promise<Array>} 菜单项数组
|
* @returns {Promise<Array>} 菜单项数组
|
||||||
*/
|
*/
|
||||||
async findMenuItems() {
|
async findMenuItems() {
|
||||||
try {
|
console.log('开始查找菜单项...');
|
||||||
console.log('开始查找菜单项...');
|
|
||||||
|
|
||||||
// 等待菜单加载完成
|
// 等待菜单加载完成
|
||||||
await this.page.waitForSelector(this.selectors.sideNav, {
|
await this.page.waitForSelector(this.selectors.sideNav, {
|
||||||
timeout: parseInt(process.env.MENU_TIME_OUT || '30000', 10)
|
timeout: parseInt(process.env.MENU_TIME_OUT || '30000', 10)
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取所有菜单项
|
// 获取所有菜单项
|
||||||
const items = await this.page.locator(this.selectors.menuItems).all();
|
const items = await this.page.locator(this.selectors.menuItems).all();
|
||||||
console.log(`找到 ${items.length} 个菜单项元素`);
|
console.log(`找到 ${items.length} 个菜单项元素`);
|
||||||
const menuItems = [];
|
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();
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const item = items[i];
|
||||||
if (isVisible && text.trim()) {
|
//过滤一级菜单
|
||||||
// 检查是否有子菜单指示器
|
let isTopMenu = (await item.locator(this.selectors.firstLevelIndicator).count()) > 0;
|
||||||
const hasSubMenuIndicator = await item.evaluate(el => {
|
if (isTopMenu) {
|
||||||
return el.querySelector('.el-submenu__icon-arrow') !== null ||
|
continue;
|
||||||
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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// 获取菜单项文本
|
||||||
|
const text = await item.textContent();
|
||||||
|
|
||||||
console.log(`🔍 找到 ${menuItems.length} 个可测试的菜单项`);
|
// 检查是否是可见的菜单项
|
||||||
return menuItems;
|
const isVisible = await item.isVisible();
|
||||||
} catch (error) {
|
|
||||||
console.error('查找菜单项时出错:', error);
|
if (isVisible && text.trim()) {
|
||||||
return [];
|
// 检查是否有子菜单指示器
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -235,38 +226,62 @@ class LongiMainPage extends BasePage {
|
|||||||
* @returns {Promise<string>} 菜单路径
|
* @returns {Promise<string>} 菜单路径
|
||||||
*/
|
*/
|
||||||
async getMenuPath(menuItem) {
|
async getMenuPath(menuItem) {
|
||||||
try {
|
// 尝试获取父级菜单的文本
|
||||||
// 尝试获取父级菜单的文本
|
const parentText = await menuItem.evaluate(el => {
|
||||||
const parentText = await menuItem.evaluate(el => {
|
// 查找最近的父级菜单项
|
||||||
// 查找最近的父级菜单项
|
const parent = el.closest('.el-submenu');
|
||||||
const parent = el.closest('.el-submenu');
|
if (parent) {
|
||||||
if (parent) {
|
const parentTitle = parent.querySelector('.el-submenu__title');
|
||||||
const parentTitle = parent.querySelector('.el-submenu__title');
|
if (parentTitle) {
|
||||||
if (parentTitle) {
|
const titleSpan = parentTitle.querySelector('.titleSpan');
|
||||||
const titleSpan = parentTitle.querySelector('.titleSpan');
|
return titleSpan ? titleSpan.textContent.trim() : parentTitle.textContent.trim();
|
||||||
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 '';
|
return '';
|
||||||
|
});
|
||||||
|
|
||||||
|
const itemText = await menuItem.textContent();
|
||||||
|
return parentText ? `${parentText} > ${itemText}` : itemText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理所有菜单点击
|
||||||
|
* @param {Array} menuItems 菜单项数组
|
||||||
|
*/
|
||||||
|
async handleAllMenuClicks(menuItems) {
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < menuItems.length; i++) {
|
||||||
|
await this.handleSingleMenuClick(menuItems[i]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('处理菜单点击时出错:', error);
|
||||||
|
throw error; // 向上传播错误
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleAllMenuClicks(menuItems) {
|
/**
|
||||||
for (let i = 0; i < menuItems.length; i++) {
|
* 处理单个菜单点击
|
||||||
await this.handleSingleMenuClick(menuItems[i]);
|
* @param {Object} menu 菜单对象
|
||||||
|
*/
|
||||||
|
async handleSingleMenuClick(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行内存回收
|
||||||
|
await this.cleanupMemory(menu.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -276,57 +291,52 @@ class LongiMainPage extends BasePage {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
async restoreMenuElement(menuItem) {
|
async restoreMenuElement(menuItem) {
|
||||||
try {
|
// 获取当前页面上的所有菜单元素
|
||||||
// 获取当前页面上的所有菜单元素
|
const currentMenuElements = await this.page.locator(this.selectors.menuItems).all();
|
||||||
const currentMenuElements = await this.page.locator(this.selectors.menuItems).all();
|
let foundElement = null;
|
||||||
let foundElement = null;
|
let sameTextElements = [];
|
||||||
let sameTextElements = [];
|
|
||||||
|
|
||||||
// 首先找到所有文本匹配的元素
|
// 首先找到所有文本匹配的元素
|
||||||
for (const element of currentMenuElements) {
|
for (const element of currentMenuElements) {
|
||||||
const elementText = await element.textContent();
|
const elementText = await element.textContent();
|
||||||
if (elementText.trim() === menuItem.text) {
|
if (elementText.trim() === menuItem.text) {
|
||||||
// 检查是否是一级菜单
|
// 检查是否是一级菜单
|
||||||
const isTopMenu = await element.locator(this.selectors.firstLevelIndicator).count() > 0;
|
const isTopMenu = await element.locator(this.selectors.firstLevelIndicator).count() > 0;
|
||||||
if (!isTopMenu) {
|
if (!isTopMenu) {
|
||||||
sameTextElements.push(element);
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果找到多个同名菜单,根据是否有三级菜单来区分
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -356,30 +366,155 @@ class LongiMainPage extends BasePage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleSingleMenuClick(menu) {
|
/**
|
||||||
try {
|
* 获取三级菜单列表
|
||||||
await this.expandSideMenu();
|
* @param {Object} parentMenu 父级菜单对象
|
||||||
// 在处理菜单前重新获取最新的element
|
* @returns {Promise<Array>} 三级菜单项数组
|
||||||
menu = await this.restoreMenuElement(menu);
|
* @private
|
||||||
|
*/
|
||||||
|
async getThirdLevelMenus(parentMenu) {
|
||||||
|
// 检查三级菜单是否存在
|
||||||
|
const elements = await this.page.locator('.el-popper.is-light.el-popover .menuTitle.canClick').all();
|
||||||
|
if (elements.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
if (!menu.element) {
|
// 收集所有三级菜单项
|
||||||
console.error(`无法找到菜单项 "${menu.text}" 的element,跳过处理`);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理三级菜单
|
||||||
|
* @param {Object} menu 菜单对象
|
||||||
|
*/
|
||||||
|
async handleThreeLevelMenu(menu) {
|
||||||
|
console.log(`处理三级菜单: ${menu.text}`);
|
||||||
|
|
||||||
|
// 1. 点击展开三级菜单
|
||||||
|
await menu.element.click();
|
||||||
|
await this.page.waitForTimeout(500);
|
||||||
|
|
||||||
|
// 2. 获取三级菜单列表
|
||||||
|
const thirdMenus = await this.getThirdLevelMenus(menu);
|
||||||
|
if (thirdMenus.length === 0) {
|
||||||
|
console.log(`未找到三级菜单项`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 处理每个三级菜单项
|
||||||
|
for (let i = 0; i < thirdMenus.length; i++) {
|
||||||
|
const thirdMenu = thirdMenus[i];
|
||||||
|
console.log(`处理第 ${i + 1}/${thirdMenus.length} 个三级菜单项: ${thirdMenu.text}`);
|
||||||
|
|
||||||
|
await this.handleMenuClick(thirdMenu, menu);
|
||||||
|
|
||||||
|
// 如果还有下一个菜单项,重新展开三级菜单
|
||||||
|
if (i < thirdMenus.length - 1) {
|
||||||
|
await menu.element.click();
|
||||||
|
await this.page.waitForTimeout(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理菜单点击和页面加载
|
||||||
|
* @param {Object} menuInfo 菜单信息对象
|
||||||
|
* @param {Object} parentMenu 父级菜单(可选)
|
||||||
|
*/
|
||||||
|
async handleMenuClick(menuInfo, parentMenu = null) {
|
||||||
|
const menuPath = parentMenu ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text;
|
||||||
|
console.log(`点击菜单: ${menuPath}`);
|
||||||
|
|
||||||
|
// 1. 点击菜单并等待页面加载
|
||||||
|
await menuInfo.element.click();
|
||||||
|
const loadResult = await this.waitForPageLoadWithRetry(menuInfo);
|
||||||
|
|
||||||
|
if (!loadResult) {
|
||||||
|
console.warn(`页面加载失败: ${menuPath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 处理页面中的标签页
|
||||||
|
await this.handleAllTabs(menuInfo);
|
||||||
|
|
||||||
|
// 3. 关闭当前标签页
|
||||||
|
await this.closeActiveTab(menuPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理单个TAB页
|
||||||
|
* @param {Object} tabInfo TAB页信息对象,包含text、isActive和element属性
|
||||||
|
* @param {Object} parentMenu 父级菜单对象
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async handleSingleTab(tabInfo, parentMenu) {
|
||||||
|
try {
|
||||||
|
const menuPath = parentMenu.path || parentMenu.text;
|
||||||
|
console.log(`🔹 处理TAB页: ${menuPath} > ${tabInfo.text}`);
|
||||||
|
|
||||||
|
// 直接使用传入的element点击
|
||||||
|
await tabInfo.element.click();
|
||||||
|
await this.waitForPageLoadWithRetry(parentMenu, tabInfo.text)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`处理TAB页失败 [${parentMenu.text} > ${tabInfo.text}]:`, error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理所有TAB页
|
||||||
|
* @param {Object} menu 菜单对象
|
||||||
|
* @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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menu.hasThirdMenu) {
|
console.log(`📑 ${menu.text} 找到 ${tabs.length} 个TAB页`);
|
||||||
await this.handleThreeLevelMenu(menu);
|
|
||||||
} else {
|
// 获取所有TAB页的完整信息(文本、激活状态和元素引用)
|
||||||
// 处理二级菜单点击
|
const tabInfos = await Promise.all(
|
||||||
await this.handleMenuClick(menu);
|
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}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行内存回收
|
|
||||||
await this.cleanupMemory(menu.text);
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`处理菜单失败 [${menu.text}]:`, error.message);
|
console.error(`处理TAB页失败 [${menu.text}]:`, error.message);
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,171 +612,6 @@ class LongiMainPage extends BasePage {
|
|||||||
return false;
|
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) {
|
|
||||||
console.log(`处理三级菜单: ${menu.text}`);
|
|
||||||
|
|
||||||
// 1. 点击展开三级菜单
|
|
||||||
await menu.element.click();
|
|
||||||
await this.page.waitForTimeout(500);
|
|
||||||
|
|
||||||
// 2. 获取三级菜单列表
|
|
||||||
const thirdMenus = await this.getThirdLevelMenus(menu);
|
|
||||||
if (thirdMenus.length === 0) {
|
|
||||||
console.log(`未找到三级菜单项`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 处理每个三级菜单项
|
|
||||||
for (let i = 0; i < thirdMenus.length; i++) {
|
|
||||||
const thirdMenu = thirdMenus[i];
|
|
||||||
console.log(`处理第 ${i + 1}/${thirdMenus.length} 个三级菜单项: ${thirdMenu.text}`);
|
|
||||||
|
|
||||||
await this.handleMenuClick(thirdMenu, menu);
|
|
||||||
|
|
||||||
// 如果还有下一个菜单项,重新展开三级菜单
|
|
||||||
if (i < thirdMenus.length - 1) {
|
|
||||||
await menu.element.click();
|
|
||||||
await this.page.waitForTimeout(500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理菜单点击和页面加载
|
|
||||||
* @param {Object} menuInfo 菜单信息对象
|
|
||||||
* @param {Object} parentMenu 父级菜单(可选)
|
|
||||||
*/
|
|
||||||
async handleMenuClick(menuInfo, parentMenu = null) {
|
|
||||||
const menuPath = parentMenu ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text;
|
|
||||||
console.log(`点击菜单: ${menuPath}`);
|
|
||||||
|
|
||||||
// 1. 点击菜单并等待页面加载
|
|
||||||
await menuInfo.element.click();
|
|
||||||
const loadResult = await this.waitForPageLoadWithRetry(menuInfo);
|
|
||||||
|
|
||||||
if (!loadResult) {
|
|
||||||
console.warn(`页面加载失败: ${menuPath}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 处理页面中的标签页
|
|
||||||
await this.handleAllTabs(menuInfo);
|
|
||||||
|
|
||||||
// 3. 关闭当前标签页
|
|
||||||
await this.closeActiveTab(menuPath);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理单个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();
|
|
||||||
|
|
||||||
return !await this.waitForPageLoadWithRetry(parentMenu, tabInfo.text);
|
|
||||||
} 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;
|
module.exports = LongiMainPage;
|
||||||
Loading…
Reference in New Issue
Block a user