// 视觉验证:打开打印页,等待 iframe 就绪 + 字体加载,截图 iframe 区域 import { createRequire } from 'module' import fs from 'fs' const PW = 'C:/Users/范先生/AppData/Roaming/npm/node_modules/@playwright/cli/node_modules/playwright-core' const require = createRequire(PW + '/package.json') const { chromium } = require(PW) const B = 'http://localhost:5136' const token = fs.readFileSync(new URL('_token.txt', import.meta.url), 'utf8').trim() const url = `http://localhost:5227/?print=1&template=2&table=RawMaterial_OutStock&row=2&token=${encodeURIComponent(token)}&api=${B}` const browser = await chromium.launch({ headless: true, channel: 'msedge' }) const page = await browser.newPage({ viewport: { width: 900, height: 500 } }) page.on('pageerror', (e) => console.log('[pageerror]', e.message)) page.on('console', (m) => { if (m.type() === 'error') console.log('[console]', m.text()) }) await page.goto(url, { waitUntil: 'networkidle', timeout: 30000 }) for (let i = 0; i < 40; i++) { const ok = await page.evaluate(() => { const f = document.querySelector('iframe') return !!(f && f.srcdoc && f.srcdoc.length > 1000) }) if (ok) break await new Promise((r) => setTimeout(r, 500)) } // 等字体与图片加载 await page.evaluate(async () => { const f = document.querySelector('iframe') if (f && f.contentDocument) { await f.contentDocument.fonts.ready.catch(() => {}) await new Promise((r) => setTimeout(r, 800)) } }) // 模拟浏览器进入打印预览/打印媒体,验证 iframe 在 @media print 下可见 await page.emulateMedia({ media: 'print' }) await page.waitForTimeout(500) await page.screenshot({ path: 'print-preview.png' }) const buf = fs.statSync('print-preview.png') console.log('SHOT_SAVED size=' + buf.size) // 用 canvas 判断内容像素比例(主页面同源 iframe 可访问) const stats = await page.evaluate(async () => { const f = document.querySelector('iframe') if (!f || !f.contentDocument) return { err: 'no-iframe' } const d = f.contentDocument const w = 210 * 96 / 25.4 // 793px const h = 99 * 96 / 25.4 // 374px const canvas = document.createElement('canvas') canvas.width = w canvas.height = h const ctx = canvas.getContext('2d') ctx.fillStyle = '#fff' ctx.fillRect(0, 0, w, h) // 将 iframe body 克隆到独立容器渲染后截图(drawWindow 不可用,改用 HTML 转图) const container = document.createElement('div') container.style.position = 'fixed' container.style.left = '0' container.style.top = '0' container.style.zIndex = '99999' container.appendChild(d.body.cloneNode(true)) document.body.appendChild(container) // 用 SVG foreignObject 序列化渲染 const svg = `
${d.body.innerHTML}
` const img = new Image() const ok = await new Promise((resolve) => { img.onload = () => resolve(true) img.onerror = () => resolve(false) img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg) }) document.body.removeChild(container) if (!ok) return { err: 'svg-fail' } ctx.drawImage(img, 0, 0, w, h) const data = ctx.getImageData(0, 0, w, h).data let nonWhite = 0 for (let i = 0; i < data.length; i += 40) { const r = data[i], g = data[i + 1], b = data[i + 2] if (r < 245 || g < 245 || b < 245) nonWhite++ } const total = Math.floor(data.length / 4 / 10) return { nonWhiteRatio: (nonWhite / total).toFixed(4) } }) console.log('PIXEL=' + JSON.stringify(stats)) await browser.close() console.log('DONE')