Lodop使用经验

原创
2021/06/02 09:58
阅读数 1.2K

1 概述

这两日使用Lodop完成打印功能.为防止以后再次需要时遗忘怎么使用,特将经验记录下,以供将来参考.


2 前置准备

Lodop是一个jQuery时代很好用的打印组件,但到了Vue/React时代,用起来反而有些束手束脚.
先说流程,使用Lodop打印,需要先将Lodop控件的主程序下载下来.此法使用此主程序,官网也提供了一个很好用的LodopFuncs.js,调用此js后,就可直接使用LODOP布局打印而不必关注打印实现的细节.
官方打印控件样例


3 打印内容构建

在做好前置准备后,js方法就可直接调用LODOP=getLodop(),进行api中介绍的操作.
在jQuery时代,可以直接使用document.getElementById('someId').innerHTML来调用获取要答应的内容,可以是HTML,TABLE等.
在当前Vue/React时代,理论上也可使用如上方法,但笔者在测试时发现视图经常不回随着数据的变化而变化.即使使用了像$forceUpdate(),$nextTick(()=>{}),setTimeout(()=>{},1000)这样的延时方法,仍是效果不彰.在这种情况下,最稳妥的方式,就是采取字符串拼接的方式:

/**
 * 计算头部dom
 * @param headData
 * @returns {string}
 */
export const calcHeadDom = (headData) => {
  return `<table  cellpadding="0" cellspacing="0" style="width: 100%;table-layout: fixed;">` +
    (headData.map((headItem, index) => {
      return `<tr>` +
        (index === 0 ? (`
            <td colspan="${headItem[0].contentColspan}" style="font-weight: bold;text-align: center;font-size: 14pt;height: 50px">
              ${headItem[0].content}
            </td>`
        ) : (
          headItem.map((item) => {
            return `
              <td colspan="${item.titleColspan}" style="font-weight: bold;text-align: right;height: 19px;" >
                  ${item.title}
                </td>
                <td colspan="${item.contentColspan}" >` +
              (item.content ? `<div style="width: 100%;border-bottom: 1px solid black;height: 19px;">${item.content}</div>` : ``) +
              `</td>`
          }).reduce((a, b) => (a + b), ``)
        )
        ) +
        `</tr>`
    }).reduce((a, b) => (a + b), '')) +
    `</table>`
}

/**
 * 计算主体dom
 * @param bodyData
 */
export const calcBodyDom = (bodyData) => {
  return `
      <table border="1" cellpadding="0" cellspacing="0" style="width: 100%;margin-top: 5px;table-layout: fixed;border-color: black;border-collapse:collapse">
        <thead>` +
    bodyData.head.map((headItem) => {
      return `
        <tr >` +
        headItem.map(item => {
          return `
          <th  colspan="${item.contentColspan}" align="${item.align === '' ? 'left' : item.align}" style="font-weight: bold;font-size: 14pt;">
            ${item.content}
          </th>`
        }).reduce((a, b) => a + b, '') +
        `
        </tr>`
    }).reduce((a, b) => a + b, '') +
    `</thead>

        <tbody>` +
    bodyData.body.map(bodyItem => {
      return `<tr >` +
        bodyItem.map(item => {
          return `<td colspan="${item.contentColspan}" align="${item.align === '' ? 'left' : item.align}" style="height: 19px;">
            ${item.content}
          </td>`
        }).reduce((a, b) => a + b, '') +
        `</tr>`
    }).reduce((a, b) => a + b, '') +
    `</tbody>

        <tfoot>` +
    bodyData.foot.map(footItem => {
      return `
        <tr >` +
        footItem.map(item => {
          return `
          <th  colspan="${item.contentColspan}" align="${item.align === '' ? 'left' : item.align}" style="height: 19px;">` +
            (item.tData
              ? `
            <div >
              <font color="blue" tdata="${item.tData}" format="${item.format}" tindex="${item.tIndex}" >${item.content}######</font>
            </div>` : `
            <div>
              ${item.content}
            </div>`
            ) +
            `
          </th>`
        }).reduce((a, b) => a + b, '') +
        `
        </tr>`
    }).reduce((a, b) => a + b, '') +
    `</tfoot>
      </table>`
}

/**
 * 计算尾部dom
 * @param footData
 */
export const calcFootDom = (footData) => {
  return `
        <table style="width: 100%;table-layout: fixed;">` +
    footData.map(footItem => {
      return `
        <tr >` +
        footItem.map(item => {
          return `
            <td colspan="${item.titleColspan}" style="font-weight: bold;text-align: right;font-size: 12px;" >
              ${item.title}
            </td>

            <td colspan="${item.contentColspan}" >` +
            (item.content ? `
              <div style="width: 100%;height: 100%;border-bottom: 1px solid black;font-size: 12px;">${item.content}</div>` : ``) +
            `
            </td>
          `
        }).reduce((a, b) => a + b, '') +
        `
        </tr>`
    }).reduce((a, b) => a + b, '') +
    `
      </table>
  `
}

4 api方法使用

关于api中的操作,笔者仅列举常见操作,如果对更多api方法有兴趣的,可参考后面的参考地址,写的还是比较详细的.

// 凭证打印

import { calcBodyDom, calcFootDom, calcHeadDom } from '@/libs/lodop/lodop-string'
import { getLodop } from '@/libs/lodop/LodopFuncs'
import { calcVoucherPrintData } from '@/common/voucher/voucher'

