1、我们在工作中,在中后台系统应用中,经常会遇到打印的问题。
2、产品需求将列表详情数据能够打印生产单据,包括列表详情的所有数据。
3、通常我们可以通过接口拿到一定格式的JSON数据。
打印组件,总的思想就是把JSON数据通过Vue渲染成HTML,然后把指定id的标签打印出来。
封装组件时遇到的问题:
1、elementUI表格如果直接使用,浏览器打印时有的CSS会渲染不出来,自己重新写了表格的CSS和HTML。
2、按钮使用v-print打印指令时,print的id要是动态的,不然会有打印缓存(我是这样的理解的,可能不准确)。
第一张为需要被打印的组件,第二、第三为浏览器打印的效果图
目录
一、全局注册组件,在main.js中全局注册组件
将组件注册为全局组件,方便使用,减少引用次数
// 全局打印组件挂载
import PrintForm from '@/components/PrintForm'
Vue.component('PrintForm', PrintForm);
二、组件代码
UI组件封装,统一封装UI,统一固定格式的数据格式来进行渲染。
<template>
<!-- 查看详细信息话框 -->
<el-dialog title="打印" :visible.sync="isVisiblePrint" width="70%" append-to-body :close-on-click-modal="false">
<div class="contentPrint">
<div :id="printId" style="width: 780px;margin: 0 auto;padding: 5px;">
<h4 style="text-align: center;">{{companyPrint}}</h4>
<el-descriptions class="margin-top" :title="titlePrint" :column="3" :size="size">
<el-descriptions-item v-for="(item,index) in titleArrayPrint" :key="index" :label="item.label">{{ item.content }}</el-descriptions-item>
</el-descriptions>
<table class="tableStyle " v-if="detailListDataPrint[0].length > 1">
<tr class="borderStyle">
<td class="borderStyle" v-for="(item,index) in detailListDataPrint[0]" :key="index">{{ item }}</td>
</tr>
<tr class="borderStyle" v-for="(item,index) in detailListDataPrint[1]" :key="index">
<td class="borderStyle" v-for="(keys,index) in item" :key="index">{{keys}}</td>
</tr>
</table>
<table class="tableStyle " style="margin-top: 25px;" v-if="examineArrayPrint.length > 0">
<tr class="borderStyle">
<td class="borderStyle">序号</td>
<td class="borderStyle">审批节点</td>
<td class="borderStyle">审批处理</td>
<td class="borderStyle">审批意见</td>
<td class="borderStyle">审批人</td>
<td class="borderStyle">审批时间</td>
</tr>
<tr class="borderStyle" v-for="(item,index) in examineArrayPrint" :key="index">
<td class="borderStyle">{{ index+1 }}</td>
<td class="borderStyle">{{ item.taskNodeName?item.taskNodeName:'' }}</td>
<td class="borderStyle">{{ item.controlValue ?item.controlValue :'' }}</td>
<td class="borderStyle">{{ item.remark?item.remark:'' }}</td>
<td class="borderStyle">{{ item.createName ?item.createName:'' }}</td>
<td class="borderStyle">{{ item.createTime?item.createTime:'' }}</td>
</tr>
</table>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button v-print="print" type="primary">打印</el-button>
<el-button @click="isVisiblePrint = false">关闭</el-button>
</div>
</el-dialog>
</template>
<script>
import {getTableHistory} from '@/api/activiti/activitiHistory'
export default {
name: "PrintForm",
data() {
return {
print: {
id: '',
popTitle: '', // 打印配置页上方标题
extraHead: '', //最上方的头部文字,附加在head标签上的额外标签,使用逗号分隔
preview: '', // 是否启动预览模式,默认是false(开启预览模式,可以先预览后打印)
previewTitle: '', // 打印预览的标题(开启预览模式后出现),
previewPrintBtnLabel: '', // 打印预览的标题的下方按钮文本,点击可进入打印(开启预览模式后出现)
zIndex: '', // 预览的窗口的z-index,默认是 20002(此值要高一些,这涉及到预览模式是否显示在最上面)
previewBeforeOpenCallback() { }, //预览窗口打开之前的callback(开启预览模式调用)
previewOpenCallback() { }, // 预览窗口打开之后的callback(开启预览模式调用)
beforeOpenCallback() { }, // 开启打印前的回调事件
openCallback() { }, // 调用打印之后的回调事件
closeCallback() { }, //关闭打印的回调事件(无法确定点击的是确认还是取消)
url: '',
standard: '',
extraCss: '',
},
size: '',
isVisiblePrint:false,
companyPrint:'',//公司
titlePrint:'',//功能类型,请购、入库等
titleArrayPrint:[], //单子上部基本数据
isVisiblePrint:false,
detailListDataPrint: [
[],
[]
],
examineArrayPrint:[],//审批数组
printId:''
}
},
methods: {
changeVisible(item){
console.log(item,'item打印组件',this);
this.printId = new Date().getTime() + 'print'
this.print.id = this.printId
this.isVisiblePrint = !this.isVisiblePrint
this.titlePrint = item.titlePrint
this.companyPrint = item.companyPrint
this.titleArrayPrint = item.titleArrayPrint.filter((i)=>{
if(i.content !== ''){
return i
}
})
this.detailListDataPrint[0] = item.headerArrayPrint
this.detailListDataPrint[1] = item.bodyArrayPrint
if (item.processInstancePrint) {
this.queryParams =
getTableHistory({ "instanceId": item.processInstancePrint }).then(response => {
this.examineArrayPrint = response.data
this.examineArrayPrint = this.examineArrayPrint.map(w => {
if (w.taskNodeName == '发起人') {
w.createName = item.printDataObject[0].createuser_dictText
}
return w
})
})
}
}
},
mounted() {
},
destroyed(){
this.printId = ''
}
}
</script>
<style>
h4 {
padding: 0 ;
margin:10px 0;
}
.margin-top .el-descriptions__title {
text-align: center;
width: 100%;
}
.contentPrint {
overflow: auto;
height: 460px;
}
.tableStyle {
border-collapse: collapse;
width: 100%;
text-align: center;
color: #606266;
table-layout: fixed;
border: 1px solid #dfe6ec;
page-break-after:auto
}
.borderStyle {
border: 1px solid #dfe6ec;
text-align: center;
color: #606266;
word-break: break-all;
page-break-inside:avoid;
page-break-after:auto;
}
.printTable {
border: 1px solid #dfe6ec;
}
</style>
三、在组件中使用
将数据统一封装成固定的格式,统一注入到组件中,顶部的数据格式为数组,UI为elementUI中的描述列表。
//在template中引入
<PrintForm ref="printFormProcurement" > </PrintForm>
//打印按钮printDataList为data中拿到的JSON的动态选择到的数据
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-print"
size="mini"
:disabled="ids.length !== 1"
@click="printVisibleDataPatent(printDataList)"
>打印</el-button>
</el-col>
//打印按钮触发函数
// 打印传参函数 row为传入的参数,包括打印所有的JSON数据
printVisibleDataPatent(row){
const printFormProcurement = this.$refs.printFormProcurement
let companyPrint =row[0].deptId_dictText?row[0].deptId_dictText:''
let processInstancePrint = row[0].processId?row[0].processId:''
let bodyArrayPrint = []
if (row[0].detailList) {
if (Array.isArray(row[0].detailList)) {
bodyArrayPrint = row[0].detailList.map((item, index) => {
let arr = []
arr.push(index + 1)
arr.push(item.goodsname || (item.goodsname === 'undefined'?'':item.goodsname))
arr.push(item.goodscode || (item.goodscode === 'undefined'?'':item.goodscode))
arr.push(item.goodsspecification || (item.goodsspecification === 'undefined'?'':item.goodsspecification))
arr.push(item.goodsnum || (item.goodsnum === 'undefined'?'':item.goodsnum))
arr.push(item.itemUnit || (item.itemUnit === 'undefined'?'':item.itemUnit))
arr.push(item.perprice || (item.perprice === 'undefined'?'':item.perprice))
if(item.goodsnum && item.perprice){
arr.push((item.goodsnum * item.perprice).toFixed(2))
}else{
arr.push(0)
}
// arr.push(item.price || (item.price === 'undefined'?'':item.price))
// arr.push(item.totalPrice || (item.totalPrice === 'undefined'?'':item.totalPrice))
// if(this.storages.length){
// console.log(this.storages);
// }
// arr.push(item.totalPrice || (item.totalPrice === 'undefined'?'':item.totalPrice))
return arr
})
}
}
let titleArrayPrint = [
{
label:'请购单号',
content:row[0].code?row[0].code:''
},
{
label:'主题',
content:row[0].theme_?row[0].theme_:''
},
{
label:'单据日期',
content:row[0].bizdate?row[0].bizdate:''
},
{
label:'采购类型',
content:row[0].type?selectDictLabel(this.dict.type.procurement_type,row[0].type) :''
},
{
label:'请购人',
content:row[0].procurementUser?row[0].procurementUser:''
},
{
label:'币种',
content:row[0].currency?selectDictLabel(this.dict.type.currency,row[0].currency):''
},
{
label:'费用类型',
content:row[0].costtype?selectDictLabel(this.dict.type.cost_type,row[0].costtype):''
},
{
label:'总费用',
content:row[0].totalcost?row[0].totalcost:''
},
{
label:'中心',
content:row[0].companyId_dictText?row[0].companyId_dictText:''
},
{
label:'场站',
content:row[0].deptId_dictText?row[0].deptId_dictText:''
},
{
label:'付款条件',
content:row[0].paymentterm?row[0].paymentterm:''
},
{
label:'最迟送货日期',
content:row[0].deadlinedeliverytime? this.parseTime(row[0].deadlinedeliverytime, '{y}-{m}-{d}') :''
},
{
label:'送货地址',
content:row[0].deliveryaddress?row[0].deliveryaddress:''
},
{
label:'用途',
content:row[0].usage_?row[0].usage_:''
},
{
label:'备注',
content:row[0].remark?row[0].remark:''
},
]
let dataTransfer = {
titlePrint:'请购单',
printDataObject:row,
companyPrint,
titleArrayPrint,
headerArrayPrint:['序号','物料名称','物料编号','规格型号','请购数量','单位','含税单价(元)','总价'],
bodyArrayPrint,
processInstancePrint,
}
printFormProcurement.changeVisible(dataTransfer)
},