Vue 类似合同套打展示的PDF并下载

<div>
 <div
        style="width: 95%;margin:15px auto 0 auto"
        class="doc-container"
        id="doc-container"
      ></div>
  <button slot="right" effect="text" type="primary" @click="aDownload">下载</button>

</div>

 

 需要安装 pizzip,html2pdf.js 的依赖;

 npm install pizzip html2pdf.js


 import PizZip from 'pizzip'
  import html2pdf from 'html2pdf.js'
//base64Content是base64,replaceData是套打的数据流;通过接口后端返回的
async handleDoc(base64Content, replaceData) {
      try {
        const imageOpts = {
          getImage(tag) {
            const imageBinaryContent = atob(
              tag.replace(/^data:image\/(png|jpg|gif|bmp|svg|svg\+xml);base64,/, '')
            )
            const imageByteArray = new Uint8Array(imageBinaryContent.length)
            for (let i = 0; i < imageBinaryContent.length; i++) {
              imageByteArray[i] = imageBinaryContent.charCodeAt(i)
            }
            return imageByteArray
          },
          getSize() {
            return [80, 80]
          }
        }
        const binaryContent = atob(base64Content)
        const byteArray = new Uint8Array(binaryContent.length)
        for (let i = 0; i < binaryContent.length; i++) {
          byteArray[i] = binaryContent.charCodeAt(i)
        }
        // 使用 PizZip 加载字节数组
        const zip = new PizZip(byteArray)
        const doc = new window.docxtemplater()
        doc.loadZip(zip)

        // Attach ImageModule with options
        doc.attachModule(new ImageModule(imageOpts))

        // Render the document (Replace {first_name} by John, {last_name} by Doe, ...)
        doc.render(replaceData)
        this.outBlob = doc.getZip().generate({
          type: 'blob',
          mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
        })
        this.docx = URL.createObjectURL(this.outBlob)
        setTimeout(() => {
          docx.renderAsync(this.outBlob, document.getElementById('doc-container')).then(x => {
            console.log('docx: finished')
            this.addWatermarksSystematically();
          })
        }, 100)
      } catch (err) {
        rt.showErrorToast(err.message || this.$_t('service.Error', 'Error'))
        rt.hideLoadingToast()
      }
    },
//添加水印
 addWatermarksSystematically() {
      const container = document.getElementById('doc-container')
      if (!container) return

      // 清除旧水印
      const oldWatermarks = container.querySelectorAll('.watermark-element')
      oldWatermarks.forEach(wm => wm.remove())

      // 计算页面数量(更精确的方法)
      const pageHeight = 1122 // A4纸像素高度近似值(根据您的scale调整)
      const contentHeight = container.scrollHeight
      let pageCount = Math.ceil(contentHeight / pageHeight)
      pageCount = Math.floor(pageCount / 2)
      // 均匀分布水印
      for (let i = 0; i < pageCount; i++) {
        const top = pageHeight * (i + 0.5) // 每页中间位置
        this.addWatermark('doc-container', this.languageMap[this.language].title, `${top}px`)
      }
    },
    addWatermark(containerId, watermarkText, top) {
      const container = document.getElementById(containerId)
      if (!container) return

      const watermark = document.createElement('div')
      watermark.className = 'watermark-element' // 添加类名便于管理

      // 增强样式
      Object.assign(watermark.style, {
        position: 'absolute',
        top: top,
        left: '0',
        width: '100%',
        height: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        pointerEvents: 'none',
        zIndex: '2147483647', // 最大z-index
        color: 'rgba(200, 200, 200, 0.7)',
        fontSize: '80px', // 增大字号
        transform: 'rotate(-45deg)',
        fontFamily: 'Arial,',
        overflow: 'hidden'
      })

      watermark.textContent = watermarkText
      container.style.position = 'relative'
      container.appendChild(watermark)

      // 强制重绘
      void watermark.offsetHeight

      // 显示水印
      watermark.style.opacity = '1'
    },
   aDownload() {
      try {
        // 显示加载中状态
        console.log('正在生成PDF,请稍候...')
        // 配置选项
        const opt = {
          margin: 10,
          filename: `contract_${new Date().getTime()}.pdf`,
          image: {
            type: 'jpeg',
            quality: 0.98
          },
          html2canvas: {
            scale: 2, // 提高分辨率
            logging: false,
            useCORS: true, // 解决图片跨域问题
            allowTaint: true
          },
          jsPDF: {
            unit: 'mm',
            format: 'a4',
            orientation: 'portrait',
            // 确保中文支持
            hotfixes: ['px_scaling']
          }
        }

        // 获取要导出的元素
        const element = document.getElementById('doc-container')

        // 生成PDF
        await html2pdf()
          .set(opt)
          .from(element)
          .save()
        console.log('PDF导出成功!')
      } catch (error) {
        console.error('导出PDF失败:', error)
      }
    },

 

posted @ 2025-05-22 17:31  Fly_bokeyuan  阅读(11)  评论(0)    收藏  举报