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)
})
}