El JsPDF html2canvas del front-end vue genera pdf y lo carga en el back-end como un flujo de archivos

1. Primero introduce htmlToPdf.js en el archivo

Este código presenta html2canvas y jspdf
//需要 npm i html2Canvas 和 npm i jspdf

Aquí, monte la función getPdf en el prototipo de Vue y, finalmente, devuelva un objeto de promesa (incluido el base64Pdf resuelto para facilitar el procesamiento), y luego se puede realizar en el componente local para cargar el backend y otras operaciones.

El código del complemento es el siguiente

import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {
    
    
  install(Vue, options) {
    
    
    /**
     * 
     * @param {*} reportName 下载时候的标题
     * @param {*} isDownload  是否下载默认为下载,传false不下载
     */
    Vue.prototype.getPdf = function (reportName, isDownload = true) {
    
    
      //     var target = document.getElementsByClassName("right-aside")[0];
      // target.style.background = "#FFFFFF";
      return new Promise((resolve, reject) => {
    
    
        var title = reportName;
        html2Canvas(document.querySelector('#pdfDom'), {
    
    
          allowTaint: true
        }).then((canvas) => {
    
    
          let contentWidth = canvas.width
          let contentHeight = canvas.height
          //一页pdf显示html页面生成的canvas高度;
          let pageHeight = contentWidth / 592.28 * 841.89
          //未生成pdf的html页面高度
          let leftHeight = contentHeight
          //页面偏移
          let position = 0
          //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
          let imgWidth = 595.28
          let imgHeight = 592.28 / contentWidth * contentHeight
          let pageData = canvas.toDataURL('image/jpeg', 1.0)
          let PDF = new JsPDF('', 'pt', 'a4')
          //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
          //当内容未超过pdf一页显示的范围,无需分页
          if (leftHeight < pageHeight) {
    
    
            PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
          } else {
    
    
            while (leftHeight > 0) {
    
    
              PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
              leftHeight -= pageHeight
              position -= 841.89
              //避免添加空白页
              if (leftHeight > 0) {
    
    
                PDF.addPage()
              }
            }
          }
          if (isDownload) {
    
    
            PDF.save(title + '.pdf')
          }
          // 删除本地存储的base64字段
          var pdfData = PDF.output('datauristring')//获取base64Pdf
          resolve(pdfData)
        }
        )
      })
    }
  }
}

A continuación, importe directamente el archivo de código ahora mismo en main.js

import htmlToPdf from '@/utils/htmlToPdf'

En componentes parciales, cuando esté listo para descargar

  <button @click="toGetPdf(0)">下载PDF</button>//这种情况是只下载,不上传后端
  <button @click="toGetPdf(1, 0)">下载PDF</button>//这种情况是只走上传后端接口,不下载
 toGetPdf(val = false, download = true) {
    
    
      /**
     * val 决定走不走上传接口,默认为不上传给后端
     * download 默认是下载
     * /
 
      /* */
      this.$nextTick(() => {
    
    
        setTimeout(() => {
    
    
          window.scrollTo(0, 0);     //这行代码很重要,它让页面的滚动条跳到了最上方如果点击打印按钮的时候,滚动条没有在最上方,打印内容会是不完整的,体验也会差
          let title ="个人报告"
          this.getPdf(title, download) //download:false为不下载,这里调用了刚刚引用的全局函数,.then得到的值是base64位的pdf文件
            .then((res) => {
    
    
              if (val) {
    
    
                console.log("准备上传");
                this.UploadPdf(res);
              } else {
    
    
                console.log("不上传");
              }
            });
        }, 1000);
      });
    },

Las siguientes dos funciones son la interfaz para cargar archivos y la función para convertir base64 en flujos de archivos.

Dado que el bit base64 de pdf requiere al menos 1M, es un poco grande para pasarlo al backend, por lo que el frontend lo convierte en un flujo de archivos formData y lo pasa al backend

//上传pdf接口
    UploadPdf(res) {
    
    
     //res拿到base64的pdf
      let pdfBase64Str = res;
      let title ="上传给后端的个人报告"
      var myfile = this.dataURLtoFile(pdfBase64Str, title + ".pdf");//调用一下下面的转文件流函数
      var formdata = new FormData();
      formdata.append("file", myfile); // 文件对象
      //该uploadMy为接口,直接以formdata格式传给后台
      uploadMy(formdata)
        .then((res) => {
    
    
          console.log("上传pdf接口", res);
        })
        .catch((err) => {
    
    
          console.log("上传pdf接口", err);
        });
    },
    
