#!/usr/bin/env node /** * 补充脚本:对核心页截 fullPage 长图,用于验证四层叙事完整性。 */ import { chromium } from 'playwright'; import path from 'node:path'; import fs from 'node:fs'; import { fileURLToPath } from 'node:url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const ROOT = path.resolve(__dirname, '../..'); const OUT = process.argv[2] || path.join(ROOT, 'dogfood-ui-audit', '2026-09-01T07-07-49', 'screenshots', 'fullpage'); fs.mkdirSync(OUT, { recursive: true }); const TARGETS = [ { route: '/', vp: { width: 1440, height: 900 } }, { route: '/products', vp: { width: 1440, height: 900 } }, { route: '/products/erp', vp: { width: 1440, height: 900 } }, { route: '/solutions/finance', vp: { width: 1440, height: 900 } }, { route: '/services/consulting', vp: { width: 1440, height: 900 } }, { route: '/about', vp: { width: 1440, height: 900 } }, { route: '/contact', vp: { width: 1440, height: 900 } }, { route: '/', vp: { width: 390, height: 844 } }, { route: '/products', vp: { width: 390, height: 844 } }, { route: '/contact', vp: { width: 390, height: 844 } }, ]; const BASE = process.env.AUDIT_BASE_URL || 'http://localhost:3000'; const browser = await chromium.launch({ headless: true }); for (const t of TARGETS) { const ctx = await browser.newContext({ viewport: t.vp, deviceScaleFactor: 1 }); const page = await ctx.newPage(); const slug = (t.route === '/' ? 'home' : t.route.replace(/^\//, '').replace(/\//g, '__')); const vp = t.vp.width < 500 ? 'mobile' : 'desktop'; const file = path.join(OUT, `${vp}-${slug}.png`); try { const t0 = Date.now(); await page.goto(BASE + t.route, { waitUntil: 'load', timeout: 60000 }); await page.waitForTimeout(1500); await page.screenshot({ path: file, fullPage: true }); console.log(`✓ ${file} (${Date.now() - t0}ms)`); } catch (e) { console.log(`✗ ${t.route} ${t.vp.width}x${t.vp.height}: ${e.message.slice(0, 100)}`); } await ctx.close(); } await browser.close(); console.log(`\n输出目录:${OUT}`);