优化分批执行点击菜单

This commit is contained in:
dengqichen 2025-03-10 15:45:40 +08:00
parent f528c74656
commit 8d38687583
5 changed files with 26 additions and 269 deletions

View File

@ -7,7 +7,7 @@ IBP_PASSWORD=123456
# 测试配置 # 测试配置
TEST_DATA_DIR=test-data TEST_DATA_DIR=test-data
TEST_BATCH_SIZE=5 TEST_BATCH_SIZE=2
TEST_RETRY_COUNT=3 TEST_RETRY_COUNT=3
TEST_BATCH_INTERVAL=2000 TEST_BATCH_INTERVAL=2000
TEST_MAX_RETRY_DELAY=10000 TEST_MAX_RETRY_DELAY=10000

View File

@ -92,7 +92,7 @@ class BasePage {
*/ */
async waitForElement(selector, options = {}) { async waitForElement(selector, options = {}) {
try { try {
const element = options.firstOnly ? this.page.locator(selector).first() : this.page.locator(selector); let element = options.firstOnly ? this.page.locator(selector).first() : this.page.locator(selector);
await element.waitFor({ await element.waitFor({
state: 'visible', state: 'visible',
@ -114,7 +114,7 @@ class BasePage {
* @param {Object} options 选项 * @param {Object} options 选项
*/ */
async clickBySelector(selector, options = {}) { async clickBySelector(selector, options = {}) {
const element = await this.waitForElement(selector, options); let element = await this.waitForElement(selector, options);
await element.click(options); await element.click(options);
} }
@ -168,7 +168,7 @@ class BasePage {
* @param {Object} options 选项 * @param {Object} options 选项
*/ */
async fill(selector, value, options = {}) { async fill(selector, value, options = {}) {
const element = await this.waitForElement(selector, options); let element = await this.waitForElement(selector, options);
await element.fill(value); await element.fill(value);
} }
@ -194,22 +194,22 @@ class BasePage {
async waitForIBPPageLoadWithRetry(pageName) { async waitForIBPPageLoadWithRetry(pageName) {
console.log(`等待页面 ${pageName} 数据加载...`); console.log(`等待页面 ${pageName} 数据加载...`);
const startTime = Date.now(); let startTime = Date.now();
let retryCount = 0; let retryCount = 0;
const {maxRetries, retryInterval, stabilityDelay} = this.config.pageLoad; let {maxRetries, retryInterval, stabilityDelay} = this.config.pageLoad;
let errorMessage = null; let errorMessage = '';
try { try {
while (retryCount < maxRetries) { while (retryCount < maxRetries) {
// 检查错误状态 // 检查错误状态
const hasError = await this.checkPageError(pageName); let hasError = await this.checkPageError(pageName);
if (hasError) { if (hasError) {
errorMessage = await this.getErrorMessage(); errorMessage = await this.getErrorMessage();
break; break;
} }
// 检查加载状态 // 检查加载状态
const isLoading = await this.elementExistsBySelector(this.selectors.loadingMask); let isLoading = await this.elementExistsBySelector(this.selectors.loadingMask);
if (!isLoading) { if (!isLoading) {
await this.waitForTimeout(stabilityDelay); await this.waitForTimeout(stabilityDelay);
console.log(`✅ 页面 ${pageName} 加载完成`); console.log(`✅ 页面 ${pageName} 加载完成`);

View File

@ -33,7 +33,7 @@ class LongiMainPage extends BasePage {
thirdLevelIndicator: '.el-icon-arrow-right', thirdLevelIndicator: '.el-icon-arrow-right',
subMenuIndicator: '.el-sub-menu__icon-arrow', subMenuIndicator: '.el-sub-menu__icon-arrow',
// Tab相关 // Tab相关
tabContainer: '.workSpaceBaseTab .el-tabs__item', tabContainer: '.workSpaceBaseTab>.el-tabs__header .el-tabs__item',
activeTab: '.vab-tabs .el-tabs--card .el-tabs__item.is-active', activeTab: '.vab-tabs .el-tabs--card .el-tabs__item.is-active',
closeButton: '.el-icon.is-icon-close', closeButton: '.el-icon.is-icon-close',
tabItems: '.workSpaceBaseTab .el-tabs__item', tabItems: '.workSpaceBaseTab .el-tabs__item',
@ -388,17 +388,17 @@ class LongiMainPage extends BasePage {
* @private * @private
*/ */
async findTabInfos(menu) { async findTabInfos(menu) {
const tabs = await this.page.locator(this.selectors.tabContainer).all(); let tabs = await this.page.locator(this.selectors.tabContainer).all();
if (tabs.length === 0) { if (tabs.length === 0) {
console.log(`📝 ${menu.text} 没有TAB页`); console.log(`📝 ${menu.text} 没有TAB页`);
return []; return [];
} }
console.log(`📑 ${menu.text} 找到 ${tabs.length} 个TAB页`); console.log(`📑 ${menu.text} 找到 ${tabs.length} 个TAB页`);
const tabInfos = []; let tabInfos = [];
for (const tab of tabs) { for (const tab of tabs) {
const text = await tab.textContent(); let text = await tab.textContent();
const isActive = await tab.evaluate(el => el.classList.contains('is-active')); let isActive = await tab.evaluate(el => el.classList.contains('is-active'));
tabInfos.push({ tabInfos.push({
text: text.trim(), text: text.trim(),
element: tab, element: tab,
@ -416,7 +416,7 @@ class LongiMainPage extends BasePage {
try { try {
await this.waitForTimeout(1000); await this.waitForTimeout(1000);
const tabInfos = await this.findTabInfos(menu); let tabInfos = await this.findTabInfos(menu);
if (tabInfos.length === 0) { if (tabInfos.length === 0) {
return; return;
} }
@ -441,9 +441,10 @@ class LongiMainPage extends BasePage {
* @param {Object} parentMenu 父级菜单对象 * @param {Object} parentMenu 父级菜单对象
*/ */
async handleSingleTab(tabInfo, parentMenu) { async handleSingleTab(tabInfo, parentMenu) {
let menuPath, tabPath = '';
try { try {
const menuPath = parentMenu.path || parentMenu.text; menuPath = parentMenu.path || parentMenu.text;
const tabPath = `${menuPath} > ${tabInfo.text}`; tabPath = `${menuPath} > ${tabInfo.text}`;
await tabInfo.element.click(); await tabInfo.element.click();
await this.waitForIBPPageLoadWithRetry(tabPath); await this.waitForIBPPageLoadWithRetry(tabPath);
} catch (error) { } catch (error) {
@ -456,8 +457,8 @@ class LongiMainPage extends BasePage {
*/ */
async closeActiveTab(parentMenu) { async closeActiveTab(parentMenu) {
try { try {
const activeTab = this.page.locator(this.selectors.activeTab); let activeTab = this.page.locator(this.selectors.activeTab);
const closeButton = activeTab.locator(this.selectors.closeButton); let closeButton = activeTab.locator(this.selectors.closeButton);
if (await this.canCloseTab(activeTab, closeButton)) { if (await this.canCloseTab(activeTab, closeButton)) {
await closeButton.waitFor({state: 'visible', timeout: 5000}); await closeButton.waitFor({state: 'visible', timeout: 5000});
await this.clickByElement(closeButton); await this.clickByElement(closeButton);
@ -478,8 +479,8 @@ class LongiMainPage extends BasePage {
* @private * @private
*/ */
async canCloseTab(activeTab, closeButton) { async canCloseTab(activeTab, closeButton) {
const hasActiveTab = await activeTab.count() > 0; let hasActiveTab = await activeTab.count() > 0;
const hasCloseButton = await closeButton.count() > 0; let hasCloseButton = await closeButton.count() > 0;
return hasActiveTab && hasCloseButton; return hasActiveTab && hasCloseButton;
} }
@ -490,7 +491,7 @@ class LongiMainPage extends BasePage {
async cleanupMemory(context = '') { async cleanupMemory(context = '') {
try { try {
await this.page.evaluate((selector) => { await this.page.evaluate((selector) => {
const elements = document.querySelectorAll(selector); let elements = document.querySelectorAll(selector);
elements.forEach(el => el.remove()); elements.forEach(el => el.remove());
if (window.gc) window.gc(); if (window.gc) window.gc();
}, this.selectors.temporaryElements); }, this.selectors.temporaryElements);

View File

@ -1,254 +1,8 @@
[ [
{
"id": 1,
"text": "主数据",
"path": "主数据",
"hasThirdMenu": true
},
{
"id": 2,
"text": "业务数据",
"path": "业务数据",
"hasThirdMenu": true
},
{
"id": 3,
"text": "电池基础数据",
"path": "电池基础数据",
"hasThirdMenu": true
},
{
"id": 4,
"text": "主需求计划",
"path": "主需求计划",
"hasThirdMenu": false
},
{
"id": 5,
"text": "供需粗匹配",
"path": "供需粗匹配",
"hasThirdMenu": false
},
{
"id": 6,
"text": "产线规划",
"path": "产线规划",
"hasThirdMenu": true
},
{ {
"id": 7, "id": 7,
"text": "电池投放计划", "text": "电池投放计划",
"path": "电池投放计划", "path": "电池投放计划",
"hasThirdMenu": true "hasThirdMenu": true
},
{
"id": 8,
"text": "主生产计划",
"path": "主生产计划",
"hasThirdMenu": true
},
{
"id": 9,
"text": "基地生产计划",
"path": "基地生产计划",
"hasThirdMenu": true
},
{
"id": 10,
"text": "ATP生成和发布",
"path": "ATP生成和发布",
"hasThirdMenu": false
},
{
"id": 11,
"text": "ATP分配调整",
"path": "ATP分配调整",
"hasThirdMenu": false
},
{
"id": 12,
"text": "ATP查询",
"path": "ATP查询",
"hasThirdMenu": false
},
{
"id": 13,
"text": "产量预测",
"path": "产量预测",
"hasThirdMenu": true
},
{
"id": 14,
"text": "入库预测",
"path": "入库预测",
"hasThirdMenu": false
},
{
"id": 15,
"text": "硅片投入需求",
"path": "硅片投入需求",
"hasThirdMenu": false
},
{
"id": 16,
"text": "硅片到货需求",
"path": "硅片到货需求",
"hasThirdMenu": false
},
{
"id": 17,
"text": "硅片需求预测",
"path": "硅片需求预测",
"hasThirdMenu": false
},
{
"id": 18,
"text": "硅片缺口审视",
"path": "硅片缺口审视",
"hasThirdMenu": false
},
{
"id": 19,
"text": "电池需求数据",
"path": "电池需求数据",
"hasThirdMenu": false
},
{
"id": 20,
"text": "基地产能利用率",
"path": "基地产能利用率",
"hasThirdMenu": false
},
{
"id": 21,
"text": "电池生产计划",
"path": "电池生产计划",
"hasThirdMenu": false
},
{
"id": 22,
"text": "入库节奏基础参数",
"path": "入库节奏基础参数",
"hasThirdMenu": false
},
{
"id": 23,
"text": "入库节奏",
"path": "入库节奏",
"hasThirdMenu": false
},
{
"id": 24,
"text": "电池基地生产计划",
"path": "电池基地生产计划",
"hasThirdMenu": false
},
{
"id": 25,
"text": "电池入库比例",
"path": "电池入库比例",
"hasThirdMenu": false
},
{
"id": 26,
"text": "电池入库计划",
"path": "电池入库计划",
"hasThirdMenu": false
},
{
"id": 27,
"text": "电池要货计划",
"path": "电池要货计划",
"hasThirdMenu": false
},
{
"id": 28,
"text": "电池发货计划",
"path": "电池发货计划",
"hasThirdMenu": false
},
{
"id": 29,
"text": "jiahx测试",
"path": "jiahx测试",
"hasThirdMenu": false
},
{
"id": 30,
"text": "业务参数",
"path": "业务参数",
"hasThirdMenu": false
},
{
"id": 31,
"text": "计划对象",
"path": "计划对象",
"hasThirdMenu": false
},
{
"id": 32,
"text": "排产优先级",
"path": "排产优先级",
"hasThirdMenu": false
},
{
"id": 33,
"text": "逃生通道",
"path": "逃生通道",
"hasThirdMenu": false
},
{
"id": 34,
"text": "主需求计划",
"path": "主需求计划",
"hasThirdMenu": true
},
{
"id": 35,
"text": "电池投放",
"path": "电池投放",
"hasThirdMenu": true
},
{
"id": 36,
"text": "供需粗匹配",
"path": "供需粗匹配",
"hasThirdMenu": true
},
{
"id": 37,
"text": "ATP",
"path": "ATP",
"hasThirdMenu": true
},
{
"id": 38,
"text": "电池要发货",
"path": "电池要发货",
"hasThirdMenu": true
},
{
"id": 39,
"text": "主计划/基地计划",
"path": "主计划/基地计划",
"hasThirdMenu": true
},
{
"id": 40,
"text": "基地计划",
"path": "基地计划",
"hasThirdMenu": true
},
{
"id": 41,
"text": "产品系列(内部手工维护)",
"path": "产品系列(内部手工维护)",
"hasThirdMenu": true
},
{
"id": 42,
"text": "管理视图",
"path": "管理视图",
"hasThirdMenu": false
} }
] ]

View File

@ -1 +1,3 @@
[] [
7
]