第一次

This commit is contained in:
dengqichen 2025-03-06 09:27:38 +08:00
parent 67149da27a
commit 08910deeed

View File

@ -263,224 +263,6 @@ class LongiMainPage extends BasePage {
}
}
/**
* 通过索引查找菜单项
* @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 handleAllMenuClicks(menuItems) {
for (let i = 0; i < menuItems.length; i++) {
await this.handleSingleMenuClick(menuItems[i]);
@ -547,6 +329,33 @@ class LongiMainPage extends BasePage {
}
}
/**
* 执行内存回收
* @param {string} context 执行内存回收的上下文信息用于日志
* @returns {Promise<void>}
* @private
*/
async cleanupMemory(context = '') {
try {
await this.page.evaluate(() => {
// 清理DOM中的临时元素
const cleanup = () => {
const elements = document.querySelectorAll('.el-loading-mask, .el-message, .el-message-box');
elements.forEach(el => el.remove());
// 如果浏览器支持手动垃圾回收,则执行
if (window.gc) {
window.gc();
}
};
cleanup();
});
console.log(`🧹 执行内存回收${context ? ` - ${context}` : ''}`);
} catch (error) {
console.warn('执行内存回收时出错:', error.message);
}
}
async handleSingleMenuClick(menu) {
try {
await this.expandSideMenu();
@ -566,20 +375,7 @@ class LongiMainPage extends BasePage {
}
// 执行内存回收
await this.page.evaluate(() => {
// 清理DOM中的临时元素
const cleanup = () => {
const elements = document.querySelectorAll('.el-loading-mask, .el-message, .el-message-box');
elements.forEach(el => el.remove());
// 如果浏览器支持手动垃圾回收,则执行
if (window.gc) {
window.gc();
}
};
cleanup();
});
console.log(`🧹 执行内存回收 - ${menu.text}`);
await this.cleanupMemory(menu.text);
} catch (error) {
console.error(`处理菜单失败 [${menu.text}]:`, error.message);
@ -723,58 +519,59 @@ class LongiMainPage extends BasePage {
* @param {Object} menu 菜单对象
*/
async handleThreeLevelMenu(menu) {
try {
console.log(`正在处理 ${menu.text} 菜单`);
await menu.element.click();
console.log(`处理三级菜单: ${menu.text}`);
// 等待一个短暂的时间让弹出层出现
await this.page.waitForTimeout(500);
// 1. 点击展开三级菜单
await menu.element.click();
await this.page.waitForTimeout(500);
// 获取三级菜单列表
const thirdMenus = await this.getThirdLevelMenus(menu);
// 2. 获取三级菜单列表
const thirdMenus = await this.getThirdLevelMenus(menu);
if (thirdMenus.length === 0) {
console.log(`未找到三级菜单项`);
return;
}
// 这里可以根据需要处理三级菜单项
for (const thirdMenu of thirdMenus) {
await this.handleMenuClick(thirdMenu, menu);
// 3. 处理每个三级菜单项
for (let i = 0; i < thirdMenus.length; i++) {
const thirdMenu = thirdMenus[i];
console.log(`处理第 ${i + 1}/${thirdMenus.length} 个三级菜单项: ${thirdMenu.text}`);
// 如果不是最后一个菜单项,需要重新点击父菜单展开三级菜单
if (thirdMenu !== thirdMenus[thirdMenus.length - 1]) {
await menu.element.click();
await this.page.waitForTimeout(500);
}
await this.handleMenuClick(thirdMenu, menu);
// 如果还有下一个菜单项,重新展开三级菜单
if (i < 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 {Object} menuInfo 菜单信息对象
* @param {Object} parentMenu 父级菜单可选
* @returns {Promise<boolean>} 处理是否成功
*/
async handleMenuClick(menuInfo, parentMenu) {
try {
const menuPath = parentMenu.text ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text;
console.log(`🔸 点击菜单: ${menuPath}`);
await menuInfo.element.click();
// 等待页面加载
const loadResult = await this.waitForPageLoadWithRetry(menuInfo);
if (loadResult) {
// 处理所有TAB页
await this.handleAllTabs(menuInfo);
async handleMenuClick(menuInfo, parentMenu = null) {
const menuPath = parentMenu ? `${parentMenu.text} > ${menuInfo.text}` : menuInfo.text;
console.log(`点击菜单: ${menuPath}`);
// 关闭标签页
await this.closeActiveTab(menuPath);
}
return true;
} catch (error) {
console.error(`处理菜单点击失败 [${menuInfo.text}]:`, error.message);
// 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;
}
/**
@ -792,14 +589,7 @@ class LongiMainPage extends BasePage {
// 直接使用传入的element点击
await tabInfo.element.click();
// 等待页面加载
const loadResult = await this.waitForPageLoadWithRetry(parentMenu, tabInfo.text);
if (!loadResult) {
console.warn('页面加载失败');
return false;
}
return true;
return !await this.waitForPageLoadWithRetry(parentMenu, tabInfo.text);
} catch (error) {
console.error(`处理TAB页失败 [${parentMenu.text} > ${tabInfo.text}]:`, error.message);
return false;
@ -851,6 +641,7 @@ class LongiMainPage extends BasePage {
return false;
}
}
}
module.exports = LongiMainPage;