1. 安装需要的插件并引入- import PizZip from 'pizzip'
- import Docxtemplater from 'docxtemplater'
- import JSZipUtils from 'jszip-utils'
- import { saveAs } from 'file-saver'
- import ImageModule from 'docxtemplater-image-module-free'
- import { Buffer } from 'buffer'
复制代码 2. 工具utils中新建 exportFile.js 文件,用于将图片转换为base64格式- // getBase64Sync
- export function getBase64Sync(imgUrl) {
- return new Promise((resolve, reject) => {
- const image = new Image();
- image.crossOrigin = 'anonymous';
- image.onload = () => {
- const canvas = document.createElement('canvas');
- // 固定画布尺寸为90x90
- canvas.width = 90;
- canvas.height = 90;
- const ctx = canvas.getContext('2d');
- // 计算缩放比例后居中绘制
- const scale = Math.min(90 / image.width, 90 / image.height);
- const scaledWidth = image.width * scale;
- const scaledHeight = image.height * scale;
- const dx = (90 - scaledWidth) / 2;
- const dy = (90 - scaledHeight) / 2;
- ctx.drawImage(image, dx, dy, scaledWidth, scaledHeight);
- let ext = imgUrl.split('.').pop().toLowerCase();
- if (ext === 'jpg') ext = 'jpeg';
- const mime = `image/${ext}`;
- try {
- const dataurl = canvas.toDataURL(mime, 0.8);
- resolve(dataurl);
- } catch (e) {
- reject(e);
- }
- };
- image.onerror = () => reject(new Error('图片加载失败'));
- image.src = imgUrl + (imgUrl.includes('?') ? '&' : '?') + 't=' + Date.now();
- });
- }
- // base64DataURLToArrayBuffer
- export function base64DataURLToArrayBuffer(dataURL) {
- const base64 = dataURL.split(',')[1];
- const binaryString = window.atob(base64);
- const len = binaryString.length;
- const bytes = new Uint8Array(len);
- for (let i = 0; i < len; i++) {
- bytes[i] = binaryString.charCodeAt(i);
- }
- return bytes.buffer;
- }
复制代码 3.引入 exportFile中的函数- import { getBase64Sync,base64DataURLToArrayBuffer } from '@/utils/exportFile.js'
复制代码 4.设置.docx模板文件,位置放在public文件下
数组使用{#data}{/data}包裹起来
展示的字段使用{item}
图片赋值用到{%img}
模板例如:
5.导出按钮具体功能实现- /** 方案1,不考虑图片直接导出 world */
- function submitForm() {
- // const htmlContent = document.getElementById('htmlcontent');
- // const blob = new Blob([htmlContent.innerHTML], { type: 'application/msword' });
- // const url = window.URL.createObjectURL(blob);
- // const a = document.createElement('a');
- // a.href = url;
- // a.download = '包装码.docx';
- // a.click();
- // window.URL.revokeObjectURL(url);
- }
复制代码- /** 方案2,考虑图片,导出world */
- async function exportWord() {
- try {
- const content = await new Promise((resolve, reject) => {<br> //world模板'/boxCode.docx'
- JSZipUtils.getBinaryContent('/boxCode.docx?random=' + Math.random(), (error, data) => {
- error ? reject(error) : resolve(data);
- });
- });
- const zip = new PizZip(content);
-
- let doc = new Docxtemplater();
-
- // 注册图片模块
- const imageOptions = {
- getImage: (tag) => {
- const base64Data = tag.split(',')[1];
- return Buffer.from(base64Data, 'base64');
- },
- // 设置Word中图片显示尺寸为90x90
- getSize: () => [90, 90]
- };
- doc.attachModule(new ImageModule(imageOptions));
- doc.loadZip(zip);
- const processedData = await Promise.all(
- currentData.value.map(async (item) => {
- const base64 = await getBase64Sync(item.boxCodeUrl);
- const matches = base64.match(/^data:image\/(\w+);base64,/);
- const validBase64 = matches ? base64 : `data:image/png;base64,${base64}`; //图片转码
- return {
- itemCode:item.itemCode?item.itemCode:'',
- batchNumber:item.batchNumber?item.batchNumber:'',
- itemName:item.itemName?item.itemName:'',
- itemModel:item.itemModel?item.itemModel:'',
- itemNumber:item.itemNumber?item.itemNumber:'',
- projectName:item.projectName?item.projectName:'',
- specification:item.specification?item.specification:'',
- vendorName:item.vendorName?item.vendorName:'',
- boxCodeUrl: validBase64 || ''
- };
- })
- )
- doc.setData({ currentData: processedData });//数据赋值
- try {
- doc.render();
- } catch (error) {
- console.error('模板渲染错误:', error.properties?.errors);
- throw error;
- }
-
- const out = doc.getZip().generate({
- type: 'blob',
- mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
- });
- saveAs(out, currentItemName.value + '包装码.docx');
- } catch (error) {
- console.error('导出失败:', error);
- throw error;
- }finally{
- visible.value = false
- }
- }
复制代码 6.导出的world页面中若需要分页,在需要分页的光标位置设置分页符
注:因为我用到了标签打印,生成的world打印时纵向横向样式展示没办法解决,所以将生成的world通过接口转为pdf输出进行打印 const selectedFile = doc.getZip().generate({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); const formData = new FormData(); formData.append('file', selectedFile); fetch(VITE_APP_BASE_API + VITE_AGENT_API+`/md/purchaseorder/convertWordToPDF`, { method: 'POST', headers: { 'Authorization': `Bearer ${getToken()}` }, body: formData }) .then(response => { if (!response.ok) { throw new Error(`服务器返回错误: ${response.status}`); } return response.blob(); }) .then(blob => { const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `${currentItemName.value}` + '包装码.pdf' ); document.body.appendChild(link); link.click(); document.body.removeChild(link); }) .catch(error => { console.error('导出失败:', error); loadingSubmit.value = false throw error; });
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |