import { chromium } from 'playwright'; const BASE = 'http://localhost:13001'; async function run() { const browser = await chromium.launch({ headless: true }); const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); // 登录 await page.goto(`${BASE}/login`, { waitUntil: 'networkidle' }); await page.waitForTimeout(1000); await page.locator('input[type="text"]').first().fill('admin'); await page.locator('input[type="password"]').first().fill('admin123'); await page.locator('button[type="submit"]').click(); await page.waitForURL('**/'); // 进入考核页(首页会显示历史记录侧栏) await page.goto(`${BASE}/assessment`, { waitUntil: 'networkidle' }); await page.waitForTimeout(3000); // 截图1:首页(含历史记录侧栏) await page.screenshot({ path: 'assessment-overview.png', fullPage: true }); console.log('📸 1/5 首页截图(含历史侧栏)保存'); // 看看历史记录里有什么 const historyInfo = await page.evaluate(() => { const items = Array.from(document.querySelectorAll('.w-80 div.space-y-3 > div')); return items.map(el => ({ text: (el.textContent || '').replace(/\s+/g, ' ').trim(), })); }); console.log('\n📋 历史记录:'); historyInfo.forEach((h, i) => console.log(` [${i+1}] ${h.text}`)); if (historyInfo.length === 0) { console.log(' 没有历史记录,可能是空状态'); await browser.close(); return; } // 点击第一条历史记录查看详情(选分数最高的那条) // 找分数最高的:解析数字 let bestIdx = 0; let bestScore = -1; historyInfo.forEach((h, i) => { const m = h.text.match(/([\d.]+)\/10/); if (m) { const s = parseFloat(m[1]); if (s > bestScore) { bestScore = s; bestIdx = i; } } }); console.log(`\n🔍 选择分数最高的记录 #${bestIdx+1} (${bestScore}/10)`); // 历史记录在右侧边栏,每条记录最右边有个查看按钮(FileText图标) const histButtons = page.locator('.w-80 div.space-y-3 > div button'); const btnCount = await histButtons.count(); console.log(` 右侧历史栏共有 ${btnCount} 个按钮`); // 每条记录有2个按钮(删除+查看),查看按钮在最后 // 第N条记录的查看按钮索引 = (N * 2 + 1) (从0开始) const viewBtnIdx = bestIdx * 2 + 1; if (viewBtnIdx < btnCount) { await histButtons.nth(viewBtnIdx).click(); await new Promise(r => setTimeout(r, 3000)); // 截图2:历史考核详情页 await page.screenshot({ path: 'assessment-history-detail.png', fullPage: true }); console.log('📸 2/5 考核详情页截图'); // 看看详情页有什么内容 const detailInfo = await page.evaluate(() => { const body = document.body.textContent || ''; const scoreMatch = body.match(/([\d.]+)\/10/g); const levelMatch = body.match(/(?:LEVEL|等级)[::]\s*(\w+)/i); const reportSection = body.includes('综合报告') || body.includes('comprehensive'); const detailSection = body.includes('每题详情') || body.includes('details'); const hasPassed = body.includes('合格') || body.includes('VERIFIED'); // 按钮文字 const btns = Array.from(document.querySelectorAll('button')) .map(b => (b.textContent || '').trim()) .filter(Boolean); return { scores: scoreMatch, level: levelMatch?.[1], reportSection, detailSection, hasPassed, btns }; }); console.log(`\n📊 得分列表: ${detailInfo.scores?.join(', ') || '无'}`); console.log(`🏆 等级: ${detailInfo.level || '未显示'}`); console.log(`✅ 合格: ${detailInfo.hasPassed ? '是' : '否'}`); console.log(`📋 每题详情: ${detailInfo.detailSection ? '✅ 有' : '❌ 无'}`); console.log(`📝 综合报告: ${detailInfo.reportSection ? '✅ 有' : '❌ 无'}`); console.log(`\n🔘 按钮列表:`); detailInfo.btns.forEach(b => console.log(` - ${b}`)); // 找"查看证书"按钮 const certBtnText = detailInfo.btns.find(b => b.includes('证书') || b.includes('Certificate') || b.includes('certificate') ); console.log(`\n🔖 证书按钮: ${certBtnText || '没找到'}`); // 如果有证书按钮,点击它 if (certBtnText) { const certBtn = page.locator('button', { hasText: /证书|Certificate|certificate/ }); if (await certBtn.isVisible().catch(() => false)) { await certBtn.click(); await new Promise(r => setTimeout(r, 2000)); // 截图3:证书弹窗 await page.screenshot({ path: 'assessment-certificate-modal.png', fullPage: true }); console.log('📸 3/5 证书弹窗截图'); // 读取证书弹窗内容 const certData = await page.evaluate(() => { // 找 portal(弹窗在 document.body 最下层) const modal = document.querySelector('.fixed.inset-0.z-\\[1000\\]'); if (!modal) return { found: false }; const text = modal.textContent || ''; const level = text.match(/(\w+)/)?.[1] || ''; const totalScore = text.match(/([\d.]+)\/10/)?.[1] || ''; const dimScores = Array.from(text.matchAll(/(\w+)\s*([\d.]+)\/10/g)) .map(m => `${m[1]}: ${m[2]}/10`); const questionCount = text.match(/题目列表[\s\S]*?#(\d+)/)?.[1] || ''; return { found: true, text: text.substring(0, 500), level, totalScore, dimScores, questionCount, }; }); if (certData.found) { console.log(`\n📜 证书内容:`); console.log(` 等级: ${certData.level}`); console.log(` 总分: ${certData.totalScore}/10`); console.log(` 维度得分: ${certData.dimScores.join(', ') || '无'}`); console.log(` 题目数: ${certData.questionCount || '未知'}`); } // 关掉弹窗 await page.keyboard.press('Escape'); await new Promise(r => setTimeout(r, 500)); } } // 看 PDF 和 Excel 导出 const hasPdf = detailInfo.btns.some(b => b.includes('PDF')); const hasExcel = detailInfo.btns.some(b => b.includes('Excel') || b.includes('excel')); console.log(`\n📄 PDF下载: ${hasPdf ? '✅ 有' : '❌ 无'}`); console.log(`📊 Excel导出: ${hasExcel ? '✅ 有' : '❌ 无'}`); } await browser.close(); console.log('\n=== 完成 ==='); } run().catch(e => { console.error('❌', e.message); process.exit(1); });