vue nuxt 导出Word携带表格 表格遍历tabelData表格中包含图片

vue nuxt 导出Word携带表格 表格遍历tabelData表格中包含图片

world模板在这里插入图片描述

导出效果

在这里插入图片描述

导入插件包

import FileSaver from 'file-saver'
import JSZip from 'jszip'
import ImageModule from 'docxtemplater-image-module-free'
import Pizzip from 'pizzip'
import Docxtemplater from 'docxtemplater'

实现过程

表格里面的图片需要转换成baseB64

// 数据 (模板字段太多,这边缩略成两个示例字段,我这边图片是附件ids)
const tableData = [
	{
		name:"测试1",
		currentPhotoIds: "39ffd7d5-488c-6979-ac5a-0c462d6912dd,39ffd703-0bb5-a989-ce87-bd7065958685"
	},
	{
		name:"测试2",
		currentPhotoIds: "39ffd703-0bb5-a989-ce87-bd7065958685"
	}
]
// 去获取图片地址并转换成base64 这边的arr= tableData 
async getImageUrl(arr: any) {
    const dataArr = []
    let i = 0
    for (let item of arr) {
      i++
      item.index = i // 添加序号
      let idArr = []
      if (item.currentPhotoIds && item.currentPhotoIds !== '') {
        idArr = item.currentPhotoIds.split(',')
      }
      item.image = []
      for (let ele of idArr) {
      // 判断id 是否正确
        var reg = new RegExp(
          '[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}'
        )
        if (reg.test(ele)) {
        // 获取图片下载地址
          const res: any = await this.getPhotoUrl(ele)
          if (!res.response) {
          // 这边因为图片地址做了代理 所以要替换成配置的代理格式
            const url = res.downloadUrl.replace(
              'xmgis/api/file-management',
              'file-xmgis-api/file-management'
            )
            // 转换成base64
            const base64 = await this.toBase64(url)

            item.image.push({ url: base64 })
          }
        }
      }
      dataArr.push(item)
    }
    this.tableData = dataArr
  }
  // 转换成base64
  toBase64(url: string) {
    return new Promise((resolve, reject) => {
      let image = new Image()
      //解决跨域问题
      image.setAttribute('crossOrigin', 'anonymous')
      image.src = url

      //image.onload为异步加载
      image.onload = () => {
      // 需要在页面添加一个隐藏的canves
      // <canvas ref="headCanvas" v-show="false" ></canvas>
        var canvas: any = this.$refs.headCanvas as Vue
        var context = canvas.getContext('2d')
        canvas.width = image.width
        canvas.height = image.height
        context.drawImage(image, 0, 0, image.width, image.height)
        var dataurl = canvas.toDataURL('image/png')
        console.log(dataurl)
        resolve(dataurl)
      }
    })
  }
// 读取word模板数据
  getBaseData(url: string, callback: any) {
    let xmlhttp: any = null
    if (window.XMLHttpRequest) {
      xmlhttp = new window.XMLHttpRequest()
    } else {
      const win: any = window
      xmlhttp = new win.ActiveXObject('Microsoft.XMLHTTP')
    }
    xmlhttp.open('GET', url, true)
    xmlhttp.withCredentials = true

    if ('responseType' in xmlhttp) {
      xmlhttp.responseType = 'arraybuffer'
    }

    // older browser
    if (xmlhttp.overrideMimeType) {
      xmlhttp.overrideMimeType('text/plain; charset=x-user-defined')
    }
    xmlhttp.onreadystatechange = function () {
      let file, err
      if (xmlhttp.readyState === 4) {
        if (xmlhttp.status === 200 || xmlhttp.status === 0) {
          file = null
          err = null
          try {
            file = xmlhttp.response || xmlhttp.responseText
          } catch (e: any) {
            err = new Error(e)
          }
          callback(err, file)
        } else {
          callback(new Error('读取word模板错误'), null)
        }
      }
    }

    xmlhttp.send()
  }
  // 导出world
async exportWorld() {
    await this.getImageUrl(this.tableData)
    // 这个是模板的地址 nuxt项目发给在static里面直接/文件就行 vue项目放在static或者public里面需要/static/文件名
    const fileUrl =
      this.address === '仅导出地址信息'
        ? '/world_template.docx'
        : '/world_template_point.docx'

    this.getBaseData(fileUrl, (error: any, content: any) => {
      // url是模板地址。我们在导出的时候,会根据此模板来导出对应的数据
      // 抛出异常
      if (error) {
        throw error
      }
      function base64DataURLToArrayBuffer(dataURL: string) {
        const base64Regex = /^data:image\/(png|jpg|svg|svg\+xml);base64,/
        if (!base64Regex.test(dataURL)) {
          return false
        }
        const stringBase64 = dataURL.replace(base64Regex, '')
        let binaryString
        if (typeof window !== 'undefined') {
          binaryString = window.atob(stringBase64)
        } else {
          binaryString = Buffer.from(stringBase64, 'base64').toString('binary')
        }
        const len = binaryString.length
        const bytes = new Uint8Array(len)
        for (let i = 0; i < len; i++) {
          const ascii = binaryString.charCodeAt(i)
          bytes[i] = ascii
        }
        return bytes.buffer
      }
      const opts: any = {}
      opts.fileType = 'docx'
      opts.centered = false
      opts.getImage = function (tagValue: any) {
        return base64DataURLToArrayBuffer(tagValue)
      }
      opts.getSize = function () {
        const width = 40
        const height = 40
        return [width, height]
      }

      const imageModule = new ImageModule(opts)

      // 创建一个JSZip实例,内容为模板的内容
      const zip = new Pizzip(content)
      // 创建并加载docxtemplater实例对象
      const doc = new Docxtemplater().attachModule(imageModule).loadZip(zip)
      // 设置模板变量的值
      const worldData: any = {
        tableData: this.tableData,
      }

      doc.setData(worldData)

      try {
        // 用模板变量的值替换所有模板变量
        doc.render()
      } catch (error: any) {
        // 抛出异常
        const e = {
          message: error.message,
          name: error.name,
          stack: error.stack,
          properties: error.properties,
        }
        console.log(JSON.stringify({ error: e }))
        throw error
      }

      // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
      const out = doc.getZip().generate({
        type: 'blob',
        mimeType:
          'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      })

      FileSaver.saveAs(out, '项目建筑信息数据.docx')

      const file = new window.File([out], '项目建筑信息数据.docx', {
        type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      })
      // callback(file)
    })
  }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值