init repo

This commit is contained in:
2026-04-25 21:50:03 +08:00
commit ada92373c2
124 changed files with 5292 additions and 0 deletions

174
debug-export.mjs Normal file
View File

@@ -0,0 +1,174 @@
/**
* 调试导出:点击导出按钮后,监控网络请求、页面变化、弹窗等
*/
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>> 完成');