前言:临时性需求没怎么接触过前端,代码实现有问题及优化点希望大佬可以留言告知一下
开发工具:VS CODE
界面开发:Vue3+TypeScript+ElementPlus
打印组件:Print-JS
前端打印入口图:
标签页面:
打印界面:
实现功能:前端点击"打印标签"弹出打印界面进行打印作业
实现过程:主界面点击"打印标签"调用el-dialog弹窗(预览和直接打印都居于弹窗实现)
标签模板代码:
TypeScript
<template>
<div class="LabelPrint-List">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="50%" >
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit/> </el-icon>
<span>标签打印界面</span>
</div>
</template>
<el-row :gutter="10">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb10">
<div v-for="item in state.Datas">
<el-card class="box-card" style="width:100mm; height: 90mm;display: block;" >
<div :id='item.id?.toString()'>
<!-- print-js -->
<div class="labelHeadBody">
<div class="labelHeadBodyLeftHead">
<img class="labelHeadBodyLeftHeadimage" src="/image/点金log.png" fit="fill" />
</div>
<div class="labelHeadBodyRightHead">
<table class="tableHead">
<tr>
<td class="labelHeadBodyRightHeadTd">某某有限公司</td>
</tr>
<tr>
<td class="labelHeadBodyRightHeadTd">物料标识卡</td>
</tr>
</table>
</div>
</div>
<div class="labelBody">
<table>
<tbody>
<tr><td class="lableBodytdleft">P/N:</td><td class="lableBodytdright">{{ item.produceNo }}</td></tr>
<tr><td class="lableBodytdleft">数量:</td><td class="lableBodytdright">{{ item.quantity }}</td></tr>
<tr><td class="lableBodytdleft">规格:</td><td class="lableBodytdright lableBodytdrightfont">{{ item.platingSpecs }}</td></tr>
<tr><td class="lableBodytdleft">供应商:</td><td class="lableBodytdright">东莞点金</td></tr>
<tr><td class="lableBodytdleft">生产日期:</td><td class="lableBodytdright">{{moment(String(item.createTime)).format('YYYY/MM/DD')}}</td></tr>
<tr><td class="lableBodytdleft">批次单号:</td><td class="lableBodytdright">{{ item.lot }}</td></tr>
<tr><td class="lableBodytdleft">单重:</td><td class="lableBodytdright">{{ item.singleWeight }}</td></tr>
<tr><td class="lableBodytdleft">总重:</td><td class="lableBodytdright">{{ item.sumWeight }}</td></tr>
<tr><td class="lableBodytdleft">标识人:</td><td class="lableBodytdright"></td></tr>
</tbody>
</table>
</div>
</div>
</el-card>
</div>
</el-col>
</el-row>
<template #footer>
<span class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button style="background-color:red;color:white" @click="print">打 印</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
Typescript代码:
printrow 方法中使用nextTick是当el-dialog弹窗DOM加载完成后在调用PrintJS获取需要打印的区域,这个直接打印过程其实会先弹窗然后DOM加载完成后直接调用浏览器打印界面,后面把弹出关闭,如果不加载el-dialog可以通过动态加载html内容来实现直接打印,我这里图方便就用该方法实现了。
printJS({printable:区域id,type:打印类型(pdf\image\html等),style:打印内容的CSS样式})
注意:style参数值按打印区域的HTMLCSS样式构建,调用printJS设置scanStyles:false不会自动加载HTML的CSS样式需要重新给Style参数赋值所以增加了一个printStyle函数,scanStyles默认值是true(会导致打印界面的内容奇奇怪怪,还没去了解详细原因哈哈哈哈)
TypeScript
<script lang="ts" setup>
import { ref,reactive,nextTick } from 'vue';
import { TbProduceOrderNoInfo } from '/@/api-services';
import printJS from 'print-js';
import moment from 'moment';
const props=defineProps({
title:String
})
const state=reactive({
isShowDialog:false,
Datas:[] as Array<TbProduceOrderNoInfo>,
})
const emits = defineEmits(['handleQuery']);
const closeDialog=()=>{
emits('handleQuery');
state.isShowDialog=false;
}
const cancel=()=>{
state.isShowDialog=false;
closeDialog();
}
//预览+打印
const openDialog=async(row:any)=>{
state.Datas=JSON.parse(JSON.stringify(row));
state.isShowDialog=true;
}
const print=()=>{
for(var i=0;i<state.Datas.length;i++){
printJS({printable:`${state.Datas[i].id}`,type:"html",style:printStyle(),scanStyles:false})
}
}
//直接打印不预览
const printrow=async(row:any)=>{
state.Datas=JSON.parse(JSON.stringify(row));
state.isShowDialog=true;
//主界面form DOM加载完成
nextTick(()=>{
//弹窗加载完成
nextTick(()=>{
printJS({printable:`${state.Datas[0].id}`,type:"html",style:printStyle(),scanStyles:false})
state.isShowDialog=false;
})
})
}
//打印界面的CSS样式
const printStyle=()=>{
return `
.labelHeadBody{
display: flex;justify-content:space-between;margin: 0; font-size: 16px;width: 100%; height:45px
}
.labelHeadBodyLeftHead{
width: 30px;
}
.labelHeadBodyRightHead{
width: 250px; height: 70px;display: flex;justify-content: center;
}
.lableBodytdrightfont{
font-size:10px
}
.labelHeadBodyRightHeadTd{
padding: 0;
font-size: 14px;
font-weight: bold;
text-align: center;
vertical-align: middle;
}
.labelBody{
margin-left: 5px;
margin-right: 5px;
}
.lableBodytdleft{
width: 30%;
font-weight: bold;
vertical-align: bottom;
}
.lableBodytdright{
width: 70%;
border-bottom: 1px solid;
}
.labelHeadBodyLeftHeadimage{
width: 70px; height: 40px
}
.tableHead{
height: 20px;
}
`;
}
//预览、直接打印
defineExpose({openDialog,printrow})
</script>
标签前端样式代码:
html
<style>
.labelHeadBody{
display: flex;justify-content:space-between;margin: 0; font-size: 16px;width: 100%;
}
.labelHeadBodyLeftHead{
width: 30px;
}
.labelHeadBodyRightHead{
width: 250px; height: 70px;display: flex;justify-content: center;
}
.labelHeadBodyRightHeadTd{
padding: 0;
font-size: 14px;
font-weight: bold;
text-align: center;
vertical-align: middle;
}
.labelBody{
margin-top: 10px;
margin-left: 5px;
margin-right: 5px;
}
.lableBodytdleft{
width: 30%;
font-weight: bold;
vertical-align: bottom;
}
.lableBodytdright{
width: 75%;
border-bottom: 1px solid;
}
.labelHeadBodyLeftHeadimage{
width: 80px; height: 55px
}
.tableHead{
height: 20px;
}
</style>
最后,如果需要带二维码的同学可以添加qrcode组件,以下是简单的实现(el-image、img标签中图片不显示的问题还没解决,迂回操作直接把生成的二维码图片设置成控件背景来处理,囧.........):
TypeScript
<template #default="scope">
<div :style="createQrcode(scope.row.eqNo)" ></div>
<!-- <el-image :scr="createQrcode1(scope.row.eqNo)" style="width: 60px;height: 60px;"></el-image> -->
</template>
import QRCode from 'qrcode'
//将生成的二维码设置成div的Style,不知道为嘛el-image绑定base64image图片不显示
const createQrcode=(text:string)=>{
if(text==""||text==undefined||text==null) return "";
let url1:any;
url1="";
QRCode.toDataURL(text,(err,url)=>{
if(err){
console.error(err);
}
else{
url1=url;
}
})
return `background-image: url(${url1});background-position: center center;background-size: contain;background-repeat: no-repeat;;width:100%;height:60px`;
}