前言—入职新公司以后 ,领导云淡风轻的说 打印的任务分配给你了 我一口应承下来 结果,,前任员工一堆坑 现任来填坑 一露肚皮深似海 从此打印是路人 言归正传,我们回归到需求本身,先简要说一下我们的需求,如下图 可以看到 要打印表头 表格 和表尾 而且还要做万恶的各种设置 (包含纸张大小 方向 页头页尾 截断还是换行 等等) 根据这些需求 通过代码调整 实现了如下效果 先贴一下用到的LODOP 方法及示意
LODOP = getLodop() // 获取LODOP 对象 LODOP.PRINT_INIT('写入你想说的话') // 打印初始化 LODOP.SET_PRINT_STYLEA(varItemNameID, attrname, attr) //设置样式 只对某打印项有效 varItemNameID: 如果序号为0,代表当前(最后加入的那个)数据项;如果序号是负数,代表前面加入的数据项,该值为前移个数偏移量。 attrname: 要设置的属性名称 大驼峰命名 例如 FontSize FontColor attr: 设置属性值 常用的attrname 及 意思 (自己总结的 ,可能不对, 具体的可以那这个属性名称去google) Alignment 设置页面居中 ItemType 显示类型 FontSize 字号 FontColor 字体颜色 Offset2Top 设置表格偏移 LinkedItem 上下文关联 (使上下文紧密联系起来) Horient 计算属性 LODOP.SET_PRINT_PAGESIZE('纸张方向', '纸张宽度', '纸张高度', '纸张类型') LODOP.SET_SHOW_MODE('LANDSCAPE_DEFROTATED', 1) // 横向时的正向显示 LODOP.ADD_PRINT_TEXT('top', 'left', 'width', 'height', 'content') // 打印文本 LODOP.SET_PRINT_MODE('POS_BASEON_PAPER', true) 打印基点 (基点就是真实打印机的物理边距) LODOP.PREVIEW() 打印预览然后根据项目说一下具体的打印组件封装思路 1.首先校验是否安装打印依赖 2.获取要打印的元素 3.获取打印配置 4.计算打印纸张与你传值的内容的具体比例。根据计算得到的约等于2.64 后边会有具体的算法 然后计算纸张宽高,单位为0.1mm 譬如该参数值为45,则表示4.5mm,计量精度是0.1mm 5.根据打印配置 + 获取到的元素 + 样式(样式根据需求和设计来写)去进行打印预览
算了 直接贴代码 欢迎指正
/* eslint-disable */ import $ from 'jquery' import {getLodop} from '../../src/assets/print/LodopFuncs' // import $utils from '@/utils/utils' import {MessageBox} from 'element-ui' import axios from '../../src/config/axios' import $common from './Common' var total, Thead, Tbody, table, head, foot // 合计 单据头 表格 单据尾 表格头 var configParams = {} // 注入打印参数 const ratio = 2.64 // 打印纸张相对的比例 const magnification = 10 // 倍数 const user = { id: sessionStorage.user ? JSON.parse(sessionStorage.getItem('user')).id : '', name: sessionStorage.user ? JSON.parse(sessionStorage.getItem('user')).name : '', shopName: sessionStorage.user ? JSON.parse(sessionStorage.getItem('user')).storeName : '' } // 打印入口 const preview = function (name, prints, cId) { // 检查是否安装lodop 没有安装先进行安装 if (!checkLodop()) { return false } // 去打印 printPreview(name, prints, cId) } // 校验打印机是否安装 如未安装 则去安装 const checkLodop = function () { let LODOP = getLodop() if (!LODOP) { // 如未安装打印控件,提示用户安装 MessageBox.confirm('未安装打印控件!是否安装打印控件?安装后请刷新页面!', '打印提示', { confirmButtonText: '下载', cancelButtonText: '取消', type: 'warning', closeOnClickModal: false }).then(() => { window.location.href = 'http://www.lodop.net/demolist/CLodop_Setup_for_Win32NT.zip' }).catch(() => { // Message.info('已取消下载') }) return false } else { return true } } // 获取页面元素 const getElement = function (name, attr) { let tags = document.querySelectorAll('#right>.main-content>.el-tabs__content > div') for (let i = 0; i < tags.length; i++) { if (tags[i].style[0] !== 'display') { return $(tags[i]).find(name) } } } // 获取打印配置 const getPrintConfig = function (prints) { return new Promise(function (resolve, reject) { let params = { cMdcode: prints } axios.get(`/tbBaseConfig/getTbcBillformPrint`, {params: params}).then(res => { if (res.data.data && res.data.meta.code === 0 && res.data.data.tbcBillformPrintList) { resolve(res.data.data.tbcBillformPrintList) } else { resolve(false) } }) }) } // 打印预览 const printPreview = function (name, prints, cId) { // 首先获取打印元素 Thead = getElement('.el-table__header-wrapper').last() // 获取表头 Tbody = getElement('.el-table__body-wrapper').last() // 主体 table = getElement('.plsss').eq(0) // 获取表格 head = getElement('.tou').eq(0) // 获取单据头 foot = getElement('.fooT').eq(0) // 获取单据尾 total = getElement('.el-table__footer-wrapper').last() // 获取合计 console.log(Thead, '表头') console.log(table, '表格') console.log(head, '单据头') // console.log(foot.html(), '单据尾') console.log(total, '合计') // 获取打印配置参数并转换 getPrintConfig(prints).then(res => { if (res) { res.map((item) => { if (item.cKey === '是否显示页眉') { configParams.cIsPagehead = item.cValue } if (item.cKey === '纸张高度') { configParams.cHeight = item.cValue } if (item.cKey === '是否显示页脚水平线') { configParams.cIsPagebottomLine = item.cValue } if (item.cKey === '表格显示(超过单元格宽)') { configParams.cIsCut = item.cValue } if (item.cKey === '每页是否都打印表头和表尾(注:当前页面有表头、表尾才起作用)') { configParams.cIsHeadevery = item.cValue } if (item.cKey === '纸张类型') { configParams.cPaperType = item.cValue } if (item.cKey === '是否显示页眉水平线') { configParams.cIsPageheadLine = item.cValue } if (item.cKey === '页面方向') { configParams.cPaperRotation = item.cValue } if (item.cKey === '纸张宽度') { configParams.cWidth = item.cValue } if (item.cKey === '是否显示页脚') { configParams.cIsPagebottom = item.cValue } }) } else { // 默认打印参数 configParams = { cPaperType: 'A4', // 纸张类型 cPaperRotation: '纵向', // 页面方向 cWidth: 210, // 页面宽度 cHeight: 297, // 页面高度 cIsPagehead: '是', // 页眉 cIsPageheadLine: '是', // 页眉线 cIsPagebottom: '是', // 页脚 cIsPagebottomLine: '是', // 页脚线 cIsCut: '否', // 是否截断 cIsHeadevery: '是' // 每页显示页眉页脚 } } console.log(configParams, '打印参数') // 如果有单据头尾或者合计 则为详情 if (head.length > 0 || foot.length > 0 || total.length > 0) { printDetail(name, cId) } else { printList(name, cId) } }) } // 列表打印 const printList = function (name, cId) { console.log('列表打印') let {cPaperRotation, cPaperType, cHeight, cWidth, cIsPagehead, cIsPageheadLine, cIsPagebottom, cIsPagebottomLine, cIsHeadevery, cIsCut} = configParams let LODOP = getLodop() // step1 获取lodop对象 let paperW = 0 let paperH = 0 LODOP.PRINT_INIT('列表打印') // 打印初始化 LODOP.SET_PRINT_STYLEA(1, 'FontName', '宋体') LODOP.SET_PRINT_STYLEA(1, 'FontSize', '12') if (cPaperRotation === '横向') { LODOP.SET_PRINT_PAGESIZE(2, cWidth * magnification, cHeight * magnification, cPaperType) LODOP.SET_SHOW_MODE('LANDSCAPE_DEFROTATED', 1) paperW = Math.round(cHeight * magnification / ratio) paperH = Math.round(cWidth * magnification / ratio) } else { paperW = Math.round(cWidth * magnification / ratio) paperH = Math.round(cHeight * magnification / ratio) LODOP.SET_PRINT_PAGESIZE(1, cWidth * magnification, cHeight * magnification, cPaperType) // 纸张类型 } // 打印页眉 if (cIsPagehead === '是') { console.log('打印页眉') LODOP.ADD_PRINT_TEXT(26, '0%', '100%', '40', name) // 标题名字及宽高距离 LODOP.SET_PRINT_STYLEA(0, 'Alignment', 2) // 居中 LODOP.SET_PRINT_STYLEA(1, 'ItemType', 1) // 显示类型 LODOP.SET_PRINT_STYLEA(1, 'FontSize', 16) // 字体大小 // LODOP.SET_PRINT_STYLEA(1, 'Bold', 1) // 字体变粗 let shopW = user.shopName.length * 12 LODOP.ADD_PRINT_TEXT(32, paperW - shopW - 30 - 10, '100%', '40', user.shopName) // 标题名字及宽高距离 LODOP.SET_PRINT_STYLEA(1, 'ItemType', 1) } if (cIsPageheadLine === '是') { console.log('打印页眉线') LODOP.ADD_PRINT_LINE(60, 0, 60, paperW, 0, 1) // 页眉线 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) } if (cIsPagebottom === '是') { console.log('打印页脚') LODOP.ADD_PRINT_TEXT(paperH - 40, '90%', '200', '25', '第#页/共&页') // 分页 LODOP.ADD_PRINT_TEXT(paperH - 40, 30, '200', '25',) // 分页 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 2) LODOP.SET_PRINT_STYLEA(0, 'Horient', 1) const date = formatTime(new Date()) LODOP.ADD_PRINT_TEXT(paperH - 40, 30, paperW - 100, '25', `打印时间:${date} 打印人:${user.name} 员工编号:${user.id}`) LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) console.log(date) } if (cIsPagebottomLine === '是') { console.log('打印页脚线') LODOP.ADD_PRINT_LINE(paperH - 56, 0, paperH - 56, paperW, 0, 1) // 页脚线 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) } // 展示方式 let tableStyle = '' if (cIsCut === '2') { // 2代表截断 1代表换行 console.log('截断显示') tableStyle = '<link href="./static/css/tableHidden.css?4 type="text/css" rel="stylesheet">' } else { console.log('折行显示') tableStyle = '<link href="./static/css/tablePrint.css?4 type="text/css" rel="stylesheet">' } console.log(paperW, paperH) // 打印固定表头 let tableHeight = paperH - 60 - 60 - 40 - 38 LODOP.ADD_PRINT_HTM(60 + 3, 16, paperW - 32, 50, tableStyle + '<body>' + Thead.html() + '</body>') LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) // 显示类型 LODOP.ADD_PRINT_HTM(60 + 3 + 38, 16, paperW - 32, tableHeight, tableStyle + '<body>' + Tbody.html() + '</body>') LODOP.SET_PRINT_MODE('POS_BASEON_PAPER', true) // 打印基点 LODOP.PREVIEW() } // 详情打印 const printDetail = function (name, cId) { console.log('详情打印') let {cPaperRotation, cPaperType, cHeight, cWidth, cIsPagehead, cIsPageheadLine, cIsPagebottom, cIsPagebottomLine, cIsHeadevery, cIsCut} = configParams let LODOP = getLodop() // step1 获取lodop对象 LODOP.PRINT_INIT('详情打印') // 打印初始化 LODOP.SET_PRINT_STYLEA(1, 'FontName', '宋体') LODOP.SET_PRINT_STYLEA(1, 'FontSize', '12') let paperW = 0 let paperH = 0 let headW = 0 // 单据头总宽 let headH = 0 // 单据头高 let footW = 0 // 单据尾总宽 let footH = 0 // 单据尾高 if (cPaperRotation === '横向') { LODOP.SET_PRINT_PAGESIZE(2, cWidth * magnification, cHeight * magnification, cPaperType) LODOP.SET_SHOW_MODE('LANDSCAPE_DEFROTATED', 1) paperW = Math.round(cHeight * magnification / ratio) paperH = Math.round(cWidth * magnification / ratio) } else { paperW = Math.round(cWidth * magnification / ratio) paperH = Math.round(cHeight * magnification / ratio) LODOP.SET_PRINT_PAGESIZE(1, cWidth * magnification, cHeight * magnification, cPaperType) // 纸张类型 } console.log(paperW, paperH) // 获取打印的所有单据头 let headArr = [] for (let h = 0; h < head.find('.details-input').length; h++) { if (head.find('.details-input').css('display') === 'block') { headArr.push(Number(head.find('.details-input').eq(h).width() + 100)) // headW += head.find('.details-input').eq(h).width() // console.log('单据头单个长度' ,head.find('.details-input').eq(h).width()) } } let footArr = [] for (let h = 0; h < foot.find('.details-input').length; h++) { if (foot.find('.details-input').css('display') === 'block') { footArr.push(Number(foot.find('.details-input').eq(h).width() + 100)) // footW += foot.find('.details-input').eq(h).width() // console.log('单据尾单个长度' ,foot.find('.details-input').eq(h).width()) } } let headRow = 1 let headSum = 0 console.log(headArr) for (let i = 0; i < headArr.length; i++) { headSum += headArr[i] if (headArr[i] > paperW) { headRow++ } else if (headSum > paperW) { headRow++ headSum = headArr[i] } } let footRow = 1 let footSum = 0 console.log(footArr) for (let i = 0; i < footArr.length; i++) { footSum += footArr[i] if (footArr[i] > paperW) { footRow++ } else if (footSum > paperW) { footRow++ footSum = footArr[i] } } console.log(headRow, '单据头打印列数') console.log(footRow, '单据尾打印列数') headH = Math.round(headRow * 30 + 15) // 列数 * 行高 footH = Math.round(footRow * 30 + 15) // 列数 * 行高 + 10 为了兼容 lineitem console.log(headH, '单据头总高度') console.log(footH, '单据尾总高度') // 打印页眉 if (cIsPagehead === '是') { console.log('打印页眉') name = name.replace(/\s*/g, '') console.log(name) console.log(name.split('单')[1]) if (!name.split('单')[1]) { console.log('不显示单据状态') LODOP.ADD_PRINT_TEXT(26, '0%', '100%', '40', name) // 标题名字及宽高距离 LODOP.SET_PRINT_STYLEA(0, 'Alignment', 2) // 居中 LODOP.SET_PRINT_STYLEA(1, 'ItemType', 1) // 显示类型 LODOP.SET_PRINT_STYLEA(1, 'FontSize', 18) // 字体大小 // LODOP.SET_PRINT_STYLEA(1, 'Bold', 1) // 字体变粗 } else { console.log('显示单据状态') LODOP.ADD_PRINT_TEXT(26, '0%', '100%', '40', name.split('单')[0] + '单') // 标题名字及宽高距离 LODOP.SET_PRINT_STYLEA(0, 'Alignment', 2) // 居中 LODOP.SET_PRINT_STYLEA(1, 'ItemType', 1) // 显示类型 LODOP.SET_PRINT_STYLEA(1, 'FontSize', 18) // 字体大小 // LODOP.SET_PRINT_STYLEA(1, 'Bold', 1) // 字体变粗 let status = name.split('单')[1] if (name.split('单')[1].indexOf('?') > -1) { status = name.split('单')[1].replace('?', '') } if (name.split('单')[1].indexOf('?') > -1) { status = name.split('单')[1].replace('?', '') } LODOP.ADD_PRINT_TEXT(29, '60%', '100%', '40', status) // 标题名字及宽高距离 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) // 显示类型 LODOP.SET_PRINT_STYLEA(1, 'FontSize', 12) // 字体大小 LODOP.SET_PRINT_STYLEA(2, 'FontColor', '#f00') // 字体颜色 // 单据号转换条形码 if (cId) { LODOP.ADD_PRINT_BARCODE(22, 30, 130, 30, '128Auto', cId) } LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) } let shopW = user.shopName.length * 12 LODOP.ADD_PRINT_TEXT(32, paperW - shopW - 30 - 10, '100%', '40', user.shopName) // 标题名字及宽高距离 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) } if (cIsPageheadLine === '是') { console.log('打印页眉线') LODOP.ADD_PRINT_LINE(60, 0, 60, '100%', 0, 1) // 页眉线 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) } let dataStyle = '<link href="./static/css/Print.css?18" type="text/css" rel="stylesheet">' // 打印单据头 LODOP.ADD_PRINT_HTM(60 + 10, 16, paperW - 32, headH, dataStyle + '<body>' + head.html() + '</body>') LODOP.SET_PRINT_STYLEA(1, 'FontSize', 12) // 字体大小 LODOP.SET_PRINT_STYLEA(1, 'FontName', '宋体') LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) // 展示方式 let tableStyle = '' if (cIsCut === '2') { // 2代表截断 1代表换行 console.log('截断显示') tableStyle = '<link href="./static/css/tableHidden.css?11" type="text/css" rel="stylesheet">' } else { console.log('折行显示') tableStyle = '<link href="./static/css/tablePrint.css?11" type="text/css" rel="stylesheet">' } LODOP.ADD_PRINT_HTM(60 + 10 + headH + 10, 16, paperW - 32, 38, tableStyle + '<body>' + Thead.html() + '</body>') LODOP.SET_PRINT_STYLEA(1, 'FontSize', 12) // 字体大小 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) // 显示类型 // LODOP.SET_PRINT_STYLEA(0,"LinkedItem",-1) // 关联打印 -1代表前一个对象 var tableHeight = 0 let tableMaxHeight = paperH - 60 - 10 - headH - 10 - 38 - footH - 38 - 56 - 10 - 10 console.log(tableMaxHeight, '动态表格最大高度') let printTrLen = Tbody.find('tr').length // 要打印的总条数 let printTrmaxLen = Math.round(tableMaxHeight / 25) // 每页最多可打印条数 let pageIndex = Math.ceil(printTrLen / printTrmaxLen) let lastLen = printTrLen % printTrmaxLen console.log(printTrmaxLen, '一页最多打印表格数') console.log(printTrLen, '要打印的表格数',pageIndex) if (printTrLen > printTrmaxLen) { tableHeight = printTrmaxLen * 25 } else { tableHeight = printTrLen * 25 } LODOP.ADD_PRINT_HTM(60 + 10 + headH + 10 + 38, 16, paperW - 32, tableHeight, tableStyle + '<body>' + Tbody.html() + '</body>') LODOP.SET_PRINT_STYLEA(1, 'FontSize', 12) // 字体大小 LODOP.SET_PRINT_STYLEA(0, 'Offset2Top', 1) // 设置表格次页偏移 规避打印过多偏移过大问题 // LODOP.SET_PRINT_STYLEA(0,"LinkedItem",-1) // 关联打印 -1代表前一个对象 if (total.length > 0) { // 有合计 console.log('打印合计') LODOP.ADD_PRINT_TABLE(60 + 10 + headH + 10 + 38 + tableHeight, 14, paperW - 32, 38, tableStyle + '<body>' + total.html() + '</body>') LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) // 显示类型 LODOP.SET_PRINT_STYLEA(0,"LinkedItem",-1) // 关联打印 -1代表前一个对象 } // 打印单据尾 LODOP.ADD_PRINT_HTM(60 + 10 + headH + 10 + 38 + tableHeight + 38 + 10, 16, paperW - 32, footH, dataStyle + '<body>' + foot.html() + '</body>') LODOP.SET_PRINT_STYLEA(1, 'FontSize', 12) // 字体大小 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) LODOP.SET_PRINT_STYLEA(0,"LinkedItem",-1) // 关联打印 -1代表前一个对象 if (cIsPagebottomLine === '是') { console.log('打印页脚线') LODOP.ADD_PRINT_LINE(60 + 10 + headH + 10 + 38 + tableHeight + 38 + 10 + footH + 10, 0, 60 + 10 + headH + 10 + 38 + tableHeight + 38 + 10 + footH + 10, paperW, 0, 1) // 页脚线 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) LODOP.SET_PRINT_STYLEA(0,"LinkedItem",-1) // 关联打印 -1代表前一个对象 } if (cIsPagebottom === '是') { console.log('打印页脚') LODOP.ADD_PRINT_TEXT(60 + 10 + headH + 10 + 38 + tableHeight + 38 + 10 + footH + 20, paperW - 60 - 16 - 16 - 0, 200, '25', '第#页/共&页') // 分页 LODOP.SET_PRINT_STYLEA(0, 'ItemType', 2) LODOP.SET_PRINT_STYLEA(0, 'Horient', 1) LODOP.SET_PRINT_STYLEA(0,"LinkedItem",-1) // 关联打印 -1代表前一个对象 const date = formatTime(new Date()) // LODOP.ADD_PRINT_TEXT(60 + 10 + headH + 10 + 38 + tableHeight + 38 + 10 + footH + 20, 30, 200, 25, '') LODOP.ADD_PRINT_TEXT(60 + 10 + headH + 10 + 38 + tableHeight + 38 + 10 + footH + 20, 30, paperW - 100, '25', `打印时间:${date} 打印人:${user.name} 员工编号:${user.id}`) LODOP.SET_PRINT_STYLEA(0, 'ItemType', 1) LODOP.SET_PRINT_STYLEA(0,"LinkedItem",-2) // 关联打印 -1代表前一个对象 } LODOP.SET_PRINT_MODE('POS_BASEON_PAPER', true) // 打印基点 LODOP.PREVIEW() } const formatTime = function () { // 把时间戳转换成 年月日时分秒 let date = new Date() let year = date.getFullYear() let month = date.getMonth() + 1 let day = date.getDate() let hour = date.getHours() let minute = date.getMinutes() let second = date.getSeconds() return `${year}-${month}-${day} ${hour}:${minute}:${second}` } export default { checkLodop, preview, getElement, printPreview, getPrintConfig, printList, printDetail, formatTime }做完发现很简单 只要把API 吃透了 希望能给大家带来帮助