// deploy/m2_probe6.js —— 卡片枚举探针(PM 使用,在远端运行) // 枚举文档中全部 .pipeline-card:props 状态 / textContent / 可见性 / 所属容器 / 挂载状态 const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 } }); const page = await ctx.newPage(); await page.goto('http://127.0.0.1:5180', { waitUntil: 'domcontentloaded' }); await page.waitForSelector('.app-shell', { timeout: 15000 }); await page.click('.new-task-btn'); await page.waitForSelector('.composer textarea', { timeout: 15000 }); await page.fill('.composer textarea', 'SPL gene family in rice'); await page.click('.send-btn'); // 等流结束 await page.waitForFunction(() => { const rootEl = document.querySelector('#app'); let n = rootEl; let app = null; while (n && !app) { if (n.__vue_app__) app = n.__vue_app__; n = n.__vueParentComponent?.parent || null; } if (!app) return false; const chat = app.config.globalProperties.$pinia._s.get('chat'); return chat && !chat.busy && chat.completedOnce; }, null, { timeout: 180000 }); await new Promise((r) => setTimeout(r, 3000)); // 揭示动画收尾 const report = await page.evaluate(() => { const cards = Array.from(document.querySelectorAll('.pipeline-card')); return cards.map((el, i) => { let vnode = el.__vueParentComponent; let props = null, compName = null; for (let d = 0; d < 6 && vnode; d++) { if (vnode.props && vnode.props.block) { props = { status: vnode.props.block.status, steps: vnode.props.block.steps.map((s) => `${s.phase}:${s.state}`).join(',') }; compName = vnode.type?.name || vnode.type?.__name || 'anon'; break; } vnode = vnode.parent; } const msgEl = el.closest('.msg'); const chatScroll = el.closest('.chat-scroll'); const style = getComputedStyle(el); const inDrawer = !!el.closest('.drawer'); const inOverlay = !!el.closest('.bench-overlay'); // 每个元素与文档根的连接性 + 是否在视口 const rect = el.getBoundingClientRect(); return { i, props, compName, text: el.textContent.slice(0, 70), display: style.display, visibility: style.visibility, opacity: style.opacity, rect: { x: Math.round(rect.x), y: Math.round(rect.y), w: Math.round(rect.width), h: Math.round(rect.height) }, inMsg: !!msgEl, msgText: msgEl ? msgEl.textContent.slice(0, 30) : null, inChatScroll: !!chatScroll, inDrawer, inOverlay, isConnected: el.isConnected, }; }); }); console.log(JSON.stringify(report, null, 2)); await browser.close(); })();