/*
将base64转换为文件,接收2个参数,第一是base64,第二个是文件名字
最后返回文件对象
*/
   dataURLtoFile(dataurl, filename) {
    
    
      var arr = dataurl.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
    
    
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, {
    
     type: mime });
    },

Cabe señalar que el encabezado de solicitud del archivo cargado es 'Content-Type': 'multipart/form-data', post request.

Parte del código en el archivo de interfaz de solicitud de red a continuación es un registro personal, no aplicable a todos los proyectos, y es parte del código.
Por lo general, es suficiente hacer una descarga de pdf con el código anterior, que se puede ignorar a continuación

//api/index.js文件:

import $request from '@/utils/http'
let baseUrl = '/api/test'


if (process.env.NODE_ENV === 'development') {
    
    
  baseUrl = '/dev'
  bigDataUrl = '/service'
  collectUrl = '/collect'
}
// 上传文件-个人
export function uploadMy(data) {
    
    
  return $request.postUpload(baseUrl + '/common/upload', data)
}


//@/utils/http.js文件
import axios from './request'
/** post请求 lcl编写 请求头为上传的请求头*/
function postUpload(url, data,config) {
    
    
  return new Promise((resolve, reject) => {
    
    
    axios.post(url, data, config?config:{
    
    
     headers: {
    
    
        // 'Content-Type': 'application/x-www-form-urlencoded'
        'Content-Type': 'multipart/form-data'
      }
    }).then((res) => {
    
    
      // if (res.data.code === '801' || res.data.code === '802' || res.data.code === '804') {
    
    
      //   removeToken()
      //   router.push({ name: 'login' })
      // }
      resolve(res.data)
    }).catch((err) => {
    
    
      reject(err)
    })
  })
}



//@/utils/request.js文件

import axios from 'axios'
// import { Message, MessageBox } from 'element-ui'
import store from '@/store'
import {
    
     getToken, removeToken} from '@/utils/auth'

// create an axios instance

const service = axios.create({
    
    
  // baseURL: process.env.VUE_APP_APIURL, 
  // baseURL: "/api/test", 
  timeout: 20000 // request timeout  超过20s则失败
})

// request interceptor
service.interceptors.request.use(
  config => {
    
    
    // Do something before request is sent
    // 让每个请求携带token-- ['Token']为自定义key 请根据实际情况自行修改
    if(store.getters.token) {
    
    
      config.headers['Authorization'] = store.getters.token
    }
    return config
  },
  error => {
    
    
    Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  // response => response,
  /**
   * 下面的注释为通过在response里,自定义code来标示请求状态
   * 当code返回如下情况则说明权限有问题,登出并返回到登录页
   * 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
   * 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
   */

  response => {
    
    
    const res = response.data
    if (res.code !== 200 && res.code !== 204) {
    
    
      // Message({
    
    
      //   message: res.msg,
      //   type: 'error',
      //   duration: 5 * 1000
      // })
      if (res.code === 401  || res.code === 501 || res.code === 804) {
    
    
        // 请自行在引入 MessageBox
        // import { Message, MessageBox } from 'element-ui'
        // MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
    
    
        //   confirmButtonText: '重新登录',
        //   cancelButtonText: '取消',
        //   type: 'warning'
        // }).then(() => {
    
    
          removeToken();
          location.reload();
          store.dispatch('FedLogOut').then(() => {
    
    
            location.reload() // 为了重新实例化vue-router对象 避免bug
          });
          
        // })
      }
      return Promise.reject(res)
    } else {
    
    
      return response
    }
  },
  error => {
    
    
    // Message({
    
    
    //   message: error.msg,
    //   type: 'error',
    //   duration: 5 * 1000
    // })
    return Promise.reject(error)
  }
)

export default service

Lo anterior es usar JsPDF y html2canvas para tomar capturas de pantalla primero, generar pdf y subirlo al backend en forma de flujo de archivo. El pdf generado predeterminado es tamaño de papel A4.

Supongo que te gusta

Origin blog.csdn.net/qq_38594056/article/details/118212082
Recomendado
Clasificación