/**
 * 批量打印凭证
 * @param arrVoucherInfo
 */
export const printBatchVoucher = arrVoucherInfo => {
  LODOP = getLodop()

  LODOP.PRINT_INIT('打印控件')

  for (let [i, { voucherMain, voucherDetail, companyName }] of arrVoucherInfo.entries()) {
    // LODOP.NewPage();

    let { head, body, foot } = calcVoucherPrintData({ voucherMain, voucherDetail, companyName })
    const intPaddingHeight = 10
    const intRowHeight = 21
    const intHeadHeight = (head.length + 2) * intRowHeight
    const intBodyHeight = (body.head.length + body.body.length + body.foot.length) * intRowHeight
    const intFootHeight = foot.length * intRowHeight
    const intItemNo = 0

    const strPaddingLeft = i === 0 ? '5%' : '5%'

    // 1.头部打印
    let intPaddingTop = intPaddingHeight
    // 偏移测试
    // if(i!==0){
    //   intPaddingTop-=100*i;
    // }
    const strDivHead = calcHeadDom(head)

    // 上、左、宽、高、内容
    LODOP.ADD_PRINT_HTM(intPaddingTop, strPaddingLeft, '90%', intHeadHeight + intPaddingHeight, strDivHead)

    // “VOrient”:设定打印项在纸张内的垂直位置锁定方式。VOrient的值:数字型,0--上边距锁定 1--下边距锁定 2--垂直方向居中 3--上边距和下边距同时锁定(中间拉伸),缺省值是0。
    LODOP.SET_PRINT_STYLEA(0, 'Vorient', 3)

    // 固定标题,设置卫页眉页脚
    LODOP.SET_PRINT_STYLEA(0, 'ItemType', 0)

    // “LinkedItem”:设置关联内容项的项目编号
    LODOP.SET_PRINT_STYLEA(0, 'LinkedItem', intItemNo)

    // 2.身体数据打印
    intPaddingTop += (intHeadHeight + intPaddingHeight * 2)
    const strDivBody = calcBodyDom(body)
    // console.log('body:',strDivBody);
    // 上、左、宽、高、内容
    LODOP.ADD_PRINT_TABLE(intPaddingTop, strPaddingLeft, '90%', intBodyHeight + intPaddingHeight, strDivBody)

    // “VOrient”:设定打印项在纸张内的垂直位置锁定方式。VOrient的值:数字型,0--上边距锁定 1--下边距锁定 2--垂直方向居中 3--上边距和下边距同时锁定(中间拉伸),缺省值是0。
    LODOP.SET_PRINT_STYLEA(0, 'Vorient', 3)

    // 固定标题,普通内容
    LODOP.SET_PRINT_STYLEA(0, 'ItemType', 0)

    // “LinkedItem”:设置关联内容项的项目编号
    LODOP.SET_PRINT_STYLEA(0, 'LinkedItem', intItemNo)

    // 此页top偏移
    // LODOP.SET_PRINT_STYLEA(0,'Offset2Top',100);

    // 3.尾部数据打印
    intPaddingTop += (intBodyHeight + intPaddingHeight * 2)
    const strDivFoot = calcFootDom(foot)
    // 上、左、宽、高、内容
    LODOP.ADD_PRINT_HTM(intPaddingTop, strPaddingLeft, '90%', intFootHeight + intPaddingHeight, strDivFoot)

    // “VOrient”:设定打印项在纸张内的垂直位置锁定方式。VOrient的值:数字型,0--上边距锁定 1--下边距锁定 2--垂直方向居中 3--上边距和下边距同时锁定(中间拉伸),缺省值是0。
    LODOP.SET_PRINT_STYLEA(0, 'Vorient', 3)

    // 固定标题,设置卫页眉页脚
    LODOP.SET_PRINT_STYLEA(0, 'ItemType', 0)

    // “LinkedItem”:设置关联内容项的项目编号
    LODOP.SET_PRINT_STYLEA(0, 'LinkedItem', intItemNo)

    LODOP.NewPageA()
  }

  // 4.其他信息

  LODOP.SET_PRINT_MODE('CATCH_PRINT_STATUS', true)
  LODOP.SET_PRINT_MODE('AUTO_CLOSE_PREWINDOW', 1)// 打印后自动关闭预览窗口

  if (LODOP.CVERSION) {
    LODOP.On_Return = function (TaskID, Value) { // 2、插件自动识别是否需要返回值
      P_ID = Value
      console.log('第二步执行代码返回结果TaskID:' + TaskID + '  P_ID:' + P_ID)
      th.sureSubmit(P_ID)
    }
    P_ID = LODOP.PREVIEW()// 1、开始执行打印
    console.log('第一步执行代码返回结果:' + P_ID)
  } else { // 这块貌似报错才会执行
    P_ID = LODOP.PREVIEW()
    console.log('报错执行代码返回结果:' + P_ID)
  }
}

此处调用到了分页.对于自然情况下内容过多自动跑到了下一页的情况,会使用到SET_PRINT_STYLEA中的LinkedItem,实际使用中有一些小问题.但考虑到实际业务逻辑几乎不会出现这种情况,故暂且忽略,以后再研究.


5 其他

参考地址:

  1. 官方样例合集
  2. 民间api

end

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部