#!/usr/bin/env node /** * 调试前端页面,查看具体的页面内容和问题 */ const { chromium } = require('playwright'); async function debugFrontend() { console.log('🔍 开始调试前端页面...\n'); let browser; let page; try { browser = await chromium.launch({ headless: false, slowMo: 1000 }); const context = await browser.newContext({ viewport: { width: 1400, height: 900 } }); page = await context.newPage(); // 登录 console.log('🚀 登录系统...'); await page.goto('http://localhost:8891'); await page.waitForLoadState('networkidle'); await page.fill('input[type="text"]', 'admin'); await page.fill('input[type="password"]', '111111'); await page.click('button:has-text("登录")'); await page.waitForLoadState('networkidle'); // 进入姓名管理 console.log('🔍 进入姓名管理页面...'); const nameMenu = await page.locator('text=名字管理').first(); await nameMenu.click(); await page.waitForLoadState('networkidle'); // 检查当前URL const currentUrl = page.url(); console.log(`📍 当前URL: ${currentUrl}`); // 获取页面HTML内容 console.log('\n📄 页面HTML结构分析...'); const pageContent = await page.evaluate(() => { // 获取主要内容区域 const mainContent = document.querySelector('main, .main-content, .content, #app > div'); if (mainContent) { return { hasContent: true, innerHTML: mainContent.innerHTML.substring(0, 1000), // 前1000字符 classes: mainContent.className, children: Array.from(mainContent.children).map(child => ({ tagName: child.tagName, className: child.className, id: child.id, textContent: child.textContent ? child.textContent.substring(0, 100) : '' })) }; } else { return { hasContent: false, bodyHTML: document.body.innerHTML.substring(0, 1000) }; } }); console.log('📋 页面内容分析结果:'); if (pageContent.hasContent) { console.log(` ✅ 找到主内容区域`); console.log(` 📦 容器类名: ${pageContent.classes}`); console.log(` 🔢 子元素数量: ${pageContent.children.length}`); pageContent.children.forEach((child, index) => { console.log(` ${index + 1}. <${child.tagName}> class="${child.className}" - ${child.textContent.substring(0, 50)}...`); }); } else { console.log(` ❌ 未找到主内容区域`); console.log(` 📄 Body内容预览: ${pageContent.bodyHTML}...`); } // 检查是否有Vue组件 console.log('\n🔍 Vue组件检查...'); const vueInfo = await page.evaluate(() => { // 检查Vue实例 const app = document.getElementById('app'); if (app && app.__vue__) { return { hasVue: true, vueVersion: 'Vue 2', componentName: app.__vue__.$options.name || 'unknown' }; } else if (app && app._vnode) { return { hasVue: true, vueVersion: 'Vue 3', componentData: 'Vue 3 detected' }; } else { return { hasVue: false }; } }); console.log('🔧 Vue状态:'); if (vueInfo.hasVue) { console.log(` ✅ Vue检测成功: ${vueInfo.vueVersion}`); if (vueInfo.componentName) { console.log(` 📦 组件名称: ${vueInfo.componentName}`); } } else { console.log(` ❌ 未检测到Vue实例`); } // 检查网络请求 console.log('\n🌐 检查网络请求...'); // 手动触发一些API调用来看看数据 const apiTest = await page.evaluate(async () => { try { // 测试姓名模板列表API(需要认证) const listResponse = await fetch('http://localhost:3000/nameTemplate/list', { method: 'POST', headers: { 'Content-Type': 'application/json', // 这里需要token,但我们先看看是否会返回401 }, body: JSON.stringify({}) }); return { listAPI: { status: listResponse.status, statusText: listResponse.statusText, needsAuth: listResponse.status === 401 } }; } catch (error) { return { error: error.message }; } }); console.log('📡 API测试结果:'); if (apiTest.listAPI) { console.log(` - 列表API状态: ${apiTest.listAPI.status} ${apiTest.listAPI.statusText}`); console.log(` - 需要认证: ${apiTest.listAPI.needsAuth ? '是' : '否'}`); } // 查找所有可能的页面路由 console.log('\n🗺️ 检查路由结构...'); const routeInfo = await page.evaluate(() => { // 检查Vue Router const links = Array.from(document.querySelectorAll('a[href*="#"]')).map(a => ({ href: a.href, text: a.textContent?.trim() })); return { hashLinks: links.slice(0, 10), // 前10个 currentHash: window.location.hash }; }); console.log('🔗 路由信息:'); console.log(` 📍 当前Hash: ${routeInfo.currentHash}`); console.log(' 🔗 可用路由:'); routeInfo.hashLinks.forEach((link, index) => { if (link.text) { console.log(` ${index + 1}. ${link.text} -> ${link.href}`); } }); // 尝试直接访问firstName页面 console.log('\n🎯 尝试直接访问firstName页面...'); try { await page.goto('http://localhost:8891/#/nameManage/firstnameList'); await page.waitForTimeout(3000); await page.screenshot({ path: 'firstname_page_debug.png', fullPage: true }); console.log('📸 截图保存: firstname_page_debug.png'); // 再次检查页面内容 const firstnamePageContent = await page.evaluate(() => { const tables = document.querySelectorAll('table'); const buttons = document.querySelectorAll('button'); const inputs = document.querySelectorAll('input'); return { tables: tables.length, buttons: Array.from(buttons).map(b => b.textContent?.trim()).filter(t => t), inputs: Array.from(inputs).map(i => i.placeholder || i.type).filter(t => t), hasViewCard: !!document.querySelector('.view-card, view-card'), hasTableList: !!document.querySelector('.table-list, table-list') }; }); console.log('📊 firstName页面内容:'); console.log(` - 表格数量: ${firstnamePageContent.tables}`); console.log(` - 按钮: ${firstnamePageContent.buttons.join(', ')}`); console.log(` - 输入框: ${firstnamePageContent.inputs.join(', ')}`); console.log(` - view-card组件: ${firstnamePageContent.hasViewCard ? '存在' : '不存在'}`); console.log(` - table-list组件: ${firstnamePageContent.hasTableList ? '存在' : '不存在'}`); } catch (error) { console.log(`❌ 访问firstName页面失败: ${error.message}`); } console.log('\n⏰ 浏览器将保持打开10秒供观察...'); await page.waitForTimeout(10000); } catch (error) { console.error('❌ 调试失败:', error.message); } finally { if (browser) { await browser.close(); } console.log('🏁 调试结束'); } } if (require.main === module) { debugFrontend().catch(console.error); } module.exports = debugFrontend;