capture-screenshots.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /* eslint-disable */
  2. // 自动截图脚本:登录后逐页访问、等待加载、截图保存到 prd/汇丰银行/screenshots/
  3. // 用法:node pc/scripts/capture-screenshots.js
  4. // 前置:pc/ 下 npm run serve 已在 http://localhost:8080 运行
  5. const { chromium } = require('playwright')
  6. const path = require('path')
  7. const fs = require('fs')
  8. const BASE = 'http://localhost:8080'
  9. const OUT_DIR = path.resolve(__dirname, '../../prd/汇丰银行/screenshots')
  10. // 页面清单:{ name: 输出文件名(不带扩展名), path: 路由, step?: 多步骤页的某一步, wait?: 额外等待 ms, action?: 截图前执行的函数 }
  11. const PAGES = [
  12. // §2 借记卡权益
  13. { name: '2-1-equity-products-list', path: '/customization/hsbc/equity-products' },
  14. { name: '2-2-equity-add-step1', path: '/customization/hsbc/equity-products/add' },
  15. { name: '2-2-equity-add-step2', path: '/customization/hsbc/equity-products/add', step: 2 },
  16. { name: '2-2-equity-add-step3', path: '/customization/hsbc/equity-products/add', step: 3 },
  17. { name: '2-3-equity-edit', path: '/customization/hsbc/equity-products/edit/Q100006' },
  18. { name: '2-4-equity-view', path: '/customization/hsbc/equity-products/view/Q100001' },
  19. // §3 信用卡权益
  20. { name: '3-credit-card-equity-list', path: '/customization/hsbc/credit-card-equity' },
  21. // §6 权益审核
  22. { name: '6-audit-list', path: '/customization/hsbc/audit' },
  23. { name: '6-audit-detail', path: '/customization/hsbc/audit/AR202605150001' },
  24. // §三 人群管理
  25. { name: 'crowd-task-list', path: '/customization/hsbc/crowd-tasks' },
  26. { name: 'crowd-task-add-step1', path: '/customization/hsbc/crowd-tasks/add' },
  27. { name: 'crowd-task-add-step2', path: '/customization/hsbc/crowd-tasks/add', step: 2 },
  28. { name: 'crowd-name-list-add-step1', path: '/customization/hsbc/crowd-name-lists/add' },
  29. { name: 'crowd-name-list-add-step2', path: '/customization/hsbc/crowd-name-lists/add', step: 2 },
  30. { name: 'rule-group-list', path: '/customization/hsbc/rule-groups' },
  31. { name: 'rule-group-add-step1', path: '/customization/hsbc/rule-groups/add' },
  32. { name: 'rule-group-add-step2', path: '/customization/hsbc/rule-groups/add', step: 2 },
  33. // §四 发放计划
  34. { name: '4-grant-campaign-list', path: '/customization/hsbc/equity-grant-campaign' },
  35. { name: '4-grant-campaign-add', path: '/customization/hsbc/equity-grant-campaign/add' },
  36. // §五 页面管理
  37. { name: '5-page-home', path: '/customization/hsbc/pages/home' },
  38. { name: '5-page-zone', path: '/customization/hsbc/pages/zone' },
  39. { name: '5-page-assembly', path: '/customization/hsbc/pages/assembly' },
  40. // Channel/Campaign
  41. { name: 'channel-management', path: '/customization/hsbc/channel' },
  42. { name: 'campaign-management', path: '/customization/hsbc/campaign' },
  43. // §六 短信管理
  44. { name: '6-sms-template-list', path: '/customization/hsbc/sms-templates' },
  45. { name: '6-sms-send-record', path: '/customization/hsbc/sms-send-records' },
  46. // §七 报表中心
  47. { name: '7-points-detail', path: '/customization/hsbc/points-detail' },
  48. { name: '7-customer-equity-grant', path: '/customization/hsbc/equity-grant' },
  49. { name: '7-cash-discount-grant', path: '/customization/hsbc/cash-discount-grant' }
  50. ]
  51. async function waitDevServer() {
  52. const fetchUrl = BASE + '/'
  53. for (let i = 0; i < 60; i++) {
  54. try {
  55. const res = await fetch(fetchUrl)
  56. if (res.ok || res.status === 200) return true
  57. } catch (_) { /* not ready */ }
  58. await new Promise(r => setTimeout(r, 1000))
  59. }
  60. throw new Error('dev server 未在 60s 内就绪,请确认 npm run serve 已启动')
  61. }
  62. async function gotoStep(page, stepIdx) {
  63. // 三步骤向导(添加/编辑/规则组/客群任务)通过点击「下一步」翻到目标 step
  64. // stepIdx 是 1-based 业务步骤;首屏已是 step 1,则点击 stepIdx-1 次「下一步」
  65. for (let i = 1; i < stepIdx; i++) {
  66. const nextBtn = page.locator('button:has-text("下一步")').first()
  67. if (await nextBtn.count() === 0) break
  68. await nextBtn.click().catch(() => {})
  69. await page.waitForTimeout(400)
  70. }
  71. }
  72. ;(async () => {
  73. console.log('[1/4] 等待 dev server 就绪...')
  74. await waitDevServer()
  75. console.log(' dev server OK')
  76. console.log('[2/4] 启动 chromium...')
  77. const browser = await chromium.launch({ headless: true })
  78. // 视口宽高按 1/0.8 放大,让一屏容纳更多内容(等价于"缩放 80%"的视觉效果)
  79. const context = await browser.newContext({ viewport: { width: 1800, height: 1125 }, deviceScaleFactor: 2 })
  80. const page = await context.newPage()
  81. console.log('[3/4] 注入 token 跳过登录...')
  82. await page.goto(BASE + '/#/login', { waitUntil: 'domcontentloaded' })
  83. await page.evaluate(() => {
  84. localStorage.setItem('token', 'mock-token-' + Date.now())
  85. localStorage.setItem('username', 'admin')
  86. })
  87. console.log(`[4/4] 开始截图(共 ${PAGES.length} 张)...`)
  88. const results = []
  89. for (const item of PAGES) {
  90. const url = BASE + '/#' + item.path
  91. try {
  92. await page.goto(url, { waitUntil: 'networkidle', timeout: 15000 })
  93. } catch (_) {
  94. // networkidle 在 dev server 热更新场景下可能 timeout,降级用 domcontentloaded
  95. await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 15000 })
  96. }
  97. await page.waitForTimeout(800)
  98. if (item.step && item.step > 1) {
  99. await gotoStep(page, item.step)
  100. await page.waitForTimeout(400)
  101. }
  102. const file = path.join(OUT_DIR, item.name + '.png')
  103. await page.screenshot({ path: file, fullPage: true })
  104. const size = (fs.statSync(file).size / 1024).toFixed(0)
  105. console.log(` ✓ ${item.name}.png (${size}KB)`)
  106. results.push({ name: item.name, file })
  107. }
  108. await browser.close()
  109. console.log(`\n完成。共 ${results.length} 张,输出目录:${OUT_DIR}`)
  110. })()