前端实现报表批量导出(html-to-image+jspdf)

1.问题描述

起初只是一个简单的报表预览和打印功能,这里使用的是vue-print-nb插件来实现打印部分页面的功能。选择报表点击查看,然后根据报表的id去获取报表的详细数据,渲染在页面。所以报表只能查看一个下载一个,现在提了一个新的需求需要批量下载这些报表,不用一个一个点。

2.单个报表下载的实现方式

实现起来很轻松,甚至不用写js代码
  1. 第一步在mian.js导入打印插件
/* 第一步在mian.js导入打印插件*/
import Print from 'vue-print-nb'
Vue.use(Print);
  1. 给打印事件触发按钮添加自定义指令v-print,并赋值要打印区域的id
<!-- 打印事件触发按钮 -->
<el-button type="text" v-print="'#printDom'" icon="el-icon-printer">打印</el-button>

<!-- 要打印的区域 -->
<div id="printDom" style="padding: 20px;"> 
   数据展示区域     
</div>

3.批量下载

批量下载需要解决的问题:

  1. 如何实现多个文件下载
  2. 如何控制页面获取到了数据并完成了渲染再下载页面,避免下载空白的文件
  3. 怎么判断文件是否下载完成,清空页面dom元素。

第一个问题解决:
通过v-for循环渲染
将通过el-tableselection-change选中方法获取到需要下载的报表的ID数组

 <!-- 批量下载结算单 -->
 <div :id="'patchPrintDom' + index" v-for="(patchInfo, index) in patchInfoList" :key="index">
       报表组件
       <statement  :id="patchInfo.id"></statement  >
 </div>

第二个问题解决:
在报表组件内通过emit在触发,父组件的打印事件。在接口数据返回之后,并给data()中属性赋值之后再emit,因为是下载是获取dom元素,还要考虑到页面更新的不及时所以还需要调用$nextTick()方法来获取页面更新之后的dom

//statement组件内部异步方法

async getDetailData(){
	const  params={
	   //...
	}
	try {
       const res = await Promise.all([saleList(params), saleDetail(params)])
        //赋值操作
        
        this.$nextTick(() => {
          setTimeout(() => {
            //延时触发emit
            this.$emit('loading', false)
          }, 1000)
        })
	 } finally {
	
	 }
}

在组件上加loading事件,调用handfill方法

 <!-- 批量下载结算单 -->
 <div :id="'patchPrintDom' + index" name="patchInfo.name" v-for="(patchInfo, index) in patchInfoList" :key="index">
       报表组件
       <statement  :id="patchInfo.id" @loading="handlefill(index)"></statement  >
 </div>

handfill方法的实现:将dom元素转为图片,再将图片添加进pdf

handlefill (index) {
      const dom = document.getElementById('patchPrintDom' + index)
      this.patchInfoList[index].visiable = false
      //  下载dom为图片
      htmlToImage.toPng(dom).then(url => {
        const img = new Image()
        img.src = url
        img.onload = function () {
          //创建一个pdf 第一个参数是横向/纵向 第二个参数是单位
          const pdf = new jsPDF('1', 'pt', [img.width, img.height])
          //addImage方法添加图片
          pdf.addImage(this, 'PNG', 0, 0, img.width, img.height, '', 'FAST')
          //如果图片高度超过pdf最大高度,就再加一页
           if(img.height>pdf.internal.pageSize.getHeight()){
            pdf.addPage()
            pdf.addImage(this, 'PNG', 0, -(pdf.internal.pageSize.getHeight()-10), img.width, img.height, '', 'FAST')
          }
          //保存的时候取name属性的值作为文件名
          pdf.save(dom.getAttribute('name') + '.pdf')
        }
      })
      //判断是否全部下载完成
      let all = this.patchInfoList.every(e => {
        return !e.visiable
      })
      //全部下载完成
      if (all) {
        this.$message.success('下载完成。')
        setTimeout(() => {
          this.patchInfoList = []
        }, 1000)
        // this.patchInfoList = []
      }

    }
Logo

前往低代码交流专区

更多推荐