pdf.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. const { PATH_FILES } = require('../config')
  2. const logger = require('../log/index')
  3. const puppeteer = require('puppeteer');
  4. const fs = require('fs')
  5. const path = require('path')
  6. // 生成
  7. async function initBrowser () {
  8. logger.log.debug('启动', new Date().toLocaleString())
  9. return await puppeteer.launch({
  10. headless: true,
  11. args: ['--no-sandbox', '--disable-setuid-sandbox']
  12. });
  13. }
  14. let browser = null
  15. function checkCache (fPath) {
  16. try {
  17. const fStat = fs.statSync(fPath)
  18. if (fStat) {
  19. const isFile = fStat.isFile()
  20. if (isFile) {
  21. return fPath
  22. }
  23. }
  24. return false
  25. } catch (err) {
  26. return false
  27. }
  28. }
  29. function wait(ms) {
  30. return new Promise((resolve, reject) => {
  31. setTimeout(() => {
  32. console.log("Done waiting");
  33. resolve(ms)
  34. }, ms)
  35. })
  36. }
  37. function asyncCheck(delay, step, delayFn) {
  38. return new Promise((resolve, reject) => {
  39. let attempts = 0;
  40. const maxAttempts = Math.ceil(delay / step); // 计算最大尝试次数
  41. const check = () => {
  42. delayFn().then(result => {
  43. if (result) {
  44. resolve({ result: true, type: 'check' });
  45. } else {
  46. attempts++;
  47. if (attempts > maxAttempts) {
  48. resolve({ result: false, type: 'max' });
  49. } else {
  50. // 如果还没有达到最大尝试次数,继续查询
  51. setTimeout(check, step);
  52. }
  53. }
  54. }).catch(error => {
  55. // 如果delayFn抛出错误,拒绝Promise
  56. logger.log.debug('检查页面状态失败', error)
  57. setTimeout(() => {
  58. resolve({ result: false, type: 'max-error' });
  59. }, delay)
  60. });
  61. };
  62. // 启动定时查询
  63. check();
  64. });
  65. }
  66. async function createPDFOfURL (url, config = {}) {
  67. if (!browser) {
  68. browser = await initBrowser()
  69. }
  70. config = Object.assign( {
  71. filename: '',
  72. dir: '',
  73. nocache: false,
  74. width: '950px',
  75. height: '1360px',
  76. margin: {
  77. top: 0,
  78. bottom: 0
  79. },
  80. step: 200,
  81. check: true
  82. }, config)
  83. // 文件路径
  84. const outPath = path.join(PATH_FILES, config.dir)
  85. if (!fs.existsSync(outPath)) {
  86. fs.mkdirSync(outPath);
  87. }
  88. const outConfig = Object.assign({path: `${config.filename}.pdf`, width: config.width, height: config.height,printBackground: true }, config)
  89. outConfig.path = path.join(outPath, outConfig.path)
  90. // 检查缓存
  91. if (!config.nocache) {
  92. const result = checkCache(outConfig.path)
  93. if (result) {
  94. logger.log.debug('命中缓存文件')
  95. return result
  96. }
  97. }
  98. const page = await browser.newPage();
  99. try {
  100. await page.setDefaultNavigationTimeout(0)
  101. await page.goto(url, {waitUntil: 'networkidle2'});
  102. logger.log.debug('等待生成', new Date().toLocaleString())
  103. if (config.check) {
  104. await asyncCheck(config.delay, config.step, async () => {
  105. const result = await page.evaluate(() => {
  106. return window.__PDF_LOADED__ || false
  107. })
  108. logger.log.debug('页面 __PDF_LOADED__ 状态检查', result)
  109. return result
  110. })
  111. } else {
  112. await wait(config.delay || 1000)
  113. }
  114. await page.pdf(outConfig);
  115. await page.close();
  116. logger.log.debug('当前时间', new Date().toLocaleString())
  117. return outConfig.path
  118. } catch (e) {
  119. logger.log.debug(e)
  120. await page.close();
  121. }
  122. }
  123. module.exports = createPDFOfURL