业务需求:财务ERP系统会计凭证的打印,科目打印需自动拼接上辅助核算,如科目有外币需打印外币,对于长凭证一张A4纸打印2张凭证,每张凭证固定5行。
大致实现思路:先把需要打印的页面用canva画转成pdf,传给后端保存,之后下载PDF预览打印结果。
需要打印的凭证:
打印结果预览:
有外币:
**实现步骤:**
1. 安装2个依赖 npm install jspdf html2canvas -D
2. 基于jspdf与html2canvas封装一个全局打印方法,查询凭证拼凑凭证数据(父组件),打印的模板(子组件)。具体实现代码如下:
```
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
import axios from 'axios' //把pdf传给后台
import qs from 'qs'//需要转换 用JOSN.stringify()不行
export default {
install(Vue, options) {
Vue.prototype.getPdf = function (dom) {
html2Canvas(document.querySelector(dom), {
allowTaint: true
}).then(function (canvas) {
let contentWidth = canvas.width
let contentHeight = canvas.height
//一页pdf显示html页面生成的canvas高度;
let pageHeight = contentWidth / 595.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()
}
}
}
var instance = axios.create({
timeout: 10000,
headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }
});
instance.post(axios.defaults.baseURL + '/file/savepdf', qs.stringify({
//output输出文件流,PDF.output('datauristring')输出base64文件流。
file: PDF.output('datauristring')//base64的文件流
}))
.then(function (response) {
window.open(axios.defaults.baseURL + '/file/showpdf/' + response.data.data.uri)//在新的窗口打开
// let dom=document.createElement('a');
// dom.setAttribute('href',axios.defaults.baseURL+'/file/showpdf/'+response.data.data.uri);
// dom.setAttribute('target','_blank');
// dom.click();//模拟新的窗口打开
})
.catch(function (error) {
});
})
}
}
}
```
3. 调用function
```
//打印凭证
printVoucher() {
//日期
let Voucherdate = new Date(this.pickerOptionsValue);
let tableData = this.childData; //整个视图数据
let trData = this.childData.trData; //列数据
//拼凑数据供打印使用,凭证头,尾信息
this.voucherHFdata = {
voucherTitle: "记账凭证", //记账凭证
billNum: this.billNum, //附件数
accbookName: this.$store.state.accbookName, //账套名
date:Voucherdate.getFullYear() + "-" +(Voucherdate.getMonth() + 1) +"-" +Voucherdate.getDate(), //日期
voucherNumber: this.voucherName + "-" + this.voucherNumberValue, //凭证号:大-16
lotal: tableData.DeCr_Total, //合计
supervisor: "", //主管
cashier: "", //出纳
auditor: "", //审核
producer: this.$store.state.voucherProducer //制单
};
//需打印的列数据过滤
// let listData = [];
trData.forEach((n, i) => {
//科目是否有辅助核算,有辅助核算,拼接上辅助核算eg:1001 库存现金_销售部
let subjectVal =
n.subject.val +
(n.subject.auxData.length > 0 ? "_" : "") +
n.subject.auxData
.map(item1 => {
return (
item1.options.filter(item2 => {
if (item1.value === item2.uid) return item2;
})[0].name || ""
);
})
.join("_");
//是否有外币,没有外币显示空。有外币匹配过滤出外币名称eg:RMB
let curName =
n.currency.currencyOptions
.filter(item => {
if (item.value === n.currency.currencyValue) return item;
})
.map(item => {
return item.label;
})[0] || "";
this.listData[i] = {
abstract: n.abstract.val, //摘要
subject: subjectVal, //科目是否有辅助核算,有辅助核算,拼接上辅助核算
currencyName: curName, //是否有外币,没有外币显示空。有外币匹配过滤出外币名称eg:RMB
showCur: n.currency.show,//false不显示
exchangeRate: n.currency.exchangeRate, //汇率
original: n.currency.original, //原币
deVal: n.DeCr.De_val, //借方金额
crVal: n.DeCr.Cr_val//贷方金额
};
});
this.$refs.print.printvoucher(); //打印调动子子组件的方法***
},
```
**模板:printVoucher.vue**
```
<!-- 打印模板 -->
<print-voucher :voucherHFdata='voucherHFdata' :listData='listData' ref="print"></print-voucher>
<!-- 打印模板 -->
```
```
export default {
name: "printVoucher",
props: ["voucherHFdata", "listData"],//父组件的凭证头尾和列集合数据
data() {
return {
// htmlTitle: "voucher"
tableData:[],
hascur:false,//是否有外币,操作2种模板
};
},
mounted() {},
methods: {
printvoucher() {
this.voucher5tr(
//解决异步
setTimeout(()=>{
this.getPdf("#printVoucher");
},1000)
);
},
//每5列切成一张凭证
voucher5tr() {
let tr5 = []; //[[{},{},{},{},{}]]一维变多维
let tr = this.listData;
let index = 0;
tr.forEach((n, i) => {
if (!tr5[index]) {
tr5[index] = [];
}
tr5[index].push(n);
if (tr5[index].length === 5) {
index++;
}
});
let last = tr5[tr5.length - 1];
for (let i = 0,l = 5 - last.length; i < l; i++) {
last.push({
abstract: "", //摘要
showCur:false,//外币不显示
subject: "", //科目是否有辅助核算,有辅助核算,拼接上辅助核算
currencyName: "", //是否有外币,没有外币显示空。有外币匹配过滤出外币名称eg:RMB
exchangeRate: "", //汇率
original: "", //原币
crVal: "", //贷方金额
deVal: "" //借方金额
});
}
this.tableData=tr5;
this.tableData.forEach(n=>{
n.forEach(n1=>{
if(n1.showCur===true){
this.hascur=true;
}
})
})
}
}
};
```