/** * 调试导出:点击导出按钮后,监控网络请求、页面变化、弹窗等 */ import { chromium } from 'playwright'; import { readFileSync, existsSync, mkdirSync } from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const COOKIE_FILE = path.join(__dirname, 'cookies.json'); const SS = path.join(__dirname, 'screenshots'); const BASE = 'https://www.dianxiaomi.com'; mkdirSync(SS, { recursive: true }); const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] }); const ctx = await browser.newContext({ viewport: { width: 1920, height: 1080 }, locale: 'zh-CN', userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', acceptDownloads: true, }); const page = await ctx.newPage(); // Cookie await ctx.addCookies(JSON.parse(readFileSync(COOKIE_FILE, 'utf-8'))); // 监听所有网络请求 page.on('request', req => { const url = req.url(); if (url.includes('export') || url.includes('Export') || url.includes('download') || url.includes('Download') || url.includes('导出') || url.includes('.xls') || url.includes('.csv') || url.includes('.xlsx')) { console.log(` [REQ] ${req.method()} ${url}`); if (req.postData()) console.log(` [POST] ${req.postData().substring(0, 200)}`); } }); page.on('response', async resp => { const url = resp.url(); if (url.includes('export') || url.includes('Export') || url.includes('download') || url.includes('Download') || url.includes('.xls') || url.includes('.csv')) { const ct = resp.headers()['content-type'] || ''; const cd = resp.headers()['content-disposition'] || ''; console.log(` [RESP] ${resp.status()} ${url.substring(0, 100)}`); console.log(` [CT] ${ct} [CD] ${cd}`); if (ct.includes('json') || ct.includes('text')) { try { const body = await resp.text(); console.log(` [BODY] ${body.substring(0, 500)}`); } catch {} } } }); page.on('download', d => { console.log(` [DOWNLOAD] ${d.suggestedFilename()} url=${d.url()}`); }); page.on('dialog', async d => { console.log(` [DIALOG] ${d.type()}: ${d.message()}`); await d.accept(); }); // 监听新页面/标签 ctx.on('page', p => { console.log(` [NEW PAGE] ${p.url()}`); }); // === 测试采购建议的导出 === console.log('\n=== 采购建议页面 ==='); await page.goto(`${BASE}/purchasingProposal/index.htm?state=3`, { waitUntil: 'load', timeout: 30000 }); await page.waitForTimeout(5000); // 点击"导出建议"下拉 const dropdown = await page.locator('text=导出建议').first(); await dropdown.click(); await page.waitForTimeout(1000); // 点击"导出全部" console.log('>> 点击"导出全部"...'); const exportAll = await page.locator('text=导出全部').first(); await exportAll.click(); // 等待并观察 console.log('>> 等待 15 秒观察反应...'); await page.waitForTimeout(15000); // 截图 await page.screenshot({ path: path.join(SS, 'debug-after-export-click.png'), fullPage: true }); // 检查页面变化 const alerts = await page.evaluate(() => { // 检查是否有弹窗/提示 const modals = document.querySelectorAll('.el-dialog, .modal, [class*="dialog"], [class*="modal"], [class*="popup"], [class*="toast"], [class*="message"], [class*="notify"]'); return Array.from(modals).map(m => ({ visible: m.offsetHeight > 0, text: m.textContent?.substring(0, 200), cls: m.className?.substring(0, 80), })).filter(m => m.visible); }); if (alerts.length) { console.log('\n>> 弹窗/提示:'); alerts.forEach(a => console.log(` ${a.cls}: "${a.text}"`)); } // 检查是否有 iframe const iframes = await page.$$('iframe'); console.log(`\n>> iframe 数量: ${iframes.length}`); // 查看页面当前状态 const pageText = await page.evaluate(() => document.body?.innerText?.substring(0, 3000)); console.log('\n>> 页面当前文本(前1500字):\n', pageText?.substring(0, 1500)); await page.screenshot({ path: path.join(SS, 'debug-final.png') }); // === 同样测试仓库 === console.log('\n\n=== 仓库页面 ==='); await page.goto(`${BASE}/warehouseProduct/index.htm`, { waitUntil: 'load', timeout: 30000 }); await page.waitForTimeout(5000); // 导入/导出 → 按所有页导出 const impExpBtn = await page.locator('text=导入/导出').first(); await impExpBtn.click(); await page.waitForTimeout(1500); console.log('>> 点击"按所有页导出"...'); const allPages = await page.locator('text=按所有页导出').first(); await allPages.click(); await page.waitForTimeout(3000); // 看看弹窗 await page.screenshot({ path: path.join(SS, 'debug-warehouse-dialog.png') }); // 找到并点击对话框的导出按钮 console.log('>> 查找对话框中的导出按钮...'); const dialogBtns = await page.$$eval('button', els => els.filter(el => el.offsetHeight > 0) .map(el => ({ text: el.textContent.trim(), id: el.id, cls: (el.className || '').substring(0, 60), rect: el.getBoundingClientRect(), })).filter(e => e.text.includes('导出') || e.text.includes('确认') || e.text.includes('确定')) ); console.log(' 可见导出/确认按钮:', JSON.stringify(dialogBtns, null, 2)); if (dialogBtns.length) { // 点击最后一个"导出"按钮(通常是对话框内的) const targetText = dialogBtns.find(b => b.text === '导出')?.text || dialogBtns[0].text; console.log(`>> 点击按钮: "${targetText}"`); const btn = await page.locator(`button:visible:has-text("${targetText}")`).last(); await btn.click(); console.log('>> 等待 15 秒...'); await page.waitForTimeout(15000); await page.screenshot({ path: path.join(SS, 'debug-warehouse-after-confirm.png') }); // 再次检查弹窗 const alerts2 = await page.evaluate(() => { const modals = document.querySelectorAll('.el-dialog, .modal, [class*="dialog"], [class*="message"], [class*="notify"], [class*="toast"]'); return Array.from(modals).map(m => ({ visible: m.offsetHeight > 0, text: m.textContent?.substring(0, 300), })).filter(m => m.visible); }); if (alerts2.length) { console.log('\n>> 点击后弹窗:'); alerts2.forEach(a => console.log(` "${a.text}"`)); } } await browser.close(); console.log('\n>> 完成');