Node中台生成基于echats的pdf文件

87 阅读2分钟

前情提要

后台觉得生成好看的图表文件有点麻烦,想看看前端有没有好的方法

目标

前端技术生成基于echarts的pdf文件,数据读后台数据,返回pdf流文件给前端

尝试

纯前端感觉基本不可能,效率慢,适配度也不好,所以试试通过请求node去生成文件返回前端。

原理:

先生成html模板,html方便设样式,请求后台数据,填入html,再转成pdf返回给前端。 这里要使用到puppeteer,访问html再转成pdf。

Puppeteer 是一个 Node.js 库,它提供了一个高级 API 来控制 Chrome 或 Chromium 浏览器(通过 DevTools 协议)。Puppeteer 主要用于自动化操作浏览器,例如抓取网页、生成截图、生成 PDF、执行性能测试,甚至模拟用户交互等。它提供了对浏览器的无头(headless)操作,也支持在有界面模式下使用。

技术栈

  • koa:接口转发
  • axios:图表数据请求
  • puppeteer:导出pdf
  • ejs:html模板,方便填写数据

代码解析


router.get('/report/pdf', async (ctx) => {
	const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
	const data = response.data;
	const templateData = {
		title: data.title,
		chartTitle: 'Sales Data',
		xData: ['A', 'B', 'C', 'D', 'E', 'F'],
		yData: [5, 20, 36, 10, 10, 5, 10]
	}; 
 // 将数据放入html模板  const templatePath = path.join(__dirname, 'template.ejs');  
	const html = await ejs.renderFile(templatePath, templateData);
	//生成puppeteer实例 
	const browser = await puppeteer.launch({ headless: 'new' });
        const page = await browser.newPage();
	//等待html里面的网络请求完毕再setContent, html里需要下载echart的js 
	await page.setContent(html, { waitUntil: 'networkidle0' });
	try {
		const pdfBuffer = await page.pdf();    
                //也可以注释掉这个, 如果不需要本地也生成一份的话    
		await fs.writeFileSync('debug.pdf', pdfBuffer);
		await browser.close();
		ctx.set('Content-Type', 'application/pdf');
		ctx.set('Content-Disposition', 'attachment; filename=report.pdf');   
                //需要用Buffer.from转成适应浏览器的格式,    
                //page.pdf()转出来的是node的文件流,给浏览器之前要先转格式再返回    
                //不然浏览器下载之后无法打开       
           ctx.body = Buffer.from(pdfBuffer) ;
	} catch (err) {
		console.error('PDF Error:', err); ctx.status = 500; 
                ctx.body = 'PDF generation failed';
	}
});


Github Demo 地址

后来

考虑到效率问题,还是没有用node去生成,确实生成单个图表的pdf感觉也比较慢,所以只能说能但效果不好,所以这个只是个demo,真正要用还要考虑挺多坑,比如网络请求和数据请求快慢的问题,效率的问题。 Puppeteer是个很有趣的库,有兴趣可以多了解一